source: indico/indico/MaKaC/reviewing.py @ 8272ae

burotelhello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.98b1v0.98b2v0.99v1.0v1.1
Last change on this file since 8272ae was 8272ae, checked in by Jose Benito <jose.benito.gonzalez@…>, 2 years ago

[FTR] Several functionalities in abstract reviewin

  • Total value included in popup of question details
  • Added class Question and question identifiers
  • Added fossilize of the class Question
  • Added the functionality of editing and removing question objects
  • Implemented the services to get, add, remove or edit reviewing questions
  • Implemented new javascript widget to manage list of elements, in this case questions.
  • Implemented new popup to Save or Cancel the changes when you edit an element of the list
  • Added warning in 'change scale component'
  • Property mode set to 100644
File size: 57.4 KB
Line 
1# -*- coding: utf-8 -*-
2##
3##
4## This file is part of CDS Indico.
5## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6##
7## CDS Indico is free software; you can redistribute it and/or
8## modify it under the terms of the GNU General Public License as
9## published by the Free Software Foundation; either version 2 of the
10## License, or (at your option) any later version.
11##
12## CDS Indico is distributed in the hope that it will be useful, but
13## WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15## General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21from MaKaC.webinterface.mail import GenericNotification
22from MaKaC.common.info import HelperMaKaCInfo
23from MaKaC.webinterface import urlHandlers
24from MaKaC.common.mail import GenericMailer
25from MaKaC.common.timezoneUtils import getAdjustedDate, nowutc
26from datetime import datetime
27from persistent import Persistent
28from MaKaC.errors import MaKaCError
29import tempfile
30from MaKaC.common import Config
31import conference
32from MaKaC.common.Counter import Counter
33from MaKaC.fossils.reviewing import IReviewingQuestionFossil
34from MaKaC.common.fossilize import fossilizes, Fossilizable
35from persistent.list import PersistentList
36
37###############################################
38# Conference-wide classes
39###############################################
40
41
42class ConferencePaperReview(Persistent):
43    """
44    This class manages the parameters of the paper reviewing.
45    """
46    reviewingModes = ["", "No reviewing", "Content reviewing", "Layout reviewing", "Content and layout reviewing"]
47    predefinedStates = ["Accept", "To be corrected", "Reject"]
48    reviewingQuestionsAnswers = ["Strongly Disagree", "Disagree", "Weakly Disagree", "Borderline", "Weakly Agree", "Agree", "Strongly Agree"]
49    reviewingQuestionsLabels = ["-3", "", "", "0", "", "", "+3"]
50    initialSelectedAnswer = 3
51
52    def __init__( self, conference):
53        """ Constructor.
54            conference must be a Conference object (not an id).
55        """
56
57        self._conference = conference
58
59        #lists of users with reviewing roles
60        self._reviewersList = []
61        self._editorsList = []
62        self._refereesList = []
63        self._paperReviewManagersList = []
64
65        self._refereeContribution = {} #key: user, value: list of contributions where user is referee
66        self._editorContribution = {} #key: user, value: list of contributions where user is editor
67        self._reviewerContribution = {} #key: user, value: list of contributions where user is reviewer
68
69        self.setChoice(1) #initial reviewing mode: no reviewing
70
71        #default dates
72        self._startSubmissionDate = None
73        self._endSubmissionDate = None
74        self._defaultRefereeDueDate = None
75        self._defaultEditorDueDate = None
76        self._defaultReviwerDueDate = None
77
78        #auto e-mails
79        self._enablePRMEmailNotif = True
80        self._enableRefereeEmailNotif = False
81        self._enableEditorEmailNotif = False
82        self._enableReviewerEmailNotif = False
83        self._enableRefereeEmailNotifForContribution = False
84        self._enableEditorEmailNotifForContribution = False
85        self._enableReviewerEmailNotifForContribution = False
86        self._enableRefereeJudgementEmailNotif = False
87        self._enableEditorJudgementEmailNotif = False
88        self._enableReviewerJudgementEmailNotif = False
89        self._enableAuthorSubmittedMatRefereeEmailNotif = False
90        self._enableAuthorSubmittedMatEditorEmailNotif = False
91        self._enableAuthorSubmittedMatReviewerEmailNotif = False
92
93        from MaKaC.webinterface.materialFactories import MaterialFactoryRegistry
94        #from MaKaC.webinterface.rh.conferenceBase import RHSubmitMaterialBase
95        self._nonReviewableMaterials = []#this is not used any more, since we have new material type used only for reviewing
96
97
98        self._states = [] # list of content reviewing and final judgement non-default states
99        self._reviewingQuestions = [] #list of content reviewing and final judgement questions
100        self._formCriteriaList = [] #list of layout editing criteria
101        self._templates = {} #dictionary with layout templates. key: id, value: Template object
102        self._templateCounter = Counter(1) #counter to make new id's for the templates
103        self._userCompetences = {} #dictionary with the competences of each user. key: user, value: list of competences
104        self._userCompetencesByTag = {} #dictionary with the users for each competence. key: competence, value: list of users
105        self._reviewingMaterials = {}
106        self.notifyModification()
107
108
109    def getConference(self):
110        """ Returns the parent conference of the ConferencePaperReview object
111        """
112        return self._conference
113
114    def setStartSubmissionDate(self, startSubmissionDate):
115        self._startSubmissionDate= datetime(startSubmissionDate.year,startSubmissionDate.month,startSubmissionDate.day,23,59,59)
116
117    def getStartSubmissionDate(self):
118        return self._startSubmissionDate
119
120    def setEndSubmissionDate(self, endSubmissionDate):
121        self._endSubmissionDate = datetime(endSubmissionDate.year,endSubmissionDate.month,endSubmissionDate.day,23,59,59)
122
123    def getEndSubmissionDate(self):
124        return self._endSubmissionDate
125
126    def setDefaultRefereeDueDate(self, date):
127        self._defaultRefereeDueDate = date
128
129    def getDefaultRefereeDueDate(self):
130        return self._defaultRefereeDueDate
131
132    def getAdjustedDefaultRefereeDueDate(self):
133        if self.getDefaultRefereeDueDate() is None:
134            return None
135        else:
136            return getAdjustedDate(self._defaultRefereeDueDate, self.getConference())
137
138    def setDefaultEditorDueDate(self, date):
139        self._defaultEditorDueDate = date
140
141    def getDefaultEditorDueDate(self):
142        return self._defaultEditorDueDate
143
144    def getAdjustedDefaultEditorDueDate(self):
145        if self.getDefaultEditorDueDate() is None:
146            return None
147        else:
148            return getAdjustedDate(self._defaultEditorDueDate, self.getConference())
149
150    def setDefaultReviewerDueDate(self, date):
151        self._defaultReviwerDueDate = date
152
153    def getDefaultReviewerDueDate(self):
154        return self._defaultReviwerDueDate
155
156    def getAdjustedDefaultReviewerDueDate(self):
157        if self.getDefaultReviewerDueDate() is None:
158            return None
159        else:
160            return getAdjustedDate(self._defaultReviwerDueDate, self.getConference())
161
162    #auto e-mails methods for assign/remove reviewing team to the conference notification
163    def getEnablePRMEmailNotif(self):
164        try :
165            if self._enablePRMEmailNotif  :
166                pass
167        except AttributeError :
168            self._enablePRMEmailNotif = True
169        return self._enablePRMEmailNotif
170
171    def enablePRMEmailNotif(self):
172        self._enablePRMEmailNotif = True
173
174    def disablePRMEmailNotif(self):
175        self._enablePRMEmailNotif = False
176
177    def getEnableRefereeEmailNotif(self):
178        try :
179            if self._enableRefereeEmailNotif  :
180                pass
181        except AttributeError :
182            self._enableRefereeEmailNotif = True
183        return self._enableRefereeEmailNotif
184
185    def enableRefereeEmailNotif(self):
186        self._enableRefereeEmailNotif = True
187
188    def disableRefereeEmailNotif(self):
189        self._enableRefereeEmailNotif = False
190
191
192    def getEnableEditorEmailNotif(self):
193        try :
194            if self._enableEditorEmailNotif  :
195                pass
196        except AttributeError :
197            self._enableEditorEmailNotif = True
198        return self._enableEditorEmailNotif
199
200    def enableEditorEmailNotif(self):
201        self._enableEditorEmailNotif = True
202
203    def disableEditorEmailNotif(self):
204        self._enableEditorEmailNotif = False
205
206
207    def getEnableReviewerEmailNotif(self):
208        try :
209            if self._enableReviewerEmailNotif  :
210                pass
211        except AttributeError :
212            self._enableReviewerEmailNotif = True
213        return self._enableReviewerEmailNotif
214
215    def enableReviewerEmailNotif(self):
216        self._enableReviewerEmailNotif = True
217
218    def disableReviewerEmailNotif(self):
219        self._enableReviewerEmailNotif = False
220
221
222    #auto e-mails methods for assign/remove reviewers to/from contributions notification
223    def getEnableRefereeEmailNotifForContribution(self):
224        try :
225            if self._enableRefereeEmailNotifForContribution  :
226                pass
227        except AttributeError :
228            self._enableRefereeEmailNotifForContribution = True
229        return self._enableRefereeEmailNotifForContribution
230
231    def enableRefereeEmailNotifForContribution(self):
232        self._enableRefereeEmailNotifForContribution = True
233
234    def disableRefereeEmailNotifForContribution(self):
235        self._enableRefereeEmailNotifForContribution = False
236
237    def getEnableEditorEmailNotifForContribution(self):
238        try :
239            if self._enableEditorEmailNotifForContribution  :
240                pass
241        except AttributeError :
242            self._enableEditorEmailNotifForContribution = True
243        return self._enableEditorEmailNotifForContribution
244
245    def enableEditorEmailNotifForContribution(self):
246        self._enableEditorEmailNotifForContribution = True
247
248    def disableEditorEmailNotifForContribution(self):
249        self._enableEditorEmailNotifForContribution = False
250
251    def getEnableReviewerEmailNotifForContribution(self):
252        try :
253            if self._enableReviewerEmailNotifForContribution  :
254                pass
255        except AttributeError :
256            self._enableReviewerEmailNotifForContribution = True
257        return self._enableReviewerEmailNotifForContribution
258
259    def enableReviewerEmailNotifForContribution(self):
260        self._enableReviewerEmailNotifForContribution = True
261
262    def disableReviewerEmailNotifForContribution(self):
263        self._enableReviewerEmailNotifForContribution = False
264
265    #auto e-mails methods for reviewers judgements notification
266    def getEnableRefereeJudgementEmailNotif(self):
267        try :
268            if self._enableRefereeJudgementEmailNotif  :
269                pass
270        except AttributeError :
271            self._enableRefereeJudgementEmailNotif = True
272        return self._enableRefereeJudgementEmailNotif
273
274    def enableRefereeJudgementEmailNotif(self):
275        self._enableRefereeJudgementEmailNotif = True
276
277    def disableRefereeJudgementEmailNotif(self):
278        self._enableRefereeJudgementEmailNotif = False
279
280    def getEnableEditorJudgementEmailNotif(self):
281        try :
282            if self._enableEditorJudgementEmailNotif  :
283                pass
284        except AttributeError :
285            self._enableEditorJudgementEmailNotif = True
286        return self._enableEditorJudgementEmailNotif
287
288    def enableEditorJudgementEmailNotif(self):
289        self._enableEditorJudgementEmailNotif = True
290
291    def disableEditorJudgementEmailNotif(self):
292        self._enableEditorJudgementEmailNotif = False
293
294    def getEnableReviewerJudgementEmailNotif(self):
295        try :
296            if self._enableReviewerJudgementEmailNotif  :
297                pass
298        except AttributeError :
299            self._enableReviewerJudgementEmailNotif = True
300        return self._enableReviewerJudgementEmailNotif
301
302    def enableReviewerJudgementEmailNotif(self):
303        self._enableReviewerJudgementEmailNotif = True
304
305    def disableReviewerJudgementEmailNotif(self):
306        self._enableReviewerJudgementEmailNotif = False
307
308    #auto e-mails methods for authors' submittion materials notification
309    def getEnableAuthorSubmittedMatRefereeEmailNotif(self):
310        try :
311            if self._enableAuthorSubmittedMatRefereeEmailNotif  :
312                pass
313        except AttributeError :
314            self._enableAuthorSubmittedMatRefereeEmailNotif = True
315        return self._enableAuthorSubmittedMatRefereeEmailNotif
316
317    def enableAuthorSubmittedMatRefereeEmailNotif(self):
318        self._enableAuthorSubmittedMatRefereeEmailNotif = True
319
320    def disableAuthorSubmittedMatRefereeEmailNotif(self):
321        self._enableAuthorSubmittedMatRefereeEmailNotif = False
322
323    def getEnableAuthorSubmittedMatEditorEmailNotif(self):
324        try :
325            if self._enableAuthorSubmittedMatEditorEmailNotif  :
326                pass
327        except AttributeError :
328            self._enableAuthorSubmittedMatEditorEmailNotif = True
329        return self._enableAuthorSubmittedMatEditorEmailNotif
330
331    def enableAuthorSubmittedMatEditorEmailNotif(self):
332        self._enableAuthorSubmittedMatEditorEmailNotif = True
333
334    def disableAuthorSubmittedMatEditorEmailNotif(self):
335        self._enableAuthorSubmittedMatEditorEmailNotif = False
336
337    def getEnableAuthorSubmittedMatReviewerEmailNotif(self):
338        try :
339            if self._enableAuthorSubmittedMatReviewerEmailNotif  :
340                pass
341        except AttributeError :
342            self._enableAuthorSubmittedMatReviewerEmailNotif = True
343        return self._enableAuthorSubmittedMatReviewerEmailNotif
344
345    def enableAuthorSubmittedMatReviewerEmailNotif(self):
346        self._enableAuthorSubmittedMatReviewerEmailNotif = True
347
348    def disableAuthorSubmittedMatReviewerEmailNotif(self):
349        self._enableAuthorSubmittedMatReviewerEmailNotif = False
350
351
352    #Reviewing mode methods
353    def setChoice(self, choice):
354        """ Sets the reviewing mode for the conference, as a number and as a string
355            1: "No reviewing"
356            2: "Content reviewing"
357            3: "Layout reviewing"
358            4: "Content and layout reviewing"
359        """
360        self._choice = choice
361        self._reviewing = ConferencePaperReview.reviewingModes[choice]
362
363    def getChoice(self):
364        """ Returns the reviewing mode for the conference, as a number
365            1: "No reviewing"
366            2: "Content reviewing"
367            3: "Layout reviewing"
368            4: "Content and layout reviewing"
369        """
370        return self._choice
371
372    def getReviewingMode(self):
373        """ Returns the reviewing mode for the conference, as a string
374        """
375        return self._reviewing
376
377    def setReviewingMode(self, mode):
378        """ Sets the reviewing mode of the conference, as a string.
379            The string has to be one of those in ConferencePaperReview.reviewingModes
380        """
381        if mode in ConferencePaperReview.reviewingModes:
382            self._reviewing = mode
383            self._choice = ConferencePaperReview.reviewingModes.index(mode)
384
385    def hasReviewing(self):
386        """ Convenience method that returns if the Conference has a reviewing mode active or not.
387        """
388        return self._choice > 1
389
390    def hasPaperReviewing(self):
391        """ Convenience method that returns if the Conference has a reviewing mode that allows paper reviewing.
392            (modes 2 and 4)
393        """
394        return self._choice == 2 or self._choice == 4
395
396    def hasPaperEditing(self):
397        """ Convenience method that returns if the Conference has a reviewing mode that allows paper editing.
398            (modes 3 and 4)
399        """
400        return self._choice == 3 or self._choice == 4
401
402    #Content reviewing and final judgement new states methods
403    def addState(self, state):
404        """ Adds a state to the list of non-default states
405        """
406        self._states.append(state)
407        self.notifyModification()
408
409    def getStates(self):
410        """ Returns list of non-default states
411        """
412        return self._states
413
414    def setStates(self, states):
415        self._states = states
416
417    def getAllStates(self):
418        """ Returns list of default and non-default states
419        """
420        return ConferencePaperReview.predefinedStates + self._states
421
422    def removeState(self, state):
423        """ Remoevs a state
424        """
425        if state in self._states:
426            self._states.remove(state)
427            self.notifyModification()
428        else:
429            raise MaKaCError("Cannot remove a state which doesn't exist")
430
431
432
433    def inModificationPeriod(self):
434        date = nowutc()
435        if date <= self._endCorrectionDate:
436            return True
437        else:
438            return False
439
440    def inSubmissionPeriod(self):
441        date = nowutc()
442        if date <= self._endSubmissionDate & date >= self._startSubmissionDate:
443            return True
444        else:
445            return False
446
447    def inEditingPeriod(self):
448        date = nowutc()
449        if date <= self._endEditingDate:
450            return True
451        else:
452            return False
453
454    def inReviewingPeriod(self):
455        date = nowutc()
456        if date <= self._endReviewingDate & date >= self._endCorrectionDate:
457            return True
458        else:
459            return False
460
461    # content reviewing and final judgement questions methods
462    def addReviewingQuestion(self, reviewingQuestion):
463        """ Adds this question at the end of the list of questions
464        """
465        self._reviewingQuestions.append(reviewingQuestion)
466        self.notifyModification()
467
468    def getReviewingQuestions(self):
469        """ Returns the list of questions
470        """
471        return self._reviewingQuestions
472
473    def setReviewingQuestions(self, questions):
474        """ Set the whole list of questions
475        """
476        self._reviewingQuestions = questions
477
478    def removeReviewingQuestion(self, reviewingQuestion):
479        """ Removes a question from the list
480        """
481        if reviewingQuestion in self._reviewingQuestions:
482            self._reviewingQuestions.remove(reviewingQuestion)
483            self.notifyModification()
484        else:
485            raise MaKaCError("Cannot remove a question which doesn't exist")
486
487    # layout editing criteria methods
488    def addLayoutCriteria(self, formCriteria):
489        """ Add a new layout editing criterion
490        """
491        self._formCriteriaList.append(formCriteria)
492        self.notifyModification()
493
494    def getLayoutCriteria(self):
495        """ Get the list of all the layout criteria
496        """
497        return self._formCriteriaList
498
499    def setLayoutCriteria(self, criteria):
500        """ Set the whole list of all the layout criteria
501        """
502        self._formCriteriaList = criteria
503
504    def removeLayoutCriteria(self, criteria):
505        """ Remove one the layout criteria
506        """
507        if criteria in self._formCriteriaList:
508            self._formCriteriaList.remove(criteria)
509            self.notifyModification()
510        else:
511            raise MaKaCError("Cannot remove a criteria which doesn't exist")
512
513
514    #referee methods
515    def addReferee(self, newReferee):
516        """ Adds a new referee to the conference.
517            newReferee has to be an Avatar object.
518            The referee is sent a mail notification only if the manager has enabled the option in 'Automatic e-mails' section.
519        """
520        if newReferee in self.getRefereesList():
521            raise MaKaCError("This referee has already been added to this conference")
522        else:
523            self._refereesList.append(newReferee)
524            newReferee.linkTo(self._conference, "referee")
525            if not self._userCompetences.has_key(newReferee):
526                self._userCompetences[newReferee] = []
527            self.notifyModification()
528            if self._enableRefereeEmailNotif == True:
529                notification = ConferenceReviewingNotification(newReferee, 'Referee', self._conference)
530                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", newReferee)
531
532
533    def removeReferee(self, referee):
534        """ Remove a referee from the conference.
535            referee has to be an Avatar object.
536            The referee is sent a mail notification only if the manager has enabled the option in 'Automatic e-mails' section.
537        """
538        if referee in self._refereesList:
539            if self._userCompetences.has_key(referee):
540                if not ((referee in self._editorsList) or \
541                        (referee in self._paperReviewManagersList) or \
542                        (referee in self._reviewersList)):
543                    self.clearUserCompetences(referee)
544                    del(self._userCompetences[referee])
545            self._refereesList.remove(referee)
546            referee.unlinkTo(self._conference, "referee")
547            self.notifyModification()
548            if self._enableRefereeEmailNotif == True:
549                notification = ConferenceReviewingRemoveNotification(referee, 'Referee', self._conference)
550                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", referee)
551        else:
552            raise MaKaCError("Cannot remove a referee who is not yet referee")
553
554    def isReferee(self, user):
555        """ Returns if a given user is referee of the conference.
556            user has to be an Avatar object.
557        """
558        return user in self._refereesList
559
560    def getRefereesList(self):
561        """ Returns the list of referees as a list of Avatar objects.
562        """
563        return self._refereesList
564
565    def addRefereeContribution(self, referee, contribution):
566        """ Adds the contribution to the list of contributions for a given referee.
567            referee has to be an Avatar object.
568        """
569        if self._refereeContribution.has_key(referee):
570            self._refereeContribution[referee].append(contribution)
571            self._refereeContribution[referee].sort(key= lambda c: int(c.getId()))
572        else:
573            self._refereeContribution[referee] = [contribution]
574        self.notifyModification()
575
576    def removeRefereeContribution(self, referee, contribution):
577        """ Removes the contribution from the list of contributions of this referee
578            referee has to be an Avatar object.
579        """
580        if self._refereeContribution.has_key(referee):
581            self._refereeContribution[referee].remove(contribution)
582        self.notifyModification()
583
584    def isRefereeContribution(self, referee, contribution):
585        """ Returns if a user is referee for a given contribution
586            referee has to be an Avatar object.
587        """
588        return self._refereeContribution.has_key(referee) and contribution in self._refereeContribution[referee]
589
590    def getJudgedContributions(self, referee):
591        """ Returns the list of contributions for a given referee
592            referee has to be an Avatar object.
593        """
594        if self._refereeContribution.has_key(referee):
595            return self._refereeContribution[referee]
596        else:
597            return []
598
599    #editor methods
600    def addEditor(self, newEditor):
601        """ Adds a new editor to the conference.
602            editor has to be an Avatar object.
603            The editor is sent a mail notification only if the manager has enabled the option in 'Automatic e-mails' section.
604        """
605        if newEditor in self.getEditorsList():
606            raise MaKaCError("This editor has already been added to this conference")
607        else:
608            self._editorsList.append(newEditor)
609            newEditor.linkTo(self._conference, "editor")
610            if not self._userCompetences.has_key(newEditor):
611                self._userCompetences[newEditor] = []
612            self.notifyModification()
613            if self._enableEditorEmailNotif == True:
614                notification = ConferenceReviewingNotification(newEditor, 'Layout Reviewer', self._conference)
615                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", newEditor)
616
617    def removeEditor(self, editor):
618        """ Remove a editor from the conference.
619            editor has to be an Avatar object.
620            The editor is sent a mail notification only if the manager has enabled the option in 'Automatic e-mails' section.
621        """
622        if editor in self._editorsList:
623            if self._userCompetences.has_key(editor):
624                if not ((editor in self._paperReviewManagersList) or \
625                        (editor in self._reviewersList) or \
626                        (editor in self._refereesList)):
627                    self.clearUserCompetences(editor)
628                    del(self._userCompetences[editor])
629            self._editorsList.remove(editor)
630            editor.unlinkTo(self._conference, "editor")
631            self.notifyModification()
632            if self._enableEditorEmailNotif == True:
633                notification = ConferenceReviewingRemoveNotification(editor, 'Layout Reviewer', self._conference)
634                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", editor)
635        else:
636            raise MaKaCError("Cannot remove an editor who is not yet editor")
637
638    def isEditor(self, user):
639        """ Returns if a given user is editor of the conference.
640            user has to be an Avatar object.
641        """
642        return user in self._editorsList
643
644    def getEditorsList(self):
645        """ Returns the list of editors as a list of users.
646        """
647        return self._editorsList
648
649    def addEditorContribution(self, editor, contribution):
650        """ Adds the contribution to the list of contributions for a given editor.
651            editor has to be an Avatar object.
652        """
653        if self._editorContribution.has_key(editor):
654            self._editorContribution[editor].append(contribution)
655            self._editorContribution[editor].sort(key= lambda c: int(c.getId()))
656        else:
657            self._editorContribution[editor] = [contribution]
658        self.notifyModification()
659
660    def removeEditorContribution(self, editor, contribution):
661        """ Removes the contribution from the list of contributions of this editor
662            editor has to be an Avatar object.
663        """
664        if self._editorContribution.has_key(editor):
665            self._editorContribution[editor].remove(contribution)
666        self.notifyModification()
667
668    def isEditorContribution(self, editor, contribution):
669        """ Returns if a user is editor for a given contribution
670            editor has to be an Avatar object.
671        """
672        return self._editorContribution.has_key(editor) and contribution in self._editorContribution[editor]
673
674    def getEditedContributions(self, editor):
675        """ Returns the list of contributions for a given editor
676            editor has to be an Avatar object.
677        """
678        if self._editorContribution.has_key(editor):
679            return self._editorContribution[editor]
680        else:
681            return []
682
683    #reviewer methods
684    def addReviewer(self, newReviewer):
685        """ Adds a new reviewer to the conference.
686            newreviewer has to be an Avatar object.
687            The reviewer is sent a mail notification only if the manager has enabled the option in 'Automatic e-mails' section.
688        """
689        if newReviewer in self.getReviewersList():
690            raise MaKaCError("This reviewer has already been added to this conference")
691        else:
692            self._reviewersList.append(newReviewer)
693            newReviewer.linkTo(self._conference, "reviewer")
694            if not self._userCompetences.has_key(newReviewer):
695                self._userCompetences[newReviewer] = []
696            self.notifyModification()
697            if self._enableReviewerEmailNotif == True:
698                notification = ConferenceReviewingNotification(newReviewer, 'Content Reviewer', self._conference)
699                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", newReviewer)
700
701    def removeReviewer(self, reviewer):
702        """ Remove a reviewer from the conference.
703            reviewer has to be an Avatar object.
704            The reviewer is sent a mail notification only if the manager has enabled the option in 'Automatic e-mails' section.
705        """
706        if reviewer in self._reviewersList:
707            if self._userCompetences.has_key(reviewer):
708                if not ((reviewer in self._editorsList) or \
709                        (reviewer in self._paperReviewManagersList) or \
710                        (reviewer in self._refereesList)):
711                    self.clearUserCompetences(reviewer)
712                    del(self._userCompetences[reviewer])
713            self._reviewersList.remove(reviewer)
714            reviewer.unlinkTo(self._conference, "reviewer")
715            self.notifyModification()
716            if self._enableReviewerEmailNotif == True:
717                notification = ConferenceReviewingRemoveNotification(reviewer, 'Content Reviewer', self._conference)
718                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", reviewer)
719        else:
720            raise MaKaCError("Cannot remove a reviewer who is not yet reviewer")
721
722    def isReviewer(self, user):
723        """ Returns if a given user is reviewer of the conference.
724            user has to be an Avatar object.
725        """
726        return user in self._reviewersList
727
728    def getReviewersList(self):
729        """ Returns the list of reviewers as a list of users.
730        """
731        return self._reviewersList
732
733    def addReviewerContribution(self, reviewer, contribution):
734        """ Adds the contribution to the list of contributions for a given reviewer.
735            reviewer has to be an Avatar object.
736        """
737        if self._reviewerContribution.has_key(reviewer):
738            self._reviewerContribution[reviewer].append(contribution)
739            self._reviewerContribution[reviewer].sort(key= lambda c: int(c.getId()))
740        else:
741            self._reviewerContribution[reviewer] = [contribution]
742        self.notifyModification()
743
744    def removeReviewerContribution(self, reviewer, contribution):
745        """ Removes the contribution from the list of contributions of this reviewer
746            reviewer has to be an Avatar object.
747        """
748        if self._reviewerContribution.has_key(reviewer):
749            self._reviewerContribution[reviewer].remove(contribution)
750        self.notifyModification()
751
752    def isReviewerContribution(self, reviewer, contribution):
753        """ Returns if a user is reviewer for a given contribution
754            reviewer has to be an Avatar object.
755        """
756        return self._reviewerContribution.has_key(reviewer) and contribution in self._reviewerContribution[reviewer]
757
758    def getReviewedContributions(self, reviewer):
759        """ Returns the list of contributions for a given reviewer
760            reviewer has to be an Avatar object.
761        """
762        if self._reviewerContribution.has_key(reviewer):
763            return self._reviewerContribution[reviewer]
764        else:
765            return []
766
767    #paper review manager methods
768    def addPaperReviewManager(self, newPaperReviewManager):
769        """ Adds a new paper review manager to the conference.
770            newPaperReviewManager has to be an Avatar object.
771            The paper review manager is sent a mail notification.
772        """
773        if newPaperReviewManager in self.getPaperReviewManagersList():
774            raise MaKaCError("This paper review manager has already been added to this conference")
775        else:
776            self._paperReviewManagersList.append(newPaperReviewManager)
777            newPaperReviewManager.linkTo(self._conference, "paperReviewManager")
778            if not self._userCompetences.has_key(newPaperReviewManager):
779                self._userCompetences[newPaperReviewManager] = []
780            self.notifyModification()
781        if self._enablePRMEmailNotif == True:
782            notification = ConferenceReviewingNotification(newPaperReviewManager, 'Paper Review Manager', self._conference)
783            GenericMailer.sendAndLog(notification, self._conference, "Reviewing", newPaperReviewManager)
784
785    def removePaperReviewManager(self, paperReviewManager):
786        """ Remove a paper review manager from the conference.
787            paperReviewManager has to be an Avatar object.
788            The paper review manager is sent a mail notification.
789        """
790        if paperReviewManager in self._paperReviewManagersList:
791            if self._userCompetences.has_key(paperReviewManager):
792                if not ((paperReviewManager in self._editorsList) or \
793                        (paperReviewManager in self._reviewersList) or \
794                        (paperReviewManager in self._refereesList)):
795                    self.clearUserCompetences(paperReviewManager)
796                    del(self._userCompetences[paperReviewManager])
797            self._paperReviewManagersList.remove(paperReviewManager)
798            paperReviewManager.unlinkTo(self._conference, "paperReviewManager")
799            self.notifyModification()
800            if self._enablePRMEmailNotif == True:
801                notification = ConferenceReviewingRemoveNotification(paperReviewManager, 'Paper Review Manager', self._conference)
802                GenericMailer.sendAndLog(notification, self._conference, "Reviewing", paperReviewManager)
803        else:
804            raise MaKaCError("Cannot remove a paper review manager who is not yet paper review manager")
805
806    def isPaperReviewManager(self, user):
807        """ Returns if a given user is paper review manager of the conference.
808            user has to be an Avatar object.
809        """
810        return user in self._paperReviewManagersList
811
812    def getPaperReviewManagersList(self):
813        """ Returns the list of paper review managers as a list of users.
814        """
815        return self._paperReviewManagersList
816
817    # templates methods
818    def setTemplate(self, name, description, format, fd, id):
819        """ Stores a template.
820            There can be 1 template for any format.
821        """
822
823        cfg = Config.getInstance()
824        tempPath = cfg.getUploadedFilesTempDir()
825        tempFileName = tempfile.mkstemp( suffix="MaKaC.tmp", dir = tempPath )[1]
826        f = open( tempFileName, "wb" )
827        f.write( fd.read() )
828        f.close()
829
830        if format in Template.formats:
831            extension = Template.formats[format]
832        else:
833            extension = ".template"
834
835        #id = self.getNewTemplateId()
836
837        fileName = "Contribution_template_" + id + "_c" + self._conference.id + extension
838
839        file = conference.LocalFile()
840        file.setName( fileName )
841        file.setDescription( "Paper reviewing template with id " + id + "with format: " + format + " of the conference " + self._conference.id )
842        file.setFileName( fileName )
843
844        file.setFilePath( tempFileName )
845        file.setOwner( self._conference )
846        file.setId( fileName )
847        file.archive( self._conference._getRepository() )
848
849        self._templates[id] = Template(id, self._conference, name, description, format, file)
850        self.notifyModification()
851
852    def hasTemplates(self):
853        """ Returns if the conference has any reviewing templates
854        """
855        return len(self._templates) > 0
856
857    def getTemplates(self):
858        """ Returns a dictionary of templates. key: id, value: Template object
859        """
860        return self._templates
861
862    def getNewTemplateId(self):
863        """ Returns a new an unused templateId
864            Increments the templateId counter
865        """
866        return self._templateCounter.newCount()
867
868    def deleteTemplate(self, id):
869        """ Removes a reviewing template from the conference, given the id.
870        """
871        del self._templates[id]
872        self.notifyModification()
873
874
875    #competences methods
876    def isInReviewingTeam(self, user):
877        return user in self._paperReviewManagersList or \
878               user in self._refereesList or \
879               user in self._editorsList or \
880               user in self._reviewersList or \
881               user in self._reviewersList
882
883    def setUserCompetences(self, user, competences):
884        """ Sets a list of competences (a list of strings) to a given user
885        """
886        if self.isInReviewingTeam(user):
887            self.clearUserCompetences(user)
888            self.addUserCompetences(user, competences)
889        else:
890            raise MaKaCError("""User %s is not in the reviewing team for this conference, so you cannot set competences for him/her"""%user.getFullName())
891
892    def clearUserCompetences(self, user):
893        if self.isInReviewingTeam(user):
894            for c in self.getCompetencesByUser(user):
895                self._userCompetencesByTag[c].remove(user)
896                if len(self._userCompetencesByTag[c]) == 0:
897                        del self._userCompetencesByTag[c]
898            self._userCompetences[user] = []
899        else:
900            raise MaKaCError("""User %s is not in the reviewing team for this conference, so you cannot clear competences for him/her"""%user.getFullName())
901
902    def addUserCompetences(self, user, competences):
903        """ Adds a list of competences (a list of strings) to a given user
904        """
905        if self.isInReviewingTeam(user):
906            self._userCompetences[user].extend(competences)
907            for c in competences:
908                if self._userCompetencesByTag.has_key(c):
909                    self._userCompetencesByTag[c].append(user)
910                else:
911                    self._userCompetencesByTag[c] = [user]
912            self.notifyModification()
913        else:
914            raise MaKaCError("""User %s is not in the reviewing team for this conference, so you cannot add competences for him/her"""%user.getFullName())
915
916    def removeUserCompetences(self, user, competences):
917        """ Removes a list of competences (a list of strings) from a given user
918        """
919        if self.isInReviewingTeam(user):
920            if self._userCompetences.has_key(user):
921                for c in competences:
922                    self._userCompetences[user].remove(c)
923                    self._userCompetencesByTag[c].remove(user)
924                    if len(self._userCompetencesByTag[c]) == 0:
925                        del self._userCompetencesByTag[c]
926                self.notifyModification()
927            else:
928                raise MaKaCError("""User %s does not have competences"""%(user.getFullName))
929        else:
930            raise MaKaCError("""User %s is not in the reviewing team for this conference, so you cannot remove competences from him/her"""%user.getFullName())
931
932    def getAllUserCompetences(self, onlyActive = False, role = 'all'):
933        """ Returns a list with the users and their competences.
934            role can be 'referee', 'editor', 'reviewer' or 'all' (a different value or none specified defaults to 'all')
935            The list is composed of tuples of 2 elements: (user, competenceList) where competenceList is a list of strings.
936            The list is ordered by the full name of the users.
937        """
938
939        if onlyActive:
940            if role == 'referee':
941                users = self._refereesList
942            elif role == 'editor':
943                users = self._editorsList
944            elif role == 'reviewer':
945                users = self._reviewersList
946            else:
947                users = self._paperReviewManagersList + self._refereesList + self._editorsList + self._reviewersList
948        else:
949            if role == 'referee':
950                users = [u for u in self._userCompetences.keys() if u in self._refereesList]
951            elif role == 'editor':
952                users = [u for u in self._userCompetences.keys() if u in self._editorsList]
953            elif role == 'reviewer':
954                users = [u for u in self._userCompetences.keys() if u in self._reviewersList]
955            else:
956                users = self._userCompetences.keys()
957
958        users.sort(key = lambda u: u.getFullName())
959        return zip(users, [self._userCompetences[user] for user in users])
960
961    def getCompetencesByUser(self, user):
962        """ Returns the list of competences (a list of strings) for a given user.
963        """
964        return self._userCompetences[user]
965
966    def getUserReviewingRoles(self, user):
967        """ Returns the list of roles (PRM, referee, editor, reviewer) that a given user has
968            in this conference, as a list of strings.
969        """
970        roles=[]
971        if self.isPaperReviewManager(user) and not self._choice == 1:
972            roles.append('Manager of Paper Reviewing Module')
973        if self.isReferee(user) and (self._choice == 2 or self._choice == 4):
974            roles.append('Referee')
975        if self.isEditor(user) and (self._choice == 3 or self._choice == 4):
976            roles.append('Layout Reviewer')
977        if self.isReviewer(user) and (self._choice == 2 or self._choice == 4):
978            roles.append('Content Reviewer')
979        return roles
980
981    def notifyModification(self):
982        """ Notifies the DB that a list or dictionary attribute of this object has changed
983        """
984        self._p_changed = 1
985
986
987
988class Template(Persistent):
989    """ This class represents a template for contribution reviewing.
990        A template is a file uploaded by a Conference Manager or a Paper Review Manager.
991        Normal users can download it to have an idea of the format their contribution should have.
992        A conference can have many of these templates.
993    """
994
995    formats = {"Word":".doc",
996               "OpenOffice Writer":".odt",
997               "PowerPoint":".ppt",
998               "OpenOffice Impress":".odp",
999               "LaTeX":".tex"}
1000    """ This dictionary contains the different formats proposed to the uploaders.
1001        Also, if a template is uploaded with one of these formats, the file will have
1002        an appropriate extension.
1003    """
1004
1005    def __init__(self, id, conference, name, description, format, file):
1006        self.__id = id
1007        self.__conf = conference
1008        self.__name = name
1009        self.__description = description
1010        self.__format = format
1011        self.__file = file
1012
1013    def getId(self):
1014        return self.__id
1015
1016    def getName(self):
1017        return self.__name
1018
1019    def getDescription(self):
1020        return self.__description
1021
1022    def getFormat(self):
1023        return self.__format
1024
1025    def getFile(self):
1026        return self.__file
1027
1028
1029    def getLocator( self ):
1030        """Gives back (Locator) a globaly unique identification encapsulated
1031                in a Locator object for the category instance
1032        """
1033        loc = self.__conf.getLocator()
1034        loc["reviewingTemplateId"] = self.getId()
1035        return loc
1036
1037
1038class ConferenceReviewingNotification(GenericNotification):
1039    """ Template to build an email notification to a newly appointed PRM / Referee / Editor / Reviewer / Abstract Manager / Abstract Reviewer
1040    """
1041
1042    def __init__(self, user, role, conference):
1043        GenericNotification.__init__(self)
1044        self.setFromAddr("Indico Mailer<%s>"%HelperMaKaCInfo.getMaKaCInfoInstance().getSupportEmail())
1045        self.setToList([user.getEmail()])
1046        self.setSubject("""[Indico] You have been chosen as %s for the conference "%s" (id: %s)"""
1047                        % (role, conference.getTitle(), str(conference.getId())))
1048        self.setBody("""Dear Sir or Madam,
1049
1050        You have been chosen as %s of the conference "%s" (id: %s), in order to help with the abstract / contribution reviewing process.
1051        You can go to the conference main page:
1052        %s
1053        After logging in, you will find a link under 'My Conference' on which you can click to perform your new functions.
1054
1055        Best regards
1056        """ % ( role, conference.getTitle(), str(conference.getId()), urlHandlers.UHConferenceDisplay.getURL(conference)
1057        ))
1058
1059class ConferenceReviewingRemoveNotification(GenericNotification):
1060    """ Template to build an email notification to a removed PRM / Referee / Editor / Reviewer / Abstract Manager / Abstract Reviewer
1061    """
1062
1063    def __init__(self, user, role, conference):
1064        GenericNotification.__init__(self)
1065        self.setFromAddr("Indico Mailer<%s>"%HelperMaKaCInfo.getMaKaCInfoInstance().getSupportEmail())
1066        self.setToList([user.getEmail()])
1067        self.setSubject("""[Indico] You have been removed as %s of the conference "%s" (id: %s)"""
1068                        % (role, conference.getTitle(), str(conference.getId())))
1069        self.setBody("""Dear Indico user,
1070
1071        We are sorry to inform you that you have been removed as %s of the conference "%s" (id: %s).
1072
1073        Thank you for using our system.
1074        """ % ( role, conference.getTitle(), str(conference.getId())
1075        ))
1076
1077
1078class ConferenceAbstractReview(Persistent):
1079    """
1080    This class manages the parameters of the abstract reviewing.
1081    """
1082
1083    def __init__( self, conference):
1084        """ Constructor.
1085            conference must be a Conference object (not an id).
1086        """
1087
1088        self._conference = conference
1089
1090        #lists of users with reviewing roles
1091        self._abstractManagerList = []
1092        self._abstractReviewersList = []
1093
1094        self._reviewerAbstract = {} #key: user, value: list of abstracts where user is abstract reviewer
1095
1096        #default dates NOT USED YET
1097        self._defaultAbstractReviewerDueDate = None
1098
1099        self._reviewingQuestions = []
1100        # by default
1101        self._numberOfAnswers = 5
1102        self._scaleLower = 0
1103        self._scaleHigher = 100
1104        self._radioButtonsLabels = ["0", "", "50", "", "100"]
1105        self._radioButtonsTitles = ["0", "25", "50", "75", "100"]
1106        self._questionCounter = Counter(1)
1107        self.notifyModification()
1108
1109    def getConference(self):
1110        """ Returns the parent conference of the ConferencePaperReview object
1111        """
1112        return self._conference
1113
1114    # content reviewing and final judgement questions methods
1115    def addReviewingQuestion(self, text):
1116        """ Adds this question at the end of the list of questions
1117        """
1118        newId = self.getNewQuestionId()
1119        question = Question(newId,text)
1120        self._reviewingQuestions.append(question)
1121        self.notifyModification()
1122
1123    def getReviewingQuestions(self):
1124        """ Returns the list of questions
1125        """
1126        return self._reviewingQuestions
1127
1128    #def setReviewingQuestions(self, questions):
1129    #    """ Set the whole list of questions
1130    #    """
1131    #    self._reviewingQuestions = questions
1132
1133    def removeReviewingQuestion(self, questionId):
1134        """ Removes a question from the list
1135        """
1136        question = self.getQuestionById(questionId)
1137
1138        if question:
1139            self._reviewingQuestions.remove(question)
1140            self.notifyModification()
1141        else:
1142            raise MaKaCError("Cannot remove a question which doesn't exist")
1143
1144    def editReviewingQuestion(self, questionId, text):
1145        """ Edit the text of a question """
1146        question = self.getQuestionById(questionId)
1147
1148        if question:
1149            question.setText(text)
1150            self.notifyModification()
1151        else:
1152            raise MaKaCError("Cannot edit a question which doesn't exist")
1153
1154    def getQuestionNames(self):
1155        """ Return the names of the questions which are shown in the webpage """
1156        names = []
1157        for question in self._reviewingQuestions:
1158            names.append(question.getName())
1159        return names
1160
1161    def getQuestionById(self, questionId):
1162        """ Return the question with the especified id """
1163        for question in self._reviewingQuestions:
1164            if (questionId == question.getId()):
1165                return question
1166
1167    def setNumberOfAnswers(self, num):
1168        """ Set the number of possible answers (radio buttons) """
1169        self._numberOfAnswers = num
1170
1171    def getNumberOfAnswers(self):
1172        """ Returns the number of possible answers """
1173        try :
1174            if self._numberOfAnswers:
1175                pass
1176        except AttributeError :
1177            self._numberOfAnswers = 5
1178        return self._numberOfAnswers
1179
1180    def setRadioButtonsLabels(self):
1181        """ Set the labels for the radio buttons """
1182        self._radioButtonsLabels = []
1183        i = 0
1184        while i<self.getNumberOfAnswers():
1185            if i == 0: # first label
1186                self._radioButtonsLabels.append(str(self.getScaleLower()))
1187            elif i == self._numberOfAnswers - 1: # last label
1188                self._radioButtonsLabels.append(str(self.getScaleHigher()))
1189            # middle label: exist middle radio button, i has the correct value, exist middle value in the scale
1190            elif (self.getNumberOfAnswers() % 2 == 1) and  (i ==  (self.getNumberOfAnswers() - 1) / 2):
1191                # check if we need float division
1192                if ((self.getScaleLower() + self.getScaleHigher()) % 2 == 0):
1193                    label = str((self.getScaleLower() + self.getScaleHigher()) / 2)
1194                    self._radioButtonsLabels.append(label)
1195                else:
1196                    label = str((self.getScaleLower() + self.getScaleHigher()) / float(2))
1197                    self._radioButtonsLabels.append(label)
1198            # Two middles labels
1199            #elif (self.getNumberOfAnswers() % 2 == 0) and ((i ==  (self.getNumberOfAnswers() - 1) / 2) or (i == (self.getNumberOfAnswers() / 2))):
1200                # check if we need float division
1201            #    if ((i*self.getScaleHigher()) % (self.getNumberOfAnswers()-1) == 0):
1202            #        label = str(((self.getScaleHigher()-self.getScaleLower())/(self.getNumberOfAnswers()-1))*i + self.getScaleLower())
1203            #        self._radioButtonsLabels.append(label)
1204            #    else:
1205            #        label = "%.1f" % (((self.getScaleHigher()-self.getScaleLower())/float(self.getNumberOfAnswers()-1))*i + self.getScaleLower())
1206            #        self._radioButtonsLabels.append(label)
1207            else:
1208                self._radioButtonsLabels.append("")
1209            #else: All the labels
1210            #    self._radioButtonsLabels.append(str((i*self.getScaleHigher())/float(self._numberOfAnswers-1)))
1211            i += 1
1212
1213    def setRadioButtonsTitles(self):
1214        """ Set the titles for the radio buttons """
1215        self._radioButtonsTitles = []
1216        i = 0
1217        while i<self.getNumberOfAnswers():
1218            # check if we need float division
1219            if ((i*self.getScaleHigher()) % (self.getNumberOfAnswers()-1) == 0):
1220                title = "%.0f" % (((self.getScaleHigher()-self.getScaleLower())/float(self.getNumberOfAnswers()-1))*i + self.getScaleLower())
1221                self._radioButtonsTitles.append(title)
1222            else:
1223                title = "%.1f" % (((self.getScaleHigher()-self.getScaleLower())/float(self.getNumberOfAnswers()-1))*i + self.getScaleLower())
1224                self._radioButtonsTitles.append(title)
1225            i += 1
1226
1227    def getRadioButtonsTitles(self):
1228        """ Get the titles for the radio buttons """
1229        return self._radioButtonsTitles
1230
1231
1232    def getScaleLower(self):
1233        try :
1234            if self._scaleLower:
1235                pass
1236        except AttributeError :
1237            self._scaleLower = 0
1238        return self._scaleLower
1239
1240    def getScaleHigher(self):
1241        try :
1242            if self._scaleHigher:
1243                pass
1244        except AttributeError :
1245            self._scaleHigher = 100
1246        return self._scaleHigher
1247
1248
1249
1250    def getRadioButtonsLabels(self):
1251        """ Get the labels for the radio buttons """
1252        try :
1253            if self._radioButtonsLabels:
1254                pass
1255        except AttributeError :
1256            self._radioButtonsLabels = ["0", "", "50", "", "100"]
1257        return self._radioButtonsLabels
1258
1259    def setScale(self, min, max):
1260        """ Set the scale for the rating and labels """
1261        self._scaleLower = min
1262        self._scaleHigher = max
1263
1264    def getNewQuestionId(self):
1265        """ Returns a new an unused questionId
1266            Increments the questionId counter
1267        """
1268        return self._questionCounter.newCount()
1269
1270##################################### NOT USED YET #####################################################
1271
1272    # date methods
1273    def setDefaultAbstractReviewerDueDate(self, date):
1274        self._defaultAbstractReviewerDueDate = date
1275
1276    def getDefaultAbstractReviewerDueDate(self):
1277        if not hasattr(self, '_defaultAbstractReviewerDueDate'):
1278            self._defaultAbstractReviewerDueDate = None
1279        return self._defaultAbstractReviewerDueDate
1280
1281    def getAdjustedDefaultAbstractReviewerDueDate(self):
1282        if self.getDefaultAbstractReviewerDueDate() is None:
1283            return None
1284        else:
1285            return getAdjustedDate(self._defaultAbstractReviewerDueDate, self.getConference())
1286
1287
1288    #abstract manager methods
1289
1290    def addAbstractManager(self, newAbstractManager):
1291        """ Adds a new abstract manager to the conference.
1292            newAbstractManager has to be an Avatar object.
1293            The abstract manager is sent a mail notification.
1294        """
1295        if newAbstractManager in self.getAbstractManagersList():
1296            raise MaKaCError("This abstract manager has already been added to this conference")
1297        else:
1298            self._abstractManagerList.append(newAbstractManager)
1299            newAbstractManager.linkTo(self._conference, "abstractManager")
1300            if not self._userCompetences.has_key(newAbstractManager):
1301                self._userCompetences[newAbstractManager] = []
1302            self.notifyModification()
1303            notification = ConferenceReviewingNotification(newAbstractManager, 'Abstract Manager', self._conference)
1304            GenericMailer.sendAndLog(notification, self._conference, "Reviewing", newAbstractManager)
1305
1306    def removeAbstractManager(self, abstractManager):
1307        """ Remove a abstract manager from the conference.
1308            abstractManager has to be an Avatar object.
1309            The abstract manager is sent a mail notification.
1310        """
1311        if abstractManager in self._abstractManagerList:
1312            if self._userCompetences.has_key(abstractManager):
1313                if not ((abstractManager in self._editorsList) or \
1314                        (abstractManager in self._paperReviewManagersList) or \
1315                        (abstractManager in self._refereesList) or \
1316                        (abstractManager in self._reviewersList) or \
1317                        (abstractManager in self._abstractReviewersList)):
1318                    self.clearUserCompetences(abstractManager)
1319                    del(self._userCompetences[abstractManager])
1320            self._abstractManagerList.remove(abstractManager)
1321            abstractManager.unlinkTo(self._conference, "abstractManager")
1322            self.notifyModification()
1323            notification = ConferenceReviewingRemoveNotification(abstractManager, 'Abstract Manager', self._conference)
1324            GenericMailer.sendAndLog(notification, self._conference, "Reviewing", abstractManager)
1325        else:
1326            raise MaKaCError("Cannot remove a abstract manager who is not yet abstract manager")
1327
1328    def isAbstractManager(self, user):
1329        """ Returns if a given user is abstract manager of the conference.
1330            user has to be an Avatar object.
1331        """
1332        return user in self._abstractManagerList
1333
1334    def getAbstractManagersList(self):
1335        """ Returns the list of abstract managers as a list of users.
1336        """
1337        return self._abstractManagerList
1338
1339    def isAbstractReviewer(self, user):
1340        """ Returns if a given user is abstract reviewer of the conference.
1341            user has to be an Avatar object.
1342        """
1343        return user in self._abstractReviewersList
1344
1345    def getAbstractReviewersList(self):
1346        """ Returns the list of abstract reviewers as a list of users.
1347        """
1348        return self._abstractReviewersList
1349
1350    def addReviewerAbstract(self, abstractReviewer, abstract):
1351        """ Adds the abstract to the list of abstracts for a given abstract reviewer.
1352            abstractReviewer has to be an Avatar object.
1353        """
1354        if self._reviewerAbstract.has_key(abstractReviewer):
1355            self._reviewerAbstract[abstractReviewer].append(abstract)
1356            self._reviewerAbstract[abstractReviewer].sort(key= lambda c: int(c.getId()))
1357        else:
1358            self._reviewerAbstract[abstractReviewer] = [abstract]
1359        self.notifyModification()
1360
1361    def removeReviewerAbstract(self, abstractReviewer, abstract):
1362        """ Removes the contribution from the list of contributions of this reviewer
1363            reviewer has to be an Avatar object.
1364        """
1365        if self._reviewerAbstract.has_key(abstractReviewer):
1366            self._reviewerAbstract[abstractReviewer].remove(abstract)
1367        self.notifyModification()
1368
1369    def isReviewerAbstract(self, abstractReviewer, abstract):
1370        """ Returns if a user is reviewer for a given contribution
1371            reviewer has to be an Avatar object.
1372        """
1373        return self._reviewerAbstract.has_key(abstractReviewer) and abstract in self._reviewerAbstract[abstractReviewer]
1374
1375    def getReviewedAbstracts(self, abstractReviewer):
1376        """ Returns the list of abstracts for a given reviewer
1377            reviewer has to be an Avatar object.
1378        """
1379        if self._reviewerAbstract.has_key(abstractReviewer):
1380            return self._reviewerAbstract[abstractReviewer]
1381        else:
1382            return []
1383
1384    #competences methods
1385    def isInReviewingTeam(self, user):
1386        return user in self._abstractManagerList or \
1387               user in self._abstractReviewersList
1388
1389
1390    def getUserReviewingRoles(self, user):
1391        """ Returns the list of roles (PRM, referee, editor, reviewer) that a given user has
1392            in this conference, as a list of strings.
1393        """
1394        roles=[]
1395        if self.isAbstractManager(user):
1396            roles.append('Abstracts Manager')
1397        if self.isAbstractReviewer(user):
1398            roles.append('Abstract Reviewer')
1399        return roles
1400##########################################################################################
1401
1402    def notifyModification(self):
1403        """ Notifies the DB that a list or dictionary attribute of this object has changed
1404        """
1405        self._p_changed = 1
1406
1407
1408
1409class Question(Persistent, Fossilizable):
1410
1411    """
1412    This class represents a question for the abstracts reviewing.
1413    """
1414
1415    fossilizes(IReviewingQuestionFossil)
1416
1417    def __init__( self, newId, text):
1418        """ Constructor.
1419            name is a string which represents the content of the question
1420        """
1421        self._id = newId
1422        self._text = text
1423
1424    def getId(self):
1425        return self._id
1426
1427    def getText(self):
1428        return self._text
1429
1430    def setText(self, text):
1431        self._text = text
1432
1433    def notifyModification(self):
1434        """ Notifies the DB that a list or dictionary attribute of this object has changed
1435        """
1436        self._p_changed = 1
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
Note: See TracBrowser for help on using the repository browser.