source: indico/indico/MaKaC/reviewing.py @ f16f89

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

[FTR] Abstract reviewing

Implemented several functionalities in abstract reviewing

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