| 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 | |
|---|
| 21 | from copy import copy |
|---|
| 22 | from pytz import timezone |
|---|
| 23 | import ZODB |
|---|
| 24 | from persistent import Persistent |
|---|
| 25 | from persistent.list import PersistentList |
|---|
| 26 | from BTrees.OOBTree import OOBTree, intersection, union |
|---|
| 27 | from BTrees.IOBTree import IOBTree |
|---|
| 28 | import BTrees.OIBTree as OIBTree |
|---|
| 29 | from datetime import datetime,timedelta |
|---|
| 30 | import MaKaC |
|---|
| 31 | from MaKaC.common.Counter import Counter |
|---|
| 32 | from MaKaC.errors import MaKaCError |
|---|
| 33 | from MaKaC.accessControl import AdminList |
|---|
| 34 | from MaKaC.trashCan import TrashCanManager |
|---|
| 35 | from MaKaC.common.timezoneUtils import nowutc |
|---|
| 36 | from MaKaC.i18n import _ |
|---|
| 37 | #from MaKaC.abstractReviewing import AbstractReview |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | class AbstractSorter: |
|---|
| 41 | pass |
|---|
| 42 | |
|---|
| 43 | class AbstractFilter: |
|---|
| 44 | pass |
|---|
| 45 | |
|---|
| 46 | |
|---|
| 47 | class _AbstractParticipationIndex(Persistent): |
|---|
| 48 | """This class allows to index abstract participations (submitters) |
|---|
| 49 | for a single CFA process; this means that clients will be able to |
|---|
| 50 | efficiently perform queries of the type "give me all the abstracts |
|---|
| 51 | in which a certain registered user is implied". |
|---|
| 52 | For being able to perform this indexing, it is supposed that the Avatar |
|---|
| 53 | identifier is unique among other avatars and that it cannot change. |
|---|
| 54 | This index must be maintained by clients (i.e. the CFAMgr) as it doesn't |
|---|
| 55 | keep track of the changes on Participantons. |
|---|
| 56 | The key of the index is the Avatar and the values the different |
|---|
| 57 | Participations that user has within the current CFA process. For |
|---|
| 58 | performance reasons, the Avatar id will be used as index key (using the |
|---|
| 59 | whole Avatar object would make the index bigger and as the Avatar id |
|---|
| 60 | cannot change it's enough); the clients would have to keep the |
|---|
| 61 | integrity of the index. |
|---|
| 62 | """ |
|---|
| 63 | |
|---|
| 64 | def __init__( self ): |
|---|
| 65 | self._idx = OOBTree() |
|---|
| 66 | |
|---|
| 67 | def index( self, participation ): |
|---|
| 68 | """Add a new participation to the index |
|---|
| 69 | """ |
|---|
| 70 | #if the Participation is not linked to an Avatar there's no point to |
|---|
| 71 | # index it |
|---|
| 72 | a = participation.getAvatar() |
|---|
| 73 | if not a: |
|---|
| 74 | return |
|---|
| 75 | #ToDo: if the Participation corresponds to an abstract which doesn't |
|---|
| 76 | # correspond to the current CFAMgr, then an error must be raised |
|---|
| 77 | |
|---|
| 78 | if not self._idx.has_key( a.getId() ): |
|---|
| 79 | self._idx[a.getId()] = PersistentList() |
|---|
| 80 | #if the participation is already in the index, no need for adding it |
|---|
| 81 | if participation in self._idx[a.getId()]: |
|---|
| 82 | return |
|---|
| 83 | self._idx[a.getId()].append( participation ) |
|---|
| 84 | |
|---|
| 85 | def unindex( self, participation ): |
|---|
| 86 | """Remove an existing participation from the index |
|---|
| 87 | """ |
|---|
| 88 | #if the Participation is not linked to an Avatar there's no point to |
|---|
| 89 | # unindex it |
|---|
| 90 | a = participation.getAvatar() |
|---|
| 91 | |
|---|
| 92 | if not a: |
|---|
| 93 | return |
|---|
| 94 | #if the Avatar associated to the participation isn't in the index do |
|---|
| 95 | # nothing |
|---|
| 96 | if not self._idx.has_key( a.getId() ): |
|---|
| 97 | return |
|---|
| 98 | #if the given participation is indexed remove it, otherwise do nothing |
|---|
| 99 | if participation in self._idx[a.getId()]: |
|---|
| 100 | self._idx[a.getId()].remove( participation ) |
|---|
| 101 | |
|---|
| 102 | def getParticipationList( self, av ): |
|---|
| 103 | try: |
|---|
| 104 | return self._idx[ av.getId() ] |
|---|
| 105 | except KeyError, e: |
|---|
| 106 | return [] |
|---|
| 107 | |
|---|
| 108 | |
|---|
| 109 | class AbstractParticipation(Persistent): |
|---|
| 110 | |
|---|
| 111 | def __init__( self, abstract, **data ): |
|---|
| 112 | self._abstract = abstract |
|---|
| 113 | self._firstName = "" |
|---|
| 114 | self._surName = "" |
|---|
| 115 | self._email = "" |
|---|
| 116 | self._affilliation = "" |
|---|
| 117 | self._address = "" |
|---|
| 118 | self._telephone = "" |
|---|
| 119 | self._fax = "" |
|---|
| 120 | self._title = "" |
|---|
| 121 | self.setData( **data ) |
|---|
| 122 | |
|---|
| 123 | def setFromAvatar( self, av ): |
|---|
| 124 | data = {"title": av.getTitle(), \ |
|---|
| 125 | "firstName": av.getName(), \ |
|---|
| 126 | "surName": av.getSurName(), \ |
|---|
| 127 | "email": av.getEmail(), \ |
|---|
| 128 | "affiliation": av.getOrganisation(), \ |
|---|
| 129 | "address": av.getAddress(), \ |
|---|
| 130 | "telephone": av.getTelephone(), \ |
|---|
| 131 | "fax": av.getFax() } |
|---|
| 132 | self.setData( **data ) |
|---|
| 133 | |
|---|
| 134 | def setFromAbstractParticipation(self,part): |
|---|
| 135 | data = {"title": part.getTitle(), \ |
|---|
| 136 | "firstName": part.getFirstName(), \ |
|---|
| 137 | "surName": part.getSurName(), \ |
|---|
| 138 | "email": part.getEmail(), \ |
|---|
| 139 | "affiliation": part.getAffiliation(), \ |
|---|
| 140 | "address": part.getAddress(), \ |
|---|
| 141 | "telephone": part.getTelephone(), \ |
|---|
| 142 | "fax": part.getFax() } |
|---|
| 143 | self.setData( **data ) |
|---|
| 144 | |
|---|
| 145 | def setData( self, **data ): |
|---|
| 146 | if "firstName" in data: |
|---|
| 147 | self.setFirstName( data["firstName"] ) |
|---|
| 148 | if "surName" in data: |
|---|
| 149 | self.setSurName( data["surName"] ) |
|---|
| 150 | if "email" in data: |
|---|
| 151 | self.setEmail( data["email"] ) |
|---|
| 152 | if "affiliation" in data: |
|---|
| 153 | self.setAffiliation( data["affiliation"] ) |
|---|
| 154 | if "address" in data: |
|---|
| 155 | self.setAddress( data["address"] ) |
|---|
| 156 | if "telephone" in data: |
|---|
| 157 | self.setTelephone( data["telephone"] ) |
|---|
| 158 | if "fax" in data: |
|---|
| 159 | self.setFax( data["fax"] ) |
|---|
| 160 | if "title" in data: |
|---|
| 161 | self.setTitle( data["title"] ) |
|---|
| 162 | setValues = setData |
|---|
| 163 | |
|---|
| 164 | def getData(self): |
|---|
| 165 | data = {} |
|---|
| 166 | data["firstName"] = self.getFirstName() |
|---|
| 167 | data["surName"] = self.getSurName() |
|---|
| 168 | data["email"] = self.getEmail() |
|---|
| 169 | data["affiliation"] = self.getAffiliation() |
|---|
| 170 | data["address"] = self.getAddress() |
|---|
| 171 | data["telephone"] = self.getTelephone() |
|---|
| 172 | data["fax"] = self.getFax() |
|---|
| 173 | data["title"] = self.getTitle() |
|---|
| 174 | |
|---|
| 175 | return data |
|---|
| 176 | getValues = getData |
|---|
| 177 | |
|---|
| 178 | def clone (self, abstract): |
|---|
| 179 | ap = AbstractParticipation(abstract,self.getData()) |
|---|
| 180 | return ap |
|---|
| 181 | |
|---|
| 182 | def _notifyModification(self): |
|---|
| 183 | self._abstract._notifyModification() |
|---|
| 184 | |
|---|
| 185 | def _unindex(self): |
|---|
| 186 | abs=self.getAbstract() |
|---|
| 187 | if abs is not None: |
|---|
| 188 | mgr=abs.getOwner() |
|---|
| 189 | if mgr is not None: |
|---|
| 190 | mgr.unindexAuthor(self) |
|---|
| 191 | |
|---|
| 192 | def _index(self): |
|---|
| 193 | abs=self.getAbstract() |
|---|
| 194 | if abs is not None: |
|---|
| 195 | mgr=abs.getOwner() |
|---|
| 196 | if mgr is not None: |
|---|
| 197 | mgr.indexAuthor(self) |
|---|
| 198 | |
|---|
| 199 | def setFirstName( self, name ): |
|---|
| 200 | tmp=name.strip() |
|---|
| 201 | if tmp==self.getFirstName(): |
|---|
| 202 | return |
|---|
| 203 | self._unindex() |
|---|
| 204 | self._firstName=tmp |
|---|
| 205 | self._index() |
|---|
| 206 | self._notifyModification() |
|---|
| 207 | |
|---|
| 208 | def getFirstName( self ): |
|---|
| 209 | return self._firstName |
|---|
| 210 | |
|---|
| 211 | def getName( self ): |
|---|
| 212 | return self._firstName |
|---|
| 213 | |
|---|
| 214 | def setSurName( self, name ): |
|---|
| 215 | tmp=name.strip() |
|---|
| 216 | if tmp==self.getSurName(): |
|---|
| 217 | return |
|---|
| 218 | self._unindex() |
|---|
| 219 | self._surName=tmp |
|---|
| 220 | self._index() |
|---|
| 221 | self._notifyModification() |
|---|
| 222 | |
|---|
| 223 | def getSurName( self ): |
|---|
| 224 | return self._surName |
|---|
| 225 | |
|---|
| 226 | def getFamilyName( self ): |
|---|
| 227 | return self._surName |
|---|
| 228 | |
|---|
| 229 | def setEmail( self, email ): |
|---|
| 230 | email = email.strip().lower() |
|---|
| 231 | if email != self.getEmail(): |
|---|
| 232 | self._email = email |
|---|
| 233 | self._notifyModification() |
|---|
| 234 | |
|---|
| 235 | def getEmail( self ): |
|---|
| 236 | return self._email |
|---|
| 237 | |
|---|
| 238 | def setAffiliation( self, af ): |
|---|
| 239 | self._affilliation = af.strip() |
|---|
| 240 | self._notifyModification() |
|---|
| 241 | |
|---|
| 242 | setAffilliation=setAffiliation |
|---|
| 243 | |
|---|
| 244 | def getAffiliation( self ): |
|---|
| 245 | return self._affilliation |
|---|
| 246 | |
|---|
| 247 | def setAddress( self, address ): |
|---|
| 248 | self._address = address.strip() |
|---|
| 249 | self._notifyModification() |
|---|
| 250 | |
|---|
| 251 | def getAddress( self ): |
|---|
| 252 | return self._address |
|---|
| 253 | |
|---|
| 254 | def setTelephone( self, telf ): |
|---|
| 255 | self._telephone = telf.strip() |
|---|
| 256 | self._notifyModification() |
|---|
| 257 | |
|---|
| 258 | def getTelephone( self ): |
|---|
| 259 | return self._telephone |
|---|
| 260 | |
|---|
| 261 | def setFax( self, fax ): |
|---|
| 262 | self._fax = fax.strip() |
|---|
| 263 | self._notifyModification() |
|---|
| 264 | |
|---|
| 265 | def getFax(self): |
|---|
| 266 | return self._fax |
|---|
| 267 | |
|---|
| 268 | def setTitle( self, title ): |
|---|
| 269 | self._title = title.strip() |
|---|
| 270 | self._notifyModification() |
|---|
| 271 | |
|---|
| 272 | def getTitle( self ): |
|---|
| 273 | return self._title |
|---|
| 274 | |
|---|
| 275 | def getFullName( self ): |
|---|
| 276 | res = self.getSurName().upper() |
|---|
| 277 | tmp=[] |
|---|
| 278 | for name in self.getFirstName().lower().split(" "): |
|---|
| 279 | if name.strip() == "": |
|---|
| 280 | continue |
|---|
| 281 | name=name.strip() |
|---|
| 282 | tmp.append("%s%s"%(name[0].upper(),name[1:])) |
|---|
| 283 | firstName=" ".join(tmp) |
|---|
| 284 | if firstName != "": |
|---|
| 285 | res = "%s, %s"%( res, firstName ) |
|---|
| 286 | if self.getTitle() != "": |
|---|
| 287 | res = "%s %s"%( self.getTitle(), res ) |
|---|
| 288 | return res |
|---|
| 289 | |
|---|
| 290 | def getStraightFullName(self): |
|---|
| 291 | name = "" |
|---|
| 292 | if self.getName() != "": |
|---|
| 293 | name = "%s "%self.getName() |
|---|
| 294 | return "%s%s"%(name, self.getSurName()) |
|---|
| 295 | |
|---|
| 296 | def getAbrName(self): |
|---|
| 297 | res = self.getSurName() |
|---|
| 298 | if self.getFirstName() != "": |
|---|
| 299 | if res != "": |
|---|
| 300 | res = "%s, "%res |
|---|
| 301 | res = "%s%s."%(res, self.getFirstName()[0].upper()) |
|---|
| 302 | return res |
|---|
| 303 | |
|---|
| 304 | def getAbstract( self ): |
|---|
| 305 | return self._abstract |
|---|
| 306 | |
|---|
| 307 | def setAbstract(self, abs): |
|---|
| 308 | self._abstract = abs |
|---|
| 309 | |
|---|
| 310 | def delete( self ): |
|---|
| 311 | self._abstract = None |
|---|
| 312 | TrashCanManager().add(self) |
|---|
| 313 | |
|---|
| 314 | def recover(self): |
|---|
| 315 | TrashCanManager().remove(self) |
|---|
| 316 | |
|---|
| 317 | |
|---|
| 318 | class Author( AbstractParticipation ): |
|---|
| 319 | |
|---|
| 320 | def __init__( self, abstract, **data ): |
|---|
| 321 | AbstractParticipation.__init__( self, abstract, **data ) |
|---|
| 322 | self._abstractId = "" |
|---|
| 323 | |
|---|
| 324 | def getId( self ): |
|---|
| 325 | return self._id |
|---|
| 326 | |
|---|
| 327 | def setId( self, newId ): |
|---|
| 328 | self._id = str( newId ) |
|---|
| 329 | |
|---|
| 330 | def clone(self, abstract): |
|---|
| 331 | auth = Author(abstract, self.getData()) |
|---|
| 332 | return auth |
|---|
| 333 | |
|---|
| 334 | class Submitter( AbstractParticipation ): |
|---|
| 335 | |
|---|
| 336 | def __init__( self, abstract, av ): |
|---|
| 337 | if av == None: |
|---|
| 338 | raise MaKaCError( _("abstract submitter cannot be None") ) |
|---|
| 339 | AbstractParticipation.__init__( self, abstract ) |
|---|
| 340 | self._user = None |
|---|
| 341 | self._setUser( av ) |
|---|
| 342 | self.setFromAvatar( av ) |
|---|
| 343 | |
|---|
| 344 | def _setUser( self, av ): |
|---|
| 345 | if self.getUser() == av: |
|---|
| 346 | return |
|---|
| 347 | #if currently there's an association with a registered user, we notify |
|---|
| 348 | # the unidexation of the participation |
|---|
| 349 | if self.getUser(): |
|---|
| 350 | self.getAbstract().getOwner().unregisterParticipation( self ) |
|---|
| 351 | self._user = av |
|---|
| 352 | #if the participation is associated to any avatar, we make the |
|---|
| 353 | # association and index it |
|---|
| 354 | if self.getUser(): |
|---|
| 355 | self.getAbstract().getOwner().registerParticipation( self ) |
|---|
| 356 | |
|---|
| 357 | def clone(self, abstract): |
|---|
| 358 | sub = Submitter(abstract,self.getAvatar()) |
|---|
| 359 | sub.setData(self.getData()) |
|---|
| 360 | return sub |
|---|
| 361 | |
|---|
| 362 | def getUser( self ): |
|---|
| 363 | return self._user |
|---|
| 364 | |
|---|
| 365 | def getAvatar( self ): |
|---|
| 366 | return self._user |
|---|
| 367 | |
|---|
| 368 | def representsUser( self, av ): |
|---|
| 369 | return self.getUser() == av |
|---|
| 370 | |
|---|
| 371 | |
|---|
| 372 | class _AuthIdx(Persistent): |
|---|
| 373 | |
|---|
| 374 | def __init__(self,mgr): |
|---|
| 375 | self._mgr=mgr |
|---|
| 376 | self._idx=OOBTree() |
|---|
| 377 | |
|---|
| 378 | def _getKey(self,auth): |
|---|
| 379 | return "%s %s"%(auth.getSurName().lower(),auth.getFirstName().lower()) |
|---|
| 380 | |
|---|
| 381 | def index(self,auth): |
|---|
| 382 | if auth.getAbstract() is None: |
|---|
| 383 | raise MaKaCError( _("cannot index an author of an abstract which is not included in a conference")) |
|---|
| 384 | if auth.getAbstract().getOwner()!=self._mgr: |
|---|
| 385 | raise MaKaCError( _("cannot index an author of an abstract which does not belong to this conference")) |
|---|
| 386 | key=self._getKey(auth) |
|---|
| 387 | abstractId=str(auth.getAbstract().getId()) |
|---|
| 388 | if not self._idx.has_key(key): |
|---|
| 389 | self._idx[key]=OIBTree.OIBTree() |
|---|
| 390 | if not self._idx[key].has_key(abstractId): |
|---|
| 391 | self._idx[key][abstractId]=0 |
|---|
| 392 | self._idx[key][abstractId]+=1 |
|---|
| 393 | |
|---|
| 394 | def unindex(self,auth): |
|---|
| 395 | if auth.getAbstract() is None: |
|---|
| 396 | raise MaKaCError( _("cannot unindex an author of an abstract which is not included in a conference")) |
|---|
| 397 | if auth.getAbstract().getOwner()!=self._mgr: |
|---|
| 398 | raise MaKaCError( _("cannot unindex an author of an abstract which does not belong to this conference")) |
|---|
| 399 | key=self._getKey(auth) |
|---|
| 400 | if not self._idx.has_key(key): |
|---|
| 401 | return |
|---|
| 402 | abstractId=str(auth.getAbstract().getId()) |
|---|
| 403 | self._idx[key][abstractId]-=1 |
|---|
| 404 | if self._idx[key][abstractId]<=0: |
|---|
| 405 | del self._idx[key][abstractId] |
|---|
| 406 | if len(self._idx[key])<=0: |
|---|
| 407 | del self._idx[key] |
|---|
| 408 | |
|---|
| 409 | def match(self,query): |
|---|
| 410 | query=query.lower().strip() |
|---|
| 411 | res=OIBTree.OISet() |
|---|
| 412 | for k in self._idx.keys(): |
|---|
| 413 | if k.find(query)!=-1: |
|---|
| 414 | res=OIBTree.union(res,self._idx[k]) |
|---|
| 415 | return res |
|---|
| 416 | |
|---|
| 417 | |
|---|
| 418 | class _PrimAuthIdx(_AuthIdx): |
|---|
| 419 | |
|---|
| 420 | def __init__(self,mgr): |
|---|
| 421 | _AuthIdx.__init__(self,mgr) |
|---|
| 422 | for abs in self._mgr.getAbstractList(): |
|---|
| 423 | for auth in abs.getPrimaryAuthorList(): |
|---|
| 424 | self.index(auth) |
|---|
| 425 | |
|---|
| 426 | class AbstractField(Persistent): |
|---|
| 427 | _fieldTypes = [ 'input', 'textarea' ] |
|---|
| 428 | |
|---|
| 429 | def __init__(self, id, name, caption, maxlength=0, isMandatory=False, type="textarea"): |
|---|
| 430 | self._id = id |
|---|
| 431 | self._name = name |
|---|
| 432 | self._caption = caption |
|---|
| 433 | self._active = True |
|---|
| 434 | self._maxLength = maxlength |
|---|
| 435 | self._isMandatory = isMandatory |
|---|
| 436 | self._type = type |
|---|
| 437 | |
|---|
| 438 | def clone(self): |
|---|
| 439 | af = AbstractField(self.getId(),self.getName(),self.getCaption(),self.getMaxLength(), self.isMandatory(), self.getType()) |
|---|
| 440 | return af |
|---|
| 441 | |
|---|
| 442 | def _notifyModification(self): |
|---|
| 443 | self._p_changed = 1 |
|---|
| 444 | |
|---|
| 445 | def getType(self): |
|---|
| 446 | try: |
|---|
| 447 | return self._type |
|---|
| 448 | except: |
|---|
| 449 | self._type = "textarea" |
|---|
| 450 | return self._type |
|---|
| 451 | |
|---|
| 452 | def setType(self, type): |
|---|
| 453 | self._type = type |
|---|
| 454 | |
|---|
| 455 | def isMandatory(self): |
|---|
| 456 | try: |
|---|
| 457 | return self._isMandatory |
|---|
| 458 | except: |
|---|
| 459 | self._isMandatory = False |
|---|
| 460 | return self._isMandatory |
|---|
| 461 | |
|---|
| 462 | def setMandatory(self, isMandatory=False): |
|---|
| 463 | self._isMandatory = isMandatory |
|---|
| 464 | self._notifyModification() |
|---|
| 465 | |
|---|
| 466 | def getMaxLength(self): |
|---|
| 467 | try: |
|---|
| 468 | return self._maxLength |
|---|
| 469 | except: |
|---|
| 470 | self._maxLength=0 |
|---|
| 471 | return self._maxLength |
|---|
| 472 | |
|---|
| 473 | def setValues(self, name, caption, maxlength, isMandatory, fieldType): |
|---|
| 474 | self._name = name |
|---|
| 475 | self._caption = caption |
|---|
| 476 | self._maxLength = maxlength |
|---|
| 477 | self._isMandatory = isMandatory |
|---|
| 478 | self._type = fieldType |
|---|
| 479 | self._notifyModification() |
|---|
| 480 | |
|---|
| 481 | def setMaxLength(self, maxLength=0): |
|---|
| 482 | self._maxLength = maxLength |
|---|
| 483 | self._notifyModification() |
|---|
| 484 | |
|---|
| 485 | def getId(self): |
|---|
| 486 | return self._id |
|---|
| 487 | |
|---|
| 488 | def setId(self, id): |
|---|
| 489 | self._id=id |
|---|
| 490 | self._notifyModification() |
|---|
| 491 | |
|---|
| 492 | def getName(self): |
|---|
| 493 | try: |
|---|
| 494 | if self._name: |
|---|
| 495 | pass |
|---|
| 496 | except AttributeError, e: |
|---|
| 497 | try: |
|---|
| 498 | if int(self._id): |
|---|
| 499 | pass |
|---|
| 500 | self._name = "" |
|---|
| 501 | except ValueError, er: |
|---|
| 502 | self._name = self._id |
|---|
| 503 | return self._name |
|---|
| 504 | |
|---|
| 505 | def setName(self, name): |
|---|
| 506 | self._name=name |
|---|
| 507 | self._notifyModification() |
|---|
| 508 | |
|---|
| 509 | def getCaption(self): |
|---|
| 510 | return self._caption |
|---|
| 511 | |
|---|
| 512 | def setCaption(self, caption): |
|---|
| 513 | self._caption=caption |
|---|
| 514 | self._notifyModification() |
|---|
| 515 | |
|---|
| 516 | def isActive(self): |
|---|
| 517 | return self._active |
|---|
| 518 | |
|---|
| 519 | def setActive(self, active): |
|---|
| 520 | self._active=active |
|---|
| 521 | self._notifyModification() |
|---|
| 522 | |
|---|
| 523 | class AbstractFieldsMgr(Persistent): |
|---|
| 524 | |
|---|
| 525 | def __init__(self): |
|---|
| 526 | self._fields=self._initFields() |
|---|
| 527 | self.__fieldGenerator = Counter() |
|---|
| 528 | |
|---|
| 529 | def clone(self): |
|---|
| 530 | afm = AbstractFieldsMgr() |
|---|
| 531 | for f in self.getFields(): |
|---|
| 532 | afm._addField(f.clone()) |
|---|
| 533 | return afm |
|---|
| 534 | |
|---|
| 535 | def getFieldGenerator(self): |
|---|
| 536 | try: |
|---|
| 537 | if self.__fieldGenerator: |
|---|
| 538 | pass |
|---|
| 539 | except AttributeError,e: |
|---|
| 540 | self.__fieldGenerator = Counter() |
|---|
| 541 | return self.__fieldGenerator |
|---|
| 542 | |
|---|
| 543 | def _notifyModification(self): |
|---|
| 544 | self._p_changed = 1 |
|---|
| 545 | |
|---|
| 546 | def _initFields(self): |
|---|
| 547 | d=[] |
|---|
| 548 | su=AbstractField("content",_("Content"), _("Abstract content"),0,True) |
|---|
| 549 | d.append(su) |
|---|
| 550 | su=AbstractField("summary",_("Summary"), _("Summary"),0) |
|---|
| 551 | d.append(su) |
|---|
| 552 | return d |
|---|
| 553 | |
|---|
| 554 | def hasField(self, id): |
|---|
| 555 | for f in self._fields: |
|---|
| 556 | if f.getId() == id: |
|---|
| 557 | return True |
|---|
| 558 | return False |
|---|
| 559 | |
|---|
| 560 | def getFields(self): |
|---|
| 561 | if not self.hasField("content"): |
|---|
| 562 | ac=AbstractField("content","Content", _("Abstract content"),0,True) |
|---|
| 563 | self._fields.insert(0, ac) |
|---|
| 564 | return self._fields |
|---|
| 565 | |
|---|
| 566 | def getActiveFields(self): |
|---|
| 567 | fl = [] |
|---|
| 568 | for f in self.getFields(): |
|---|
| 569 | if f.isActive(): |
|---|
| 570 | fl.append(f) |
|---|
| 571 | return fl |
|---|
| 572 | |
|---|
| 573 | def hasActiveField(self, id): |
|---|
| 574 | return self.hasField(id) and self.getFieldById(id).isActive() |
|---|
| 575 | |
|---|
| 576 | def hasAnyActiveField( self ): |
|---|
| 577 | for f in self._fields: |
|---|
| 578 | if f.isActive(): |
|---|
| 579 | return True |
|---|
| 580 | return False |
|---|
| 581 | |
|---|
| 582 | def enableField(self, id): |
|---|
| 583 | if self.hasField(id): |
|---|
| 584 | self.getFieldById(id).setActive(True) |
|---|
| 585 | self._notifyModification() |
|---|
| 586 | |
|---|
| 587 | def disableField(self, id): |
|---|
| 588 | if self.hasField(id): |
|---|
| 589 | self.getFieldById(id).setActive(False) |
|---|
| 590 | self._notifyModification() |
|---|
| 591 | |
|---|
| 592 | def getFieldKeys(self): |
|---|
| 593 | keys = [] |
|---|
| 594 | for f in self._fields: |
|---|
| 595 | keys.append(f.getId()) |
|---|
| 596 | return keys |
|---|
| 597 | |
|---|
| 598 | def getFieldById(self, id): |
|---|
| 599 | for f in self._fields: |
|---|
| 600 | if f.getId() == id: |
|---|
| 601 | return f |
|---|
| 602 | return None |
|---|
| 603 | |
|---|
| 604 | def _addField(self, field): |
|---|
| 605 | self._fields.append(field) |
|---|
| 606 | |
|---|
| 607 | def addField(self, id, name, caption, maxlength=0, isMandatory=False, fieldType="textarea"): |
|---|
| 608 | if self.hasField(id): |
|---|
| 609 | self.getFieldById(id).setValues(name, caption, maxlength, isMandatory, fieldType) |
|---|
| 610 | else: |
|---|
| 611 | id=str(self.getFieldGenerator().newCount()) |
|---|
| 612 | absf = AbstractField(id, name, caption, maxlength, isMandatory, fieldType) |
|---|
| 613 | self._fields.append(absf) |
|---|
| 614 | self._notifyModification() |
|---|
| 615 | return id |
|---|
| 616 | |
|---|
| 617 | def removeField(self, id): |
|---|
| 618 | if self.hasField(id): |
|---|
| 619 | self._fields.remove(self.getFieldById(id)) |
|---|
| 620 | self._notifyModification() |
|---|
| 621 | |
|---|
| 622 | def moveAbsFieldUp(self, id): |
|---|
| 623 | if self.hasField(id): |
|---|
| 624 | f = self.getFieldById(id) |
|---|
| 625 | idx = self._fields.index(f) |
|---|
| 626 | self._fields.remove(f) |
|---|
| 627 | if idx == 0: |
|---|
| 628 | self._fields.append(f) |
|---|
| 629 | else: |
|---|
| 630 | self._fields.insert(idx-1,f) |
|---|
| 631 | self._notifyModification() |
|---|
| 632 | |
|---|
| 633 | def moveAbsFieldDown(self, id): |
|---|
| 634 | if self.hasField(id): |
|---|
| 635 | f = self.getFieldById(id) |
|---|
| 636 | idx = self._fields.index(f) |
|---|
| 637 | self._fields.remove(f) |
|---|
| 638 | if idx == len(self._fields): |
|---|
| 639 | self._fields.insert(0,f) |
|---|
| 640 | else: |
|---|
| 641 | self._fields.insert(idx+1,f) |
|---|
| 642 | self._notifyModification() |
|---|
| 643 | |
|---|
| 644 | class AbstractMgr(Persistent): |
|---|
| 645 | |
|---|
| 646 | def __init__(self, owner): |
|---|
| 647 | self._owner = owner |
|---|
| 648 | self._abstracts = OOBTree() |
|---|
| 649 | self._participationIdx = _AbstractParticipationIndex() |
|---|
| 650 | self.__abstractGenerator = Counter() |
|---|
| 651 | self._activated = False |
|---|
| 652 | self.setStartSubmissionDate( datetime.now() ) |
|---|
| 653 | self.setEndSubmissionDate( datetime.now() ) |
|---|
| 654 | ## self._contribTypes = PersistentList() |
|---|
| 655 | self.setAnnouncement( "" ) |
|---|
| 656 | self._notifTpls=IOBTree() |
|---|
| 657 | self._notifTplsOrder=PersistentList() |
|---|
| 658 | self.__notifTplsCounter=Counter() |
|---|
| 659 | self._authorizedSubmitter = PersistentList() |
|---|
| 660 | self._primAuthIdx =_PrimAuthIdx(self) |
|---|
| 661 | self._abstractFieldsMgr=AbstractFieldsMgr() |
|---|
| 662 | self._submissionNotification=SubmissionNotification() |
|---|
| 663 | self._multipleTracks = True |
|---|
| 664 | self._tracksMandatory = False |
|---|
| 665 | |
|---|
| 666 | def getMultipleTracks( self ): |
|---|
| 667 | try: |
|---|
| 668 | return self._multipleTracks |
|---|
| 669 | except: |
|---|
| 670 | self.setMultipleTracks( True ) |
|---|
| 671 | return self._multipleTracks |
|---|
| 672 | |
|---|
| 673 | def setMultipleTracks( self, multipleTracks = True ): |
|---|
| 674 | self._multipleTracks = multipleTracks |
|---|
| 675 | |
|---|
| 676 | def areTracksMandatory( self ): |
|---|
| 677 | try: |
|---|
| 678 | return self._tracksMandatory |
|---|
| 679 | except: |
|---|
| 680 | self.setTracksMandatory( False ) |
|---|
| 681 | return self._tracksMandatory |
|---|
| 682 | |
|---|
| 683 | def setTracksMandatory( self, tracksMandatory = False ): |
|---|
| 684 | self._tracksMandatory = tracksMandatory |
|---|
| 685 | |
|---|
| 686 | def getAbstractFieldsMgr(self): |
|---|
| 687 | try: |
|---|
| 688 | return self._abstractFieldsMgr |
|---|
| 689 | except: |
|---|
| 690 | self._abstractFieldsMgr=AbstractFieldsMgr() |
|---|
| 691 | return self._abstractFieldsMgr |
|---|
| 692 | |
|---|
| 693 | def clone(self, conference): |
|---|
| 694 | amgr = AbstractMgr(conference) |
|---|
| 695 | amgr._abstractFieldsMgr = self.getAbstractFieldsMgr().clone() |
|---|
| 696 | amgr.setAnnouncement(self.getAnnouncement()) |
|---|
| 697 | |
|---|
| 698 | timeDifference = conference.getStartDate() - self.getOwner().getStartDate() |
|---|
| 699 | amgr.setStartSubmissionDate(self.getStartSubmissionDate() + timeDifference) |
|---|
| 700 | amgr.setEndSubmissionDate(self.getEndSubmissionDate() + timeDifference) |
|---|
| 701 | |
|---|
| 702 | modifDeadline = self.getModificationDeadline() |
|---|
| 703 | if modifDeadline is not None : |
|---|
| 704 | amgr.setModificationDeadline(self.getModificationDeadline() + timeDifference) |
|---|
| 705 | |
|---|
| 706 | amgr.setActive(self.isActive()) |
|---|
| 707 | if self.getCFAStatus() : |
|---|
| 708 | amgr.activeCFA() |
|---|
| 709 | else : |
|---|
| 710 | amgr.desactiveCFA() |
|---|
| 711 | |
|---|
| 712 | for a in self.getAbstractList() : |
|---|
| 713 | amgr.addAbstract(a.clone(conference, amgr._generateNewAbstractId())) |
|---|
| 714 | |
|---|
| 715 | for tpl in self.getNotificationTplList() : |
|---|
| 716 | amgr.addNotificationTpl(tpl.clone()) |
|---|
| 717 | |
|---|
| 718 | # Cloning submission notification: |
|---|
| 719 | amgr.setSubmissionNotification(self.getSubmissionNotification().clone()) |
|---|
| 720 | |
|---|
| 721 | return amgr |
|---|
| 722 | |
|---|
| 723 | def getOwner(self): |
|---|
| 724 | return self._owner |
|---|
| 725 | getConference = getOwner |
|---|
| 726 | |
|---|
| 727 | def getTimezone(self): |
|---|
| 728 | return self.getConference().getTimezone() |
|---|
| 729 | |
|---|
| 730 | def activeCFA(self): |
|---|
| 731 | self._activated = True |
|---|
| 732 | |
|---|
| 733 | def desactiveCFA(self): |
|---|
| 734 | self._activated = False |
|---|
| 735 | |
|---|
| 736 | def getAuthorizedSubmitterList(self): |
|---|
| 737 | try: |
|---|
| 738 | return self._authorizedSubmitter |
|---|
| 739 | except AttributeError: |
|---|
| 740 | self._authorizedSubmitter = PersistentList() |
|---|
| 741 | return self._authorizedSubmitter |
|---|
| 742 | |
|---|
| 743 | def addAuthorizedSubmitter(self, av): |
|---|
| 744 | try: |
|---|
| 745 | if self._authorizedSubmitter: |
|---|
| 746 | pass |
|---|
| 747 | except AttributeError: |
|---|
| 748 | self._authorizedSubmitter = PersistentList() |
|---|
| 749 | if not av in self._authorizedSubmitter: |
|---|
| 750 | self._authorizedSubmitter.append(av) |
|---|
| 751 | av.linkTo(self, "abstractSubmitter") |
|---|
| 752 | |
|---|
| 753 | def removeAuthorizedSubmitter(self, av): |
|---|
| 754 | try: |
|---|
| 755 | if self._authorizedSubmitter: |
|---|
| 756 | pass |
|---|
| 757 | except: |
|---|
| 758 | self._authorizedSubmitter = PersistentList() |
|---|
| 759 | if av in self._authorizedSubmitter: |
|---|
| 760 | self._authorizedSubmitter.remove(av) |
|---|
| 761 | av.unlinkTo(self, "abstractSubmitter") |
|---|
| 762 | |
|---|
| 763 | def getCFAStatus(self): |
|---|
| 764 | return self._activated |
|---|
| 765 | |
|---|
| 766 | def setActive(self, value): |
|---|
| 767 | if value: |
|---|
| 768 | self.activeCFA() |
|---|
| 769 | else: |
|---|
| 770 | self.desactiveCFA() |
|---|
| 771 | |
|---|
| 772 | def isActive(self): |
|---|
| 773 | return self._activated |
|---|
| 774 | |
|---|
| 775 | def setStartSubmissionDate(self, date): |
|---|
| 776 | self._submissionStartDate = datetime(date.year,date.month,date.day,0,0,0) |
|---|
| 777 | |
|---|
| 778 | def getStartSubmissionDate(self): |
|---|
| 779 | return timezone(self.getTimezone()).localize(self._submissionStartDate) |
|---|
| 780 | |
|---|
| 781 | def setEndSubmissionDate(self, date): |
|---|
| 782 | self._submissionEndDate = datetime(date.year,date.month,date.day,23,59,59) |
|---|
| 783 | |
|---|
| 784 | def getEndSubmissionDate(self): |
|---|
| 785 | return timezone(self.getTimezone()).localize(self._submissionEndDate) |
|---|
| 786 | |
|---|
| 787 | def inSubmissionPeriod( self, date = None ): |
|---|
| 788 | if date is None: |
|---|
| 789 | date=nowutc() |
|---|
| 790 | sd = self.getStartSubmissionDate() |
|---|
| 791 | ed = self.getEndSubmissionDate() |
|---|
| 792 | return date <= ed and date >= sd |
|---|
| 793 | |
|---|
| 794 | def getModificationDeadline( self ): |
|---|
| 795 | """Returns the deadline for modifications on the submitted abstracts. |
|---|
| 796 | """ |
|---|
| 797 | try: |
|---|
| 798 | if self._modifDeadline: |
|---|
| 799 | pass |
|---|
| 800 | except AttributeError, e: |
|---|
| 801 | self._modifDeadline = None |
|---|
| 802 | if self._modifDeadline != None: |
|---|
| 803 | return timezone(self.getTimezone()).localize(self._modifDeadline) |
|---|
| 804 | else: |
|---|
| 805 | return None |
|---|
| 806 | |
|---|
| 807 | def setModificationDeadline( self, newDL ): |
|---|
| 808 | """Sets a new deadline for modifications on the submitted abstracts. |
|---|
| 809 | """ |
|---|
| 810 | if newDL != None: |
|---|
| 811 | self._modifDeadline = datetime( newDL.year,newDL.month,newDL.day,23,59,59) |
|---|
| 812 | else: |
|---|
| 813 | self._modifDeadline = newDL |
|---|
| 814 | |
|---|
| 815 | def inModificationPeriod( self, date=None ): |
|---|
| 816 | """Tells whether is possible to modify a submitted abstract in a |
|---|
| 817 | certain date. |
|---|
| 818 | """ |
|---|
| 819 | if date is None: |
|---|
| 820 | date=nowutc() |
|---|
| 821 | if not self.getModificationDeadline(): |
|---|
| 822 | return True |
|---|
| 823 | return date <= self.getModificationDeadline() |
|---|
| 824 | |
|---|
| 825 | def getAnnouncement( self ): |
|---|
| 826 | #to be removed |
|---|
| 827 | try: |
|---|
| 828 | if self._announcement: |
|---|
| 829 | pass |
|---|
| 830 | except AttributeError, e: |
|---|
| 831 | self._announcement = "" |
|---|
| 832 | |
|---|
| 833 | return self._announcement |
|---|
| 834 | |
|---|
| 835 | def setAnnouncement( self, newAnnouncement ): |
|---|
| 836 | self._announcement = newAnnouncement.strip() |
|---|
| 837 | |
|---|
| 838 | ## def addContribType(self, type): |
|---|
| 839 | ## type = type.strip() |
|---|
| 840 | ## if type == "": |
|---|
| 841 | ## raise MaKaCError("Cannot add an empty contribution type") |
|---|
| 842 | ## self._contribTypes.append(type) |
|---|
| 843 | ## |
|---|
| 844 | ## def removeContribType(self, type): |
|---|
| 845 | ## if type in self._contribTypes: |
|---|
| 846 | ## self._contribTypes.remove(type) |
|---|
| 847 | ## |
|---|
| 848 | ## def getContribTypeList(self): |
|---|
| 849 | ## return self._contribTypes |
|---|
| 850 | |
|---|
| 851 | def _generateNewAbstractId( self ): |
|---|
| 852 | """Returns a new unique identifier for the current conference |
|---|
| 853 | contributions |
|---|
| 854 | """ |
|---|
| 855 | #instead of having a own counter, the abstract manager will request |
|---|
| 856 | # abstract ids to the conference which will ensure a unique id |
|---|
| 857 | # which will persist afterwards when an abstract is accepted |
|---|
| 858 | return str(self.getConference().genNewAbstractId()) |
|---|
| 859 | |
|---|
| 860 | def _getOldAbstractCounter(self): |
|---|
| 861 | return self.__abstractGenerator._getCount() |
|---|
| 862 | |
|---|
| 863 | def newAbstract( self, av, **data ): |
|---|
| 864 | """Creates a new abstract under this manager |
|---|
| 865 | """ |
|---|
| 866 | id = self._generateNewAbstractId() |
|---|
| 867 | a = Abstract( self, id, av, **data ) |
|---|
| 868 | self._abstracts[ id ] = a |
|---|
| 869 | for auth in a.getPrimaryAuthorList(): |
|---|
| 870 | self.indexAuthor(auth) |
|---|
| 871 | return a |
|---|
| 872 | |
|---|
| 873 | def addAbstract(self, abstract): |
|---|
| 874 | if abstract in self.getAbstractList(): |
|---|
| 875 | return |
|---|
| 876 | if isinstance(abstract.getCurrentStatus(),AbstractStatusWithdrawn): |
|---|
| 877 | raise MaKaCError( _("Cannot add an abstract which has been withdrawn"), ("Event")) |
|---|
| 878 | abstract._setOwner(self) |
|---|
| 879 | self._abstracts[abstract.getId()] = abstract |
|---|
| 880 | for auth in abstract.getPrimaryAuthorList(): |
|---|
| 881 | self.indexAuthor(auth) |
|---|
| 882 | |
|---|
| 883 | def removeAbstract( self, abstract ): |
|---|
| 884 | if self._abstracts.has_key( abstract.getId() ): |
|---|
| 885 | #for auth in abstract.getPrimaryAuthorList(): |
|---|
| 886 | # self.unindexAuthor(auth) |
|---|
| 887 | # * Remove dependencies with another abstracts: |
|---|
| 888 | # - If it's an accepted abstract-->remove abstract from contribution |
|---|
| 889 | if isinstance(abstract.getCurrentStatus(), AbstractStatusAccepted): |
|---|
| 890 | raise MaKaCError( _("Cannot remove an accepted abstract before removing the contribution linked to it")) |
|---|
| 891 | # If it's a withdrawn abstract-->remove abstract from contribution |
|---|
| 892 | if isinstance(abstract.getCurrentStatus(), AbstractStatusWithdrawn) and abstract.getContribution(): |
|---|
| 893 | raise MaKaCError( _("Cannot remove the abstract before removing the contribution linked to it")) |
|---|
| 894 | for abs in self._abstracts.values(): |
|---|
| 895 | if abs != abstract: |
|---|
| 896 | st = abs.getCurrentStatus() |
|---|
| 897 | if isinstance(st, AbstractStatusDuplicated): |
|---|
| 898 | #if the abstract to delete is the orginal in another "duplicated", change status to submitted |
|---|
| 899 | if st.getOriginal() == abstract: |
|---|
| 900 | abs.setCurrentStatus(AbstractStatusSubmitted(abs)) |
|---|
| 901 | elif isinstance(st, AbstractStatusMerged): |
|---|
| 902 | #if the abstract to delete is the target one in another "merged", change status to submitted |
|---|
| 903 | if st.getTargetAbstract() == abstract: |
|---|
| 904 | abs.setCurrentStatus(AbstractStatusSubmitted(abs)) |
|---|
| 905 | #unindex participations!!! |
|---|
| 906 | self.unregisterParticipation(abstract.getSubmitter()) |
|---|
| 907 | del self._abstracts[ abstract.getId() ] |
|---|
| 908 | abstract.delete() |
|---|
| 909 | |
|---|
| 910 | def recoverAbstract(self, abstract): |
|---|
| 911 | self.addAbstract(abstract) |
|---|
| 912 | abstract.recoverFromTrashCan() |
|---|
| 913 | def getAbstractList(self): |
|---|
| 914 | return self._abstracts.values() |
|---|
| 915 | |
|---|
| 916 | def getAbstractById(self, id): |
|---|
| 917 | return self._abstracts.get(str(id),None) |
|---|
| 918 | |
|---|
| 919 | def registerParticipation( self, p ): |
|---|
| 920 | self._participationIdx.index( p ) |
|---|
| 921 | |
|---|
| 922 | def unregisterParticipation( self, p ): |
|---|
| 923 | self._participationIdx.unindex( p ) |
|---|
| 924 | |
|---|
| 925 | def getAbstractListForAvatar( self, av ): |
|---|
| 926 | try: |
|---|
| 927 | if self._participationIdx: |
|---|
| 928 | pass |
|---|
| 929 | except AttributeError, e: |
|---|
| 930 | self._participationIdx = self._partipationIdx |
|---|
| 931 | self._partipationIdx = None |
|---|
| 932 | res = [] |
|---|
| 933 | for participation in self._participationIdx.getParticipationList( av ): |
|---|
| 934 | abstract = participation.getAbstract() |
|---|
| 935 | if abstract is not None and abstract.isSubmitter( av ): |
|---|
| 936 | if abstract not in res: |
|---|
| 937 | res.append( abstract ) |
|---|
| 938 | return res |
|---|
| 939 | |
|---|
| 940 | def getNotificationTplList(self): |
|---|
| 941 | try: |
|---|
| 942 | if self._notifTpls: |
|---|
| 943 | pass |
|---|
| 944 | except AttributeError: |
|---|
| 945 | self._notifTpls=IOBTree() |
|---|
| 946 | try: |
|---|
| 947 | if self._notifTplsOrder: |
|---|
| 948 | pass |
|---|
| 949 | except AttributeError: |
|---|
| 950 | self._notifTplsOrder=PersistentList() |
|---|
| 951 | for tpl in self._notifTpls.values(): |
|---|
| 952 | self._notifTplsOrder.append(tpl) |
|---|
| 953 | return self._notifTplsOrder |
|---|
| 954 | |
|---|
| 955 | def addNotificationTpl(self,tpl): |
|---|
| 956 | try: |
|---|
| 957 | if self._notifTpls: |
|---|
| 958 | pass |
|---|
| 959 | except AttributeError: |
|---|
| 960 | self._notifTpls=IOBTree() |
|---|
| 961 | try: |
|---|
| 962 | if self._notifTplsOrder: |
|---|
| 963 | pass |
|---|
| 964 | except AttributeError: |
|---|
| 965 | self._notifTplsOrder=PersistentList() |
|---|
| 966 | for tpl in self._notifTpls.values(): |
|---|
| 967 | self._notifTplsOrder.append(tpl) |
|---|
| 968 | try: |
|---|
| 969 | if self._notifTplsCounter: |
|---|
| 970 | pass |
|---|
| 971 | except AttributeError: |
|---|
| 972 | self._notifTplsCounter=Counter() |
|---|
| 973 | if tpl.getOwner()==self and self._notifTpls.has_key(tpl.getId()): |
|---|
| 974 | return |
|---|
| 975 | id = tpl.getId() |
|---|
| 976 | if id == "": |
|---|
| 977 | id=self._notifTplsCounter.newCount() |
|---|
| 978 | tpl.includeInOwner(self,id) |
|---|
| 979 | self._notifTpls[int(id)]=tpl |
|---|
| 980 | self._notifTplsOrder.append(tpl) |
|---|
| 981 | |
|---|
| 982 | def removeNotificationTpl(self,tpl): |
|---|
| 983 | try: |
|---|
| 984 | if self._notifTpls: |
|---|
| 985 | pass |
|---|
| 986 | except AttributeError: |
|---|
| 987 | self._notifTpls=IOBTree() |
|---|
| 988 | try: |
|---|
| 989 | if self._notifTplsOrder: |
|---|
| 990 | pass |
|---|
| 991 | except AttributeError: |
|---|
| 992 | self._notifTplsOrder=PersistentList() |
|---|
| 993 | for tpl in self._notifTpls.values(): |
|---|
| 994 | self._notifTplsOrder.append(tpl) |
|---|
| 995 | if tpl.getOwner()!=self or not self._notifTpls.has_key(int(tpl.getId())): |
|---|
| 996 | return |
|---|
| 997 | del self._notifTpls[int(tpl.getId())] |
|---|
| 998 | self._notifTplsOrder.remove(tpl) |
|---|
| 999 | tpl.includeInOwner(None,tpl.getId()) # We don't change the id for |
|---|
| 1000 | # recovery purposes. |
|---|
| 1001 | tpl.delete() |
|---|
| 1002 | |
|---|
| 1003 | def recoverNotificationTpl(self, tpl): |
|---|
| 1004 | self.addNotificationTpl(tpl) |
|---|
| 1005 | tpl.recover() |
|---|
| 1006 | |
|---|
| 1007 | def getNotificationTplById(self,id): |
|---|
| 1008 | try: |
|---|
| 1009 | if self._notifTpls: |
|---|
| 1010 | pass |
|---|
| 1011 | except AttributeError: |
|---|
| 1012 | self._notifTpls=IOBTree() |
|---|
| 1013 | return self._notifTpls.get(int(id),None) |
|---|
| 1014 | |
|---|
| 1015 | def getNotifTplForAbstract(self,abs): |
|---|
| 1016 | """ |
|---|
| 1017 | """ |
|---|
| 1018 | for tpl in self.getNotificationTplList(): |
|---|
| 1019 | if tpl.satisfies(abs): |
|---|
| 1020 | return tpl |
|---|
| 1021 | return None |
|---|
| 1022 | |
|---|
| 1023 | def moveUpNotifTpl(self,tpl): |
|---|
| 1024 | """ |
|---|
| 1025 | """ |
|---|
| 1026 | try: |
|---|
| 1027 | if self._notifTplsOrder: |
|---|
| 1028 | pass |
|---|
| 1029 | except AttributeError: |
|---|
| 1030 | self._notifTplsOrder=PersistentList() |
|---|
| 1031 | for tpl in self._notifTpls.values(): |
|---|
| 1032 | self._notifTplsOrder.append(tpl) |
|---|
| 1033 | if tpl not in self._notifTplsOrder: |
|---|
| 1034 | return |
|---|
| 1035 | idx=self._notifTplsOrder.index(tpl) |
|---|
| 1036 | if idx==0: |
|---|
| 1037 | return |
|---|
| 1038 | self._notifTplsOrder.remove(tpl) |
|---|
| 1039 | self._notifTplsOrder.insert(idx-1,tpl) |
|---|
| 1040 | |
|---|
| 1041 | |
|---|
| 1042 | def moveDownNotifTpl(self,tpl): |
|---|
| 1043 | """ |
|---|
| 1044 | """ |
|---|
| 1045 | try: |
|---|
| 1046 | if self._notifTplsOrder: |
|---|
| 1047 | pass |
|---|
| 1048 | except AttributeError: |
|---|
| 1049 | self._notifTplsOrder=PersistentList() |
|---|
| 1050 | for tpl in self._notifTpls.values(): |
|---|
| 1051 | self._notifTplsOrder.append(tpl) |
|---|
| 1052 | idx=self._notifTplsOrder.index(tpl) |
|---|
| 1053 | if idx==len(self._notifTplsOrder): |
|---|
| 1054 | return |
|---|
| 1055 | self._notifTplsOrder.remove(tpl) |
|---|
| 1056 | self._notifTplsOrder.insert(idx+1,tpl) |
|---|
| 1057 | |
|---|
| 1058 | def indexAuthor(self,auth): |
|---|
| 1059 | a=auth.getAbstract() |
|---|
| 1060 | if a.isPrimaryAuthor(auth): |
|---|
| 1061 | self._getPrimAuthIndex().index(auth) |
|---|
| 1062 | |
|---|
| 1063 | def unindexAuthor(self,auth): |
|---|
| 1064 | a=auth.getAbstract() |
|---|
| 1065 | if a.isPrimaryAuthor(auth): |
|---|
| 1066 | self._getPrimAuthIndex().unindex(auth) |
|---|
| 1067 | |
|---|
| 1068 | def _getPrimAuthIndex(self): |
|---|
| 1069 | try: |
|---|
| 1070 | if self._primAuthIdx: |
|---|
| 1071 | pass |
|---|
| 1072 | except AttributeError: |
|---|
| 1073 | self._primAuthIdx=_PrimAuthIdx(self) |
|---|
| 1074 | return self._primAuthIdx |
|---|
| 1075 | |
|---|
| 1076 | def getAbstractsMatchingAuth(self,query,onlyPrimary=True): |
|---|
| 1077 | if str(query).strip()=="": |
|---|
| 1078 | return self.getAbstractList() |
|---|
| 1079 | res=self._getPrimAuthIndex().match(query) |
|---|
| 1080 | return [self.getAbstractById(id) for id in res] |
|---|
| 1081 | |
|---|
| 1082 | def addAbstractField(self, id, name, caption, maxLength=0, isMandatory=False, fieldType="textarea"): |
|---|
| 1083 | return self.getAbstractFieldsMgr().addField(id, name, caption, maxLength, isMandatory, fieldType) |
|---|
| 1084 | |
|---|
| 1085 | def removeAbstractField(self, id): |
|---|
| 1086 | self.getAbstractFieldsMgr().removeField(id) |
|---|
| 1087 | |
|---|
| 1088 | def hasAnyEnabledAbstractField( self ): |
|---|
| 1089 | return self.getAbstractFieldsMgr().hasAnyActiveField() |
|---|
| 1090 | |
|---|
| 1091 | def hasEnabledAbstractField(self, key): |
|---|
| 1092 | return self.getAbstractFieldsMgr().hasActiveField(key) |
|---|
| 1093 | |
|---|
| 1094 | def enableAbstractField(self, abstractField): |
|---|
| 1095 | self.getAbstractFieldsMgr().enableField(abstractField) |
|---|
| 1096 | self.notifyModification() |
|---|
| 1097 | |
|---|
| 1098 | def disableAbstractField(self, abstractField): |
|---|
| 1099 | self.getAbstractFieldsMgr().disableField(abstractField) |
|---|
| 1100 | self.notifyModification() |
|---|
| 1101 | |
|---|
| 1102 | def moveAbsFieldUp(self, id): |
|---|
| 1103 | self.getAbstractFieldsMgr().moveAbsFieldUp(id) |
|---|
| 1104 | self.notifyModification() |
|---|
| 1105 | |
|---|
| 1106 | def moveAbsFieldDown(self, id): |
|---|
| 1107 | self.getAbstractFieldsMgr().moveAbsFieldDown(id) |
|---|
| 1108 | self.notifyModification() |
|---|
| 1109 | |
|---|
| 1110 | def getSubmissionNotification(self): |
|---|
| 1111 | try: |
|---|
| 1112 | if self._submissionNotification: |
|---|
| 1113 | pass |
|---|
| 1114 | except AttributeError, e: |
|---|
| 1115 | self._submissionNotification=SubmissionNotification() |
|---|
| 1116 | return self._submissionNotification |
|---|
| 1117 | |
|---|
| 1118 | def setSubmissionNotification(self, sn): |
|---|
| 1119 | self._submissionNotification=sn |
|---|
| 1120 | |
|---|
| 1121 | def recalculateAbstractsRating(self, scaleLower, scaleHigher): |
|---|
| 1122 | ''' recalculate the values of the rating for all the abstracts in the conference ''' |
|---|
| 1123 | for abs in self.getAbstractList(): |
|---|
| 1124 | abs.updateRating((scaleLower, scaleHigher)) |
|---|
| 1125 | |
|---|
| 1126 | def removeAnswersOfQuestion(self, questionId): |
|---|
| 1127 | ''' Remove a question results for each abstract ''' |
|---|
| 1128 | for abs in self.getAbstractList(): |
|---|
| 1129 | abs.removeAnswersOfQuestion(questionId) |
|---|
| 1130 | |
|---|
| 1131 | def notifyModification(self): |
|---|
| 1132 | self._p_changed=1 |
|---|
| 1133 | |
|---|
| 1134 | class SubmissionNotification(Persistent): |
|---|
| 1135 | |
|---|
| 1136 | def __init__(self): |
|---|
| 1137 | self._toList = PersistentList() |
|---|
| 1138 | self._ccList = PersistentList() |
|---|
| 1139 | |
|---|
| 1140 | def hasDestination(self): |
|---|
| 1141 | return self._toList!=[] or self._toList!=[] |
|---|
| 1142 | |
|---|
| 1143 | def getToList(self): |
|---|
| 1144 | return self._toList |
|---|
| 1145 | |
|---|
| 1146 | def setToList(self, tl): |
|---|
| 1147 | self._toList = tl |
|---|
| 1148 | |
|---|
| 1149 | def addToList(self, to): |
|---|
| 1150 | self._toList.append(to) |
|---|
| 1151 | |
|---|
| 1152 | def clearToList(self): |
|---|
| 1153 | self._toList = PersistentList() |
|---|
| 1154 | |
|---|
| 1155 | def getCCList(self): |
|---|
| 1156 | return self._ccList |
|---|
| 1157 | |
|---|
| 1158 | def setCCList(self, cl): |
|---|
| 1159 | self._ccList = cl |
|---|
| 1160 | |
|---|
| 1161 | def addCCList(self, cc): |
|---|
| 1162 | self._ccList.append(cc) |
|---|
| 1163 | |
|---|
| 1164 | def clearCCList(self): |
|---|
| 1165 | self._ccList = PersistentList() |
|---|
| 1166 | |
|---|
| 1167 | def clone(self): |
|---|
| 1168 | nsn=SubmissionNotification() |
|---|
| 1169 | for i in self.getToList(): |
|---|
| 1170 | nsn.addToList(i) |
|---|
| 1171 | for i in self.getCCList(): |
|---|
| 1172 | nsn.addCCList(i) |
|---|
| 1173 | return nsn |
|---|
| 1174 | |
|---|
| 1175 | class Comment(Persistent): |
|---|
| 1176 | |
|---|
| 1177 | def __init__(self,res,content=""): |
|---|
| 1178 | self._abstract=None |
|---|
| 1179 | self._id="" |
|---|
| 1180 | self._responsible=res |
|---|
| 1181 | self._content="" |
|---|
| 1182 | self._creationDate=nowutc() |
|---|
| 1183 | self._modificationDate=nowutc() |
|---|
| 1184 | |
|---|
| 1185 | def getLocator(self): |
|---|
| 1186 | loc=self._abstract.getLocator() |
|---|
| 1187 | loc["intCommentId"]=self._id |
|---|
| 1188 | return loc |
|---|
| 1189 | |
|---|
| 1190 | def includeInAbstract(self,abstract,id): |
|---|
| 1191 | self._abstract=abstract |
|---|
| 1192 | self._id=id |
|---|
| 1193 | |
|---|
| 1194 | def delete(self): |
|---|
| 1195 | self._abstract=None |
|---|
| 1196 | TrashCanManager().add(self) |
|---|
| 1197 | |
|---|
| 1198 | def recover(self): |
|---|
| 1199 | TrashCanManager().remove(self) |
|---|
| 1200 | |
|---|
| 1201 | def _notifyModification(self, dt=None): |
|---|
| 1202 | if dt: |
|---|
| 1203 | self._modificationDate = dt |
|---|
| 1204 | else: |
|---|
| 1205 | self._modificationDate=nowutc() |
|---|
| 1206 | |
|---|
| 1207 | def getResponsible(self): |
|---|
| 1208 | return self._responsible |
|---|
| 1209 | |
|---|
| 1210 | def getAbstract(self): |
|---|
| 1211 | return self._abstract |
|---|
| 1212 | |
|---|
| 1213 | def getId(self): |
|---|
| 1214 | return self._id |
|---|
| 1215 | |
|---|
| 1216 | def getContent(self): |
|---|
| 1217 | return self._content |
|---|
| 1218 | |
|---|
| 1219 | def setContent(self, newContent): |
|---|
| 1220 | self._content=newContent |
|---|
| 1221 | self._notifyModification() |
|---|
| 1222 | |
|---|
| 1223 | def getCreationDate(self): |
|---|
| 1224 | return self._creationDate |
|---|
| 1225 | |
|---|
| 1226 | def getModificationDate(self): |
|---|
| 1227 | return self._modificationDate |
|---|
| 1228 | |
|---|
| 1229 | def canModify(self,aw): |
|---|
| 1230 | return self.canUserModify(aw.getUser()) |
|---|
| 1231 | |
|---|
| 1232 | def canUserModify(self,user): |
|---|
| 1233 | abstract=self.getAbstract() |
|---|
| 1234 | conf=abstract.getConference() |
|---|
| 1235 | return self.getResponsible()==user and \ |
|---|
| 1236 | (abstract.canUserModify(user) or \ |
|---|
| 1237 | len(conf.getConference().getCoordinatedTracks(user))>0) |
|---|
| 1238 | |
|---|
| 1239 | class Abstract(Persistent): |
|---|
| 1240 | |
|---|
| 1241 | def __init__(self, owner, id, submitter, **abstractData): |
|---|
| 1242 | self._setOwner( owner ) |
|---|
| 1243 | self._setId( id ) |
|---|
| 1244 | self._title = "" |
|---|
| 1245 | self._fields = {} |
|---|
| 1246 | self._authorGen = Counter() |
|---|
| 1247 | self._authors = OOBTree() |
|---|
| 1248 | self._primaryAuthors = PersistentList() |
|---|
| 1249 | self._coAuthors = PersistentList() |
|---|
| 1250 | self._speakers = PersistentList() |
|---|
| 1251 | self._tracks = OOBTree() |
|---|
| 1252 | self._contribTypes = PersistentList( [""] ) |
|---|
| 1253 | self._setSubmissionDate( nowutc() ) |
|---|
| 1254 | self._modificationDate = nowutc() |
|---|
| 1255 | self._currentStatus = AbstractStatusSubmitted( self ) |
|---|
| 1256 | self._trackAcceptances = OOBTree() |
|---|
| 1257 | self._trackRejections = OOBTree() |
|---|
| 1258 | self._trackReallocations = OOBTree() |
|---|
| 1259 | self._trackJudgementsHistorical={} |
|---|
| 1260 | self._comments = "" |
|---|
| 1261 | self._contribution = None |
|---|
| 1262 | self._intCommentGen=Counter() |
|---|
| 1263 | self._intComments=PersistentList() |
|---|
| 1264 | self._mergeFromList = PersistentList() |
|---|
| 1265 | self._notifLog=NotificationLog(self) |
|---|
| 1266 | self._submitter=None |
|---|
| 1267 | self._setSubmitter( submitter ) |
|---|
| 1268 | self._rating = None # It needs to be none to avoid the case of having the same value as the lowest value in the judgement |
|---|
| 1269 | |
|---|
| 1270 | def clone(self, conference, abstractId): |
|---|
| 1271 | |
|---|
| 1272 | # abstractId - internal in abstract manager of the conference |
|---|
| 1273 | abs = Abstract(conference.getAbstractMgr(), abstractId, self.getSubmitter().getAvatar()) |
|---|
| 1274 | abs.setTitle(self.getTitle()) |
|---|
| 1275 | for key in self.getFields().keys(): |
|---|
| 1276 | abs.setField(key,self.getField(key)) |
|---|
| 1277 | abs.setComments(self.getComments()) |
|---|
| 1278 | |
|---|
| 1279 | abs._setSubmissionDate(self.getSubmissionDate()) |
|---|
| 1280 | abs._modificationDate = self.getModificationDate() |
|---|
| 1281 | |
|---|
| 1282 | # Cloning of primary- and coauthors |
|---|
| 1283 | # if an author is also a speaker, an appropriate object will be |
|---|
| 1284 | # appended also to the speaker list |
|---|
| 1285 | for pa in self.getPrimaryAuthorList() : |
|---|
| 1286 | npa = abs.newPrimaryAuthor(**(pa.getData())) |
|---|
| 1287 | if self.isSpeaker(pa) : |
|---|
| 1288 | abs.addSpeaker(npa) |
|---|
| 1289 | for ca in self.getCoAuthorList() : |
|---|
| 1290 | nca = abs.newCoAuthor(**(ca.getData())) |
|---|
| 1291 | if self.isSpeaker(ca) : |
|---|
| 1292 | abs.addSpeaker(nca) |
|---|
| 1293 | |
|---|
| 1294 | # Cloning of speakers |
|---|
| 1295 | # only those, who are not authors : |
|---|
| 1296 | for sp in self.getSpeakerList() : |
|---|
| 1297 | if not self.isAuthor(sp) : |
|---|
| 1298 | abs.addSpeaker(sp.clone()) |
|---|
| 1299 | |
|---|
| 1300 | abs.setSubmitter(self.getSubmitter().getAvatar()) |
|---|
| 1301 | |
|---|
| 1302 | if self.getContribType() is not None : |
|---|
| 1303 | for ct in conference.getContribTypeList() : |
|---|
| 1304 | if self.getContribType().getName() == ct.getName() : |
|---|
| 1305 | abs.setContribType(ct) |
|---|
| 1306 | break |
|---|
| 1307 | else : |
|---|
| 1308 | abs.setContribType(None) |
|---|
| 1309 | |
|---|
| 1310 | # the track, to which the abstract belongs to |
|---|
| 1311 | # legacy list implementation |
|---|
| 1312 | track = None |
|---|
| 1313 | for tr in self.getTrackList() : |
|---|
| 1314 | for newtrack in conference.getTrackList(): |
|---|
| 1315 | if newtrack.getTitle() == tr.getTitle() : |
|---|
| 1316 | abs.addTrack(newtrack) |
|---|
| 1317 | track = newtrack |
|---|
| 1318 | |
|---|
| 1319 | # overall abstract status (accepted / rejected) |
|---|
| 1320 | abs._currentStatus = self._currentStatus.clone(track) |
|---|
| 1321 | |
|---|
| 1322 | for ta in self.getTrackAcceptanceList() : |
|---|
| 1323 | for newtrack in conference.getTrackList(): |
|---|
| 1324 | if newtrack.getTitle() == ta.getTrack().getTitle() : |
|---|
| 1325 | newta = ta.clone(newtrack) |
|---|
| 1326 | abs._addTrackAcceptance(newta) |
|---|
| 1327 | abs._addTrackJudgementToHistorical(newta) |
|---|
| 1328 | |
|---|
| 1329 | for trj in self._trackRejections.values() : |
|---|
| 1330 | for newtrack in conference.getTrackList(): |
|---|
| 1331 | if newtrack.getTitle() == trj.getTrack().getTitle() : |
|---|
| 1332 | newtrj = trj.clone(newtrack) |
|---|
| 1333 | abs._addTrackRejection(newtrj) |
|---|
| 1334 | abs._addTrackJudgementToHistorical(newtrj) |
|---|
| 1335 | |
|---|
| 1336 | for trl in self._trackReallocations.values() : |
|---|
| 1337 | for newtrack in conference.getTrackList(): |
|---|
| 1338 | if newtrack.getTitle() == trl.getTrack().getTitle() : |
|---|
| 1339 | newtrl = trl.clone(newtrack) |
|---|
| 1340 | abs._addTrackReallocation(newtrl) |
|---|
| 1341 | abs._addTrackJudgementToHistorical(newtrl) |
|---|
| 1342 | |
|---|
| 1343 | return abs |
|---|
| 1344 | |
|---|
| 1345 | def getUniqueId( self ): |
|---|
| 1346 | """returns (string) the unique identifier of the item""" |
|---|
| 1347 | """used only in the web session access key table""" |
|---|
| 1348 | """it is the same as the conference since only the conf can""" |
|---|
| 1349 | """be protected with an access key""" |
|---|
| 1350 | return self.getConference().getUniqueId() |
|---|
| 1351 | |
|---|
| 1352 | def getMergeFromList(self): |
|---|
| 1353 | try: |
|---|
| 1354 | return self._mergeFromList |
|---|
| 1355 | except AttributeError: |
|---|
| 1356 | self._mergeFromList = PersistentList() |
|---|
| 1357 | return self._mergeFromList |
|---|
| 1358 | |
|---|
| 1359 | def addMergeFromAbstract(self, abstract): |
|---|
| 1360 | try: |
|---|
| 1361 | if self._mergeFromList: |
|---|
| 1362 | pass |
|---|
| 1363 | except AttributeError: |
|---|
| 1364 | self._mergeFromList = PersistentList() |
|---|
| 1365 | self._mergeFromList.append(abstract) |
|---|
| 1366 | |
|---|
| 1367 | def removeMergeFromAbstract(self, abstract): |
|---|
| 1368 | try: |
|---|
| 1369 | if self._mergeFromList: |
|---|
| 1370 | pass |
|---|
| 1371 | except AttributeError: |
|---|
| 1372 | self._mergeFromList = PersistentList() |
|---|
| 1373 | |
|---|
| 1374 | if abstract in self._mergeFromList: |
|---|
| 1375 | self._mergeFromList.remove(abstract) |
|---|
| 1376 | |
|---|
| 1377 | def getComments(self): |
|---|
| 1378 | try: |
|---|
| 1379 | return self._comments |
|---|
| 1380 | except AttributeError: |
|---|
| 1381 | self._comments = "" |
|---|
| 1382 | return self._comments |
|---|
| 1383 | |
|---|
| 1384 | def setComments(self, comments): |
|---|
| 1385 | self._comments = comments |
|---|
| 1386 | |
|---|
| 1387 | def _setOwner( self, owner ): |
|---|
| 1388 | self._owner = owner |
|---|
| 1389 | |
|---|
| 1390 | def getOwner( self ): |
|---|
| 1391 | return self._owner |
|---|
| 1392 | |
|---|
| 1393 | def _setId( self, id ): |
|---|
| 1394 | self._id = str( id ) |
|---|
| 1395 | |
|---|
| 1396 | def getId(self): |
|---|
| 1397 | return self._id |
|---|
| 1398 | |
|---|
| 1399 | def _setSubmissionDate( self, newDate ): |
|---|
| 1400 | self._submissionDate = newDate |
|---|
| 1401 | |
|---|
| 1402 | def _notifyModification( self, dt=None ): |
|---|
| 1403 | if dt: |
|---|
| 1404 | self._modificationDate = dt |
|---|
| 1405 | else: |
|---|
| 1406 | self._modificationDate = nowutc() |
|---|
| 1407 | |
|---|
| 1408 | def getModificationDate( self ): |
|---|
| 1409 | return self._modificationDate |
|---|
| 1410 | |
|---|
| 1411 | def _setSubmitter( self, av ): |
|---|
| 1412 | if not av: |
|---|
| 1413 | raise MaKaCError( _("An abstract must have a submitter")) |
|---|
| 1414 | if self._submitter: |
|---|
| 1415 | self.getOwner().unregisterParticipation( self._submitter ) |
|---|
| 1416 | self._submitter.getUser().unlinkTo(self, "submitter") |
|---|
| 1417 | self._submitter.delete() |
|---|
| 1418 | self._submitter=Submitter( self, av ) |
|---|
| 1419 | av.linkTo(self, "submitter") |
|---|
| 1420 | self.getOwner().registerParticipation( self._submitter ) |
|---|
| 1421 | self._notifyModification() |
|---|
| 1422 | |
|---|
| 1423 | def recoverSubmitter(self, subm): |
|---|
| 1424 | if not subm: |
|---|
| 1425 | raise MaKaCError( _("An abstract must have a submitter")) |
|---|
| 1426 | if self._submitter: |
|---|
| 1427 | self.getOwner().unregisterParticipation( self._submitter ) |
|---|
| 1428 | self._submitter.delete() |
|---|
| 1429 | self._submitter = subm |
|---|
| 1430 | self._submitter.setAbstract(self) |
|---|
| 1431 | self.getOwner().registerParticipation( self._submitter ) |
|---|
| 1432 | subm.recover() |
|---|
| 1433 | self._notifyModification() |
|---|
| 1434 | |
|---|
| 1435 | def setSubmitter( self, av ): |
|---|
| 1436 | self._setSubmitter(av) |
|---|
| 1437 | |
|---|
| 1438 | def getSubmitter( self ): |
|---|
| 1439 | return self._submitter |
|---|
| 1440 | |
|---|
| 1441 | def isSubmitter( self, av ): |
|---|
| 1442 | return self.getSubmitter().representsUser( av ) |
|---|
| 1443 | |
|---|
| 1444 | def setTitle(self, title): |
|---|
| 1445 | self._title = title.strip() |
|---|
| 1446 | self._notifyModification() |
|---|
| 1447 | |
|---|
| 1448 | def getTitle(self): |
|---|
| 1449 | return self._title |
|---|
| 1450 | |
|---|
| 1451 | def getFields( self ): |
|---|
| 1452 | try: |
|---|
| 1453 | return self._fields |
|---|
| 1454 | except: |
|---|
| 1455 | self._fields = {} |
|---|
| 1456 | try: |
|---|
| 1457 | if self._content != "": |
|---|
| 1458 | self._fields["content"] = self._content |
|---|
| 1459 | del self._content |
|---|
| 1460 | except: |
|---|
| 1461 | pass |
|---|
| 1462 | try: |
|---|
| 1463 | if self._summary != "": |
|---|
| 1464 | self._fields["summary"] = self._summary |
|---|
| 1465 | del self._summary |
|---|
| 1466 | except: |
|---|
| 1467 | pass |
|---|
| 1468 | return self._fields |
|---|
| 1469 | |
|---|
| 1470 | def removeField(self, field): |
|---|
| 1471 | if self.getFields().has_key(field): |
|---|
| 1472 | del self.getFields()[field] |
|---|
| 1473 | self._notifyModification() |
|---|
| 1474 | |
|---|
| 1475 | def setField( self, field, value ): |
|---|
| 1476 | try: |
|---|
| 1477 | self.getFields()[field] = value |
|---|
| 1478 | self._notifyModification() |
|---|
| 1479 | except: |
|---|
| 1480 | pass |
|---|
| 1481 | |
|---|
| 1482 | def getField( self, field): |
|---|
| 1483 | try: |
|---|
| 1484 | if self._content != "": |
|---|
| 1485 | self._fields["content"] = self._content |
|---|
| 1486 | del self._content |
|---|
| 1487 | except: |
|---|
| 1488 | pass |
|---|
| 1489 | try: |
|---|
| 1490 | if self._summary != "": |
|---|
| 1491 | self._fields["summary"] = self._summary |
|---|
| 1492 | del self._summary |
|---|
| 1493 | except: |
|---|
| 1494 | pass |
|---|
| 1495 | if self.getFields().has_key(field): |
|---|
| 1496 | return self.getFields()[field] |
|---|
| 1497 | else: |
|---|
| 1498 | return "" |
|---|
| 1499 | |
|---|
| 1500 | def getSubmissionDate( self ): |
|---|
| 1501 | try: |
|---|
| 1502 | if self._submissionDate: |
|---|
| 1503 | pass |
|---|
| 1504 | except AttributeError: |
|---|
| 1505 | self._submissionDate=nowutc() |
|---|
| 1506 | return self._submissionDate |
|---|
| 1507 | |
|---|
| 1508 | def getConference( self ): |
|---|
| 1509 | return self.getOwner().getOwner() |
|---|
| 1510 | |
|---|
| 1511 | def _newAuthor( self, **data ): |
|---|
| 1512 | author = Author( self, **data ) |
|---|
| 1513 | author.setId( self._authorGen.newCount() ) |
|---|
| 1514 | self._authors[ author.getId() ] = author |
|---|
| 1515 | return author |
|---|
| 1516 | |
|---|
| 1517 | def _removeAuthor(self,part): |
|---|
| 1518 | if not self.isAuthor(part): |
|---|
| 1519 | return |
|---|
| 1520 | part.delete() |
|---|
| 1521 | del self._authors[part.getId()] |
|---|
| 1522 | |
|---|
| 1523 | def isAuthor( self, part ): |
|---|
| 1524 | return self._authors.has_key( part.getId() ) |
|---|
| 1525 | |
|---|
| 1526 | def getAuthorList( self ): |
|---|
| 1527 | return self._authors.values() |
|---|
| 1528 | |
|---|
| 1529 | def getAuthorById(self, id): |
|---|
| 1530 | return self._authors.get(str(id), None) |
|---|
| 1531 | |
|---|
| 1532 | def clearAuthors( self ): |
|---|
| 1533 | self.clearPrimaryAuthors() |
|---|
| 1534 | self.clearCoAuthors() |
|---|
| 1535 | self._notifyModification() |
|---|
| 1536 | |
|---|
| 1537 | def newPrimaryAuthor(self,**data): |
|---|
| 1538 | auth=self._newAuthor(**data) |
|---|
| 1539 | self._addPrimaryAuthor(auth) |
|---|
| 1540 | self._notifyModification() |
|---|
| 1541 | return auth |
|---|
| 1542 | |
|---|
| 1543 | def isPrimaryAuthor( self, part ): |
|---|
| 1544 | return part in self._primaryAuthors |
|---|
| 1545 | |
|---|
| 1546 | def getPrimaryAuthorList( self ): |
|---|
| 1547 | return self._primaryAuthors |
|---|
| 1548 | #XXX: I keep it for compatibility but it should be removed |
|---|
| 1549 | getPrimaryAuthorsList = getPrimaryAuthorList |
|---|
| 1550 | |
|---|
| 1551 | def clearPrimaryAuthors(self): |
|---|
| 1552 | while len(self._primaryAuthors)>0: |
|---|
| 1553 | self._removePrimaryAuthor(self._primaryAuthors[0]) |
|---|
| 1554 | self._notifyModification() |
|---|
| 1555 | |
|---|
| 1556 | def _addPrimaryAuthor( self, part ): |
|---|
| 1557 | if not self.isAuthor( part ): |
|---|
| 1558 | raise MaKaCError( _("The participation you want to set as primary author is not an author of the abstract")) |
|---|
| 1559 | if part in self._primaryAuthors: |
|---|
| 1560 | return |
|---|
| 1561 | self._primaryAuthors.append( part ) |
|---|
| 1562 | self.getOwner().indexAuthor(part) |
|---|
| 1563 | |
|---|
| 1564 | def _removePrimaryAuthor(self,part): |
|---|
| 1565 | if not self.isPrimaryAuthor(part): |
|---|
| 1566 | return |
|---|
| 1567 | if self.isSpeaker(part): |
|---|
| 1568 | self.removeSpeaker(part) |
|---|
| 1569 | self.getOwner().unindexAuthor(part) |
|---|
| 1570 | self._primaryAuthors.remove(part) |
|---|
| 1571 | self._removeAuthor(part) |
|---|
| 1572 | |
|---|
| 1573 | def recoverPrimaryAuthor(self, auth): |
|---|
| 1574 | self._authors[ auth.getId() ] = auth |
|---|
| 1575 | auth.setAbstract(self) |
|---|
| 1576 | self._addPrimaryAuthor(auth) |
|---|
| 1577 | auth.recover() |
|---|
| 1578 | self._notifyModification() |
|---|
| 1579 | |
|---|
| 1580 | def newCoAuthor(self,**data): |
|---|
| 1581 | auth=self._newAuthor(**data) |
|---|
| 1582 | self._addCoAuthor(auth) |
|---|
| 1583 | self._notifyModification() |
|---|
| 1584 | return auth |
|---|
| 1585 | |
|---|
| 1586 | def _comp_CoAuthors(self): |
|---|
| 1587 | try: |
|---|
| 1588 | if self._coAuthors!=None: |
|---|
| 1589 | return |
|---|
| 1590 | except AttributeError: |
|---|
| 1591 | self._coAuthors=PersistentList() |
|---|
| 1592 | for auth in self._authors.values(): |
|---|
| 1593 | if not self.isPrimaryAuthor(auth): |
|---|
| 1594 | self._addCoAuthor(auth) |
|---|
| 1595 | |
|---|
| 1596 | def isCoAuthor( self, part ): |
|---|
| 1597 | self._comp_CoAuthors() |
|---|
| 1598 | return part in self._coAuthors |
|---|
| 1599 | |
|---|
| 1600 | def getCoAuthorList( self ): |
|---|
| 1601 | self._comp_CoAuthors() |
|---|
| 1602 | return self._coAuthors |
|---|
| 1603 | |
|---|
| 1604 | def clearCoAuthors(self): |
|---|
| 1605 | while len(self._coAuthors)>0: |
|---|
| 1606 | self._removeCoAuthor(self._coAuthors[0]) |
|---|
| 1607 | self._notifyModification() |
|---|
| 1608 | |
|---|
| 1609 | def _addCoAuthor( self, part ): |
|---|
| 1610 | self._comp_CoAuthors() |
|---|
| 1611 | if not self.isAuthor( part ): |
|---|
| 1612 | raise MaKaCError( _("The participation you want to set as primary author is not an author of the abstract")) |
|---|
| 1613 | if part in self._coAuthors: |
|---|
| 1614 | return |
|---|
| 1615 | self._coAuthors.append( part ) |
|---|
| 1616 | |
|---|
| 1617 | def _removeCoAuthor(self,part): |
|---|
| 1618 | if not self.isCoAuthor(part): |
|---|
| 1619 | return |
|---|
| 1620 | if self.isSpeaker(part): |
|---|
| 1621 | self.removeSpeaker(part) |
|---|
| 1622 | self._coAuthors.remove(part) |
|---|
| 1623 | self._removeAuthor(part) |
|---|
| 1624 | |
|---|
| 1625 | def recoverCoAuthor(self, auth): |
|---|
| 1626 | self._authors[ auth.getId() ] = auth |
|---|
| 1627 | auth.setAbstract(self) |
|---|
| 1628 | self._addCoAuthor(auth) |
|---|
| 1629 | auth.recover() |
|---|
| 1630 | self._notifyModification() |
|---|
| 1631 | |
|---|
| 1632 | def addSpeaker( self, part ): |
|---|
| 1633 | if not self.isAuthor( part ): |
|---|
| 1634 | raise MaKaCError( _("The participation you want to set as speaker is not an author of the abstract")) |
|---|
| 1635 | if part in self._speakers: |
|---|
| 1636 | return |
|---|
| 1637 | self._speakers.append( part ) |
|---|
| 1638 | self._notifyModification() |
|---|
| 1639 | |
|---|
| 1640 | def removeSpeaker(self,part): |
|---|
| 1641 | if part not in self._speakers: |
|---|
| 1642 | return |
|---|
| 1643 | self._speakers.remove(part) |
|---|
| 1644 | |
|---|
| 1645 | def clearSpeakers( self ): |
|---|
| 1646 | while len(self.getSpeakerList()) > 0: |
|---|
| 1647 | self.removeSpeaker(self.getSpeakerList()[0]) |
|---|
| 1648 | self._speakers = PersistentList() |
|---|
| 1649 | |
|---|
| 1650 | def getSpeakerList( self ): |
|---|
| 1651 | return self._speakers |
|---|
| 1652 | |
|---|
| 1653 | def isSpeaker( self, part ): |
|---|
| 1654 | return part in self._speakers |
|---|
| 1655 | |
|---|
| 1656 | def setContribType( self, contribType ): |
|---|
| 1657 | self._contribTypes[0] = contribType |
|---|
| 1658 | self._notifyModification() |
|---|
| 1659 | |
|---|
| 1660 | def getContribType( self ): |
|---|
| 1661 | return self._contribTypes[0] |
|---|
| 1662 | |
|---|
| 1663 | |
|---|
| 1664 | def _addTrack( self, track ): |
|---|
| 1665 | """Adds the specified track to the suggested track list. Any |
|---|
| 1666 | verification must be done by the caller. |
|---|
| 1667 | """ |
|---|
| 1668 | self._tracks[ track.getId() ] = track |
|---|
| 1669 | track.addAbstract( self ) |
|---|
| 1670 | self._notifyModification() |
|---|
| 1671 | |
|---|
| 1672 | def addTrack( self, track ): |
|---|
| 1673 | self._changeTracksImpl() |
|---|
| 1674 | if not self._tracks.has_key( track.getId() ): |
|---|
| 1675 | self._addTrack( track ) |
|---|
| 1676 | self.getCurrentStatus().update() |
|---|
| 1677 | |
|---|
| 1678 | def _removeTrack( self, track ): |
|---|
| 1679 | """Removes the specified track from the track list. Any verification |
|---|
| 1680 | must be done by the caller. |
|---|
| 1681 | """ |
|---|
| 1682 | del self._tracks[ track.getId() ] |
|---|
| 1683 | track.removeAbstract( self ) |
|---|
| 1684 | self._notifyModification() |
|---|
| 1685 | |
|---|
| 1686 | def removeTrack( self, track ): |
|---|
| 1687 | if self._tracks.has_key( track.getId() ): |
|---|
| 1688 | self._removeTrack( track ) |
|---|
| 1689 | self.getCurrentStatus().update() |
|---|
| 1690 | if isinstance(self.getCurrentStatus(), AbstractStatusAccepted): |
|---|
| 1691 | self.getCurrentStatus()._setTrack(None) |
|---|
| 1692 | |
|---|
| 1693 | def _changeTracksImpl( self ): |
|---|
| 1694 | if self._tracks.__class__ != OOBTree: |
|---|
| 1695 | oldTrackList = self._tracks |
|---|
| 1696 | self._tracks = OOBTree() |
|---|
| 1697 | for track in oldTrackList: |
|---|
| 1698 | self._addTrack( track ) |
|---|
| 1699 | self.getCurrentStatus().update() |
|---|
| 1700 | |
|---|
| 1701 | def getTrackList( self ): |
|---|
| 1702 | self._changeTracksImpl() |
|---|
| 1703 | |
|---|
| 1704 | return self._tracks.values() |
|---|
| 1705 | |
|---|
| 1706 | def hasTrack( self, track ): |
|---|
| 1707 | self._changeTracksImpl() |
|---|
| 1708 | |
|---|
| 1709 | return self._tracks.has_key( track.getId() ) |
|---|
| 1710 | |
|---|
| 1711 | def getTrackListSorted( self ): |
|---|
| 1712 | self._changeTracksImpl() |
|---|
| 1713 | return self.getConference().sortTrackList( self._tracks.values() ) |
|---|
| 1714 | |
|---|
| 1715 | def clearTracks( self ): |
|---|
| 1716 | self._changeTracksImpl() |
|---|
| 1717 | |
|---|
| 1718 | while len(self.getTrackList())>0: |
|---|
| 1719 | track = self.getTrackList()[0] |
|---|
| 1720 | self._removeTrack( track ) |
|---|
| 1721 | self.getCurrentStatus().update() |
|---|
| 1722 | |
|---|
| 1723 | def setTracks( self, trackList ): |
|---|
| 1724 | """Set the suggested track classification of the current abstract to |
|---|
| 1725 | the specified list |
|---|
| 1726 | """ |
|---|
| 1727 | #We need to do it in 2 steps otherwise the list over which we are |
|---|
| 1728 | # iterating gets modified |
|---|
| 1729 | toBeRemoved = [] |
|---|
| 1730 | toBeAdded = copy( trackList ) |
|---|
| 1731 | for track in self.getTrackList(): |
|---|
| 1732 | if track not in trackList: |
|---|
| 1733 | toBeRemoved.append( track ) |
|---|
| 1734 | else: |
|---|
| 1735 | toBeAdded.remove( track ) |
|---|
| 1736 | for track in toBeRemoved: |
|---|
| 1737 | self._removeTrack( track ) |
|---|
| 1738 | for track in toBeAdded: |
|---|
| 1739 | self._addTrack( track ) |
|---|
| 1740 | self.getCurrentStatus().update() |
|---|
| 1741 | |
|---|
| 1742 | def isProposedForTrack( self, track ): |
|---|
| 1743 | return self._tracks.has_key( track.getId() ) |
|---|
| 1744 | |
|---|
| 1745 | def getNumTracks( self ): |
|---|
| 1746 | return len( self._tracks ) |
|---|
| 1747 | |
|---|
| 1748 | def getLocator(self): |
|---|
| 1749 | loc = self.getConference().getLocator() |
|---|
| 1750 | loc["abstractId"] = self.getId() |
|---|
| 1751 | return loc |
|---|
| 1752 | |
|---|
| 1753 | def isAllowedToCoordinate(self,av): |
|---|
| 1754 | """Tells whether or not the specified user can coordinate any of the |
|---|
| 1755 | tracks of this abstract |
|---|
| 1756 | """ |
|---|
| 1757 | for track in self.getTrackList(): |
|---|
| 1758 | if track.canUserCoordinate(av): |
|---|
| 1759 | return True |
|---|
| 1760 | return False |
|---|
| 1761 | |
|---|
| 1762 | def isAllowedToAccess( self, av ): |
|---|
| 1763 | """Tells whether or not an avatar can access an abstract independently |
|---|
| 1764 | of the protection |
|---|
| 1765 | """ |
|---|
| 1766 | #any author is allowed to access |
|---|
| 1767 | #CFA managers are allowed to access |
|---|
| 1768 | #??? any user granted with access privileges is allowed to access |
|---|
| 1769 | #??? any user begin able to modify is also allowed to access |
|---|
| 1770 | #any TC is allowed to access |
|---|
| 1771 | if self.isAllowedToCoordinate(av): |
|---|
| 1772 | return True |
|---|
| 1773 | return self.canUserModify(av) |
|---|
| 1774 | |
|---|
| 1775 | def canAccess(self,aw): |
|---|
| 1776 | #if the conference is protected, then only allowed AW can access |
|---|
| 1777 | return self.isAllowedToAccess( aw.getUser() ) |
|---|
| 1778 | |
|---|
| 1779 | def canView(self, aw): |
|---|
| 1780 | #in the future it would be possible to add an access control |
|---|
| 1781 | #only those users allowed to access are allowed to view |
|---|
| 1782 | return self.isAllowedToAccess( aw.getUser() ) |
|---|
| 1783 | |
|---|
| 1784 | def canModify( self, aw ): |
|---|
| 1785 | return self.canUserModify( aw.getUser() ) |
|---|
| 1786 | |
|---|
| 1787 | def canUserModify( self, av ): |
|---|
| 1788 | #the submitter can modify |
|---|
| 1789 | if self.isSubmitter( av ): |
|---|
| 1790 | return True |
|---|
| 1791 | #??? any CFA manager can modify |
|---|
| 1792 | #??? any user granted with modification privileges can modify |
|---|
| 1793 | #conference managers can modify |
|---|
| 1794 | conf = self.getConference() |
|---|
| 1795 | return conf.canUserModify( av ) |
|---|
| 1796 | |
|---|
| 1797 | def getModifKey( self ): |
|---|
| 1798 | return "" |
|---|
| 1799 | |
|---|
| 1800 | def getAccessKey( self ): |
|---|
| 1801 | return "" |
|---|
| 1802 | |
|---|
| 1803 | def delete( self ): |
|---|
| 1804 | if self._owner: |
|---|
| 1805 | self.getSubmitter().delete() |
|---|
| 1806 | self._submitter = None |
|---|
| 1807 | self.clearAuthors() |
|---|
| 1808 | self.clearSpeakers() |
|---|
| 1809 | self.clearTracks() |
|---|
| 1810 | owner = self._owner |
|---|
| 1811 | self._owner = None |
|---|
| 1812 | owner.removeAbstract( self ) |
|---|
| 1813 | self.setCurrentStatus(AbstractStatusNone(self)) |
|---|
| 1814 | TrashCanManager().add(self) |
|---|
| 1815 | |
|---|
| 1816 | def recoverFromTrashCan(self): |
|---|
| 1817 | TrashCanManager().remove(self) |
|---|
| 1818 | |
|---|
| 1819 | def getCurrentStatus( self ): |
|---|
| 1820 | try: |
|---|
| 1821 | if self._currentStatus: |
|---|
| 1822 | pass |
|---|
| 1823 | except AttributeError, e: |
|---|
| 1824 | self._currentStatus = AbstractStatusSubmitted( self ) |
|---|
| 1825 | return self._currentStatus |
|---|
| 1826 | |
|---|
| 1827 | def setCurrentStatus( self, newStatus ): |
|---|
| 1828 | self._currentStatus = newStatus |
|---|
| 1829 | #If we want to keep a history of status changes we should add here |
|---|
| 1830 | # the old status to a list |
|---|
| 1831 | |
|---|
| 1832 | def accept(self,responsible,destTrack,type,comments="",session=None): |
|---|
| 1833 | """ |
|---|
| 1834 | """ |
|---|
| 1835 | self.getCurrentStatus().accept(responsible,destTrack,type,comments ) |
|---|
| 1836 | #add the abstract to the track for which it has been accepted so it |
|---|
| 1837 | # is visible for it. |
|---|
| 1838 | if destTrack is not None: |
|---|
| 1839 | destTrack.addAbstract( self ) |
|---|
| 1840 | #once the abstract is accepted a new contribution under the destination |
|---|
| 1841 | # track must be created |
|---|
| 1842 | # ATTENTION: This import is placed here explicitely for solving |
|---|
| 1843 | # problems with circular imports |
|---|
| 1844 | from MaKaC.conference import AcceptedContribution |
|---|
| 1845 | contrib=AcceptedContribution(self) |
|---|
| 1846 | if session != None: |
|---|
| 1847 | contrib.setSession(session) |
|---|
| 1848 | self.getCurrentStatus().setContribution( contrib ) |
|---|
| 1849 | self._setContribution( contrib ) |
|---|
| 1850 | |
|---|
| 1851 | def reject( self, responsible, comments="" ): |
|---|
| 1852 | """ |
|---|
| 1853 | """ |
|---|
| 1854 | self.getCurrentStatus().reject( responsible, comments ) |
|---|
| 1855 | |
|---|
| 1856 | def _cmpByDate(self, tj1, tj2): |
|---|
| 1857 | return cmp(tj1.getDate(), tj2.getDate()) |
|---|
| 1858 | |
|---|
| 1859 | def getTrackJudgementsHistorical(self): |
|---|
| 1860 | try: |
|---|
| 1861 | if self._trackJudgementsHistorical: |
|---|
| 1862 | pass |
|---|
| 1863 | if type(self._trackJudgementsHistorical) == tuple: |
|---|
| 1864 | self._trackJudgementsHistorical={} |
|---|
| 1865 | except AttributeError, e: |
|---|
| 1866 | self._trackJudgementsHistorical={} |
|---|
| 1867 | for track in self.getTrackList(): |
|---|
| 1868 | if self.getTrackJudgement(track) is not None: |
|---|
| 1869 | self._trackJudgementsHistorical[track.getId()]= [self.getTrackJudgement(track)] |
|---|
| 1870 | self._notifyModification() |
|---|
| 1871 | return self._trackJudgementsHistorical |
|---|
| 1872 | |
|---|
| 1873 | def getJudgementHistoryByTrack(self, track): |
|---|
| 1874 | id = "notrack" |
|---|
| 1875 | if track is not None: |
|---|
| 1876 | id = track.getId() |
|---|
| 1877 | if self.getTrackJudgementsHistorical().has_key(id): |
|---|
| 1878 | return self.getTrackJudgementsHistorical()[id] |
|---|
| 1879 | return [] |
|---|
| 1880 | |
|---|
| 1881 | def _addTrackJudgementToHistorical(self, tj): |
|---|
| 1882 | id = "notrack" |
|---|
| 1883 | if tj.getTrack() is not None: |
|---|
| 1884 | id = tj.getTrack().getId() |
|---|
| 1885 | if self.getTrackJudgementsHistorical().has_key(id): |
|---|
| 1886 | if tj not in self.getTrackJudgementsHistorical()[id]: |
|---|
| 1887 | self.getTrackJudgementsHistorical()[id].insert(0, tj) |
|---|
| 1888 | else: |
|---|
| 1889 | self.getTrackJudgementsHistorical()[id] = [tj] |
|---|
| 1890 | self._notifyModification() |
|---|
| 1891 | |
|---|
| 1892 | def _removeTrackAcceptance( self, track ): |
|---|
| 1893 | """ |
|---|
| 1894 | """ |
|---|
| 1895 | try: |
|---|
| 1896 | if self._trackAcceptances: |
|---|
| 1897 | pass |
|---|
| 1898 | except AttributeError, e: |
|---|
| 1899 | self._trackAcceptances = OOBTree() |
|---|
| 1900 | |
|---|
| 1901 | if self._trackAcceptances.has_key( track.getId() ): |
|---|
| 1902 | del self._trackAcceptances[ track.getId() ] |
|---|
| 1903 | |
|---|
| 1904 | def _addTrackAcceptance( self, judgement ): |
|---|
| 1905 | """ |
|---|
| 1906 | """ |
|---|
| 1907 | try: |
|---|
| 1908 | if self._trackAcceptances: |
|---|
| 1909 | pass |
|---|
| 1910 | except AttributeError, e: |
|---|
| 1911 | self._trackAcceptances = OOBTree() |
|---|
| 1912 | |
|---|
| 1913 | self._removeTrackRejection( judgement.getTrack() ) |
|---|
| 1914 | self._removeTrackReallocation( judgement.getTrack() ) |
|---|
| 1915 | self._trackAcceptances[ judgement.getTrack().getId() ] = judgement |
|---|
| 1916 | self._addTrackJudgementToHistorical(judgement) |
|---|
| 1917 | |
|---|
| 1918 | def _removeTrackRejection( self, track ): |
|---|
| 1919 | """ |
|---|
| 1920 | """ |
|---|
| 1921 | try: |
|---|
| 1922 | if self._trackRejections: |
|---|
| 1923 | pass |
|---|
| 1924 | except AttributeError, e: |
|---|
| 1925 | self._trackRejections = OOBTree() |
|---|
| 1926 | |
|---|
| 1927 | if self._trackRejections.has_key( track.getId() ): |
|---|
| 1928 | del self._trackRejections[ track.getId() ] |
|---|
| 1929 | |
|---|
| 1930 | def _addTrackRejection( self, judgement ): |
|---|
| 1931 | """ |
|---|
| 1932 | """ |
|---|
| 1933 | try: |
|---|
| 1934 | if self._trackRejections: |
|---|
| 1935 | pass |
|---|
| 1936 | except AttributeError, e: |
|---|
| 1937 | self._trackRejections = OOBTree() |
|---|
| 1938 | |
|---|
| 1939 | self._removeTrackAcceptance( judgement.getTrack() ) |
|---|
| 1940 | self._removeTrackReallocation( judgement.getTrack() ) |
|---|
| 1941 | self._trackRejections[ judgement.getTrack().getId() ] = judgement |
|---|
| 1942 | self._addTrackJudgementToHistorical(judgement) |
|---|
| 1943 | |
|---|
| 1944 | def _removeTrackReallocation( self, track ): |
|---|
| 1945 | """ |
|---|
| 1946 | """ |
|---|
| 1947 | try: |
|---|
| 1948 | if self._trackReallocations: |
|---|
| 1949 | pass |
|---|
| 1950 | except AttributeError, e: |
|---|
| 1951 | self._trackReallocations = OOBTree() |
|---|
| 1952 | |
|---|
| 1953 | if self._trackReallocations.has_key( track.getId() ): |
|---|
| 1954 | del self._trackReallocations[ track.getId() ] |
|---|
| 1955 | |
|---|
| 1956 | def _addTrackReallocation( self, judgement ): |
|---|
| 1957 | """ |
|---|
| 1958 | """ |
|---|
| 1959 | try: |
|---|
| 1960 | if self._trackReallocations: |
|---|
| 1961 | pass |
|---|
| 1962 | except AttributeError, e: |
|---|
| 1963 | self._trackReallocations = OOBTree() |
|---|
| 1964 | |
|---|
| 1965 | self._removeTrackAcceptance( judgement.getTrack() ) |
|---|
| 1966 | self._removeTrackRejection( judgement.getTrack() ) |
|---|
| 1967 | self._trackReallocations[ judgement.getTrack().getId() ] = judgement |
|---|
| 1968 | self._addTrackJudgementToHistorical(judgement) |
|---|
| 1969 | |
|---|
| 1970 | def _clearTrackRejections( self ): |
|---|
| 1971 | try: |
|---|
| 1972 | if self._trackRejections: |
|---|
| 1973 | pass |
|---|
| 1974 | except AttributeError, e: |
|---|
| 1975 | self._trackRejections = OOBTree() |
|---|
| 1976 | while len(self._trackRejections.values())>0: |
|---|
| 1977 | t = self._trackRejections.values()[0].getTrack() |
|---|
| 1978 | self._removeTrackRejection( t ) |
|---|
| 1979 | |
|---|
| 1980 | def _clearTrackAcceptances( self ): |
|---|
| 1981 | try: |
|---|
| 1982 | if self._trackAcceptances: |
|---|
| 1983 | pass |
|---|
| 1984 | except AttributeError, e: |
|---|
| 1985 | self._trackAcceptances = OOBTree() |
|---|
| 1986 | while len(self._trackAcceptances.values())>0: |
|---|
| 1987 | t = self._trackAcceptances.values()[0].getTrack() |
|---|
| 1988 | self._removeTrackAcceptance( t ) |
|---|
| 1989 | |
|---|
| 1990 | def _clearTrackReallocations( self ): |
|---|
| 1991 | try: |
|---|
| 1992 | if self._trackReallocations: |
|---|
| 1993 | pass |
|---|
| 1994 | except AttributeError, e: |
|---|
| 1995 | self._trackReallocations = OOBTree() |
|---|
| 1996 | while len(self._trackReallocations.values())>0: |
|---|
| 1997 | t = self._trackReallocations.values()[0].getTrack() |
|---|
| 1998 | self._removeTrackReallocation(t) |
|---|
| 1999 | |
|---|
| 2000 | def _removePreviousJud(self, responsible, track): |
|---|
| 2001 | ''' Check if there is a previous judgement and remove it ''' |
|---|
| 2002 | toDelete = [] # list of judgements to delete |
|---|
| 2003 | for jud in self.getJudgementHistoryByTrack(track): |
|---|
| 2004 | if jud.getResponsible() == responsible: |
|---|
| 2005 | toDelete.append(jud) |
|---|
| 2006 | |
|---|
| 2007 | for x in toDelete: |
|---|
| 2008 | self.getTrackJudgementsHistorical()[track.getId()].remove(x) |
|---|
| 2009 | |
|---|
| 2010 | |
|---|
| 2011 | def proposeToAccept( self, responsible, track, contribType, comment="", answers=[] ): |
|---|
| 2012 | """ |
|---|
| 2013 | """ |
|---|
| 2014 | # the proposal has to be done for a track |
|---|
| 2015 | if track is None: |
|---|
| 2016 | raise MaKaCError( _("You have to choose a track in order to do the proposal. If there are not tracks to select, please change the track assignment of the abstract")) |
|---|
| 2017 | #We check the track for which the abstract is proposed to be accepted |
|---|
| 2018 | # is in the current abstract |
|---|
| 2019 | if not self.isProposedForTrack( track ): |
|---|
| 2020 | raise MaKaCError( _("Cannot propose to accept an abstract which is not proposed for the specified track")) |
|---|
| 2021 | # check if there is a previous judgement of this author in for this abstract in this track |
|---|
| 2022 | self._removePreviousJud(responsible, track) |
|---|
| 2023 | # Create the new judgement |
|---|
| 2024 | jud = AbstractAcceptance( track, responsible, contribType, answers ) |
|---|
| 2025 | jud.setComment( comment ) |
|---|
| 2026 | self._addTrackAcceptance( jud ) |
|---|
| 2027 | # Update the rating of the abstract |
|---|
| 2028 | self.updateRating() |
|---|
| 2029 | #We trigger the state transition |
|---|
| 2030 | self.getCurrentStatus().proposeToAccept() |
|---|
| 2031 | |
|---|
| 2032 | def proposeToReject( self, responsible, track, comment="", answers=[] ): |
|---|
| 2033 | """ |
|---|
| 2034 | """ |
|---|
| 2035 | # the proposal has to be done for a track |
|---|
| 2036 | if track is None: |
|---|
| 2037 | raise MaKaCError( _("You have to choose a track in order to do the proposal. If there are not tracks to select, please change the track assignment of the abstract")) |
|---|
| 2038 | #We check the track for which the abstract is proposed to be accepted |
|---|
| 2039 | # is in the current abstract |
|---|
| 2040 | if not self.isProposedForTrack( track ): |
|---|
| 2041 | raise MaKaCError( _("Cannot propose to reject an abstract which is not proposed for the specified track")) |
|---|
| 2042 | # check if there is a previous judgement of this author in for this abstract in this track |
|---|
| 2043 | self._removePreviousJud(responsible, track) |
|---|
| 2044 | # Create the new judgement |
|---|
| 2045 | jud = AbstractRejection( track, responsible, answers ) |
|---|
| 2046 | jud.setComment( comment ) |
|---|
| 2047 | self._addTrackRejection( jud ) |
|---|
| 2048 | # Update the rating of the abstract |
|---|
| 2049 | self.updateRating() |
|---|
| 2050 | #We trigger the state transition |
|---|
| 2051 | self.getCurrentStatus().proposeToReject() |
|---|
| 2052 | |
|---|
| 2053 | def proposeForOtherTracks( self, responsible, track, comment, propTracks ): |
|---|
| 2054 | """ |
|---|
| 2055 | """ |
|---|
| 2056 | #We check the track which proposes to allocate the abstract is in the |
|---|
| 2057 | # current abstract |
|---|
| 2058 | if not self.isProposedForTrack( track ): |
|---|
| 2059 | raise MaKaCError( _("Cannot propose to reallocate an abstract which is not proposed for the specified track")) |
|---|
| 2060 | #We keep the track judgement |
|---|
| 2061 | jud = AbstractReallocation( track, responsible, propTracks ) |
|---|
| 2062 | jud.setComment( comment ) |
|---|
| 2063 | self._addTrackReallocation( jud ) |
|---|
| 2064 | #We add the proposed tracks to the abstract |
|---|
| 2065 | for track in propTracks: |
|---|
| 2066 | self._addTrack( track ) |
|---|
| 2067 | #We trigger the state transition |
|---|
| 2068 | self.getCurrentStatus().proposeToReallocate() |
|---|
| 2069 | |
|---|
| 2070 | def withdraw(self,resp,comment=""): |
|---|
| 2071 | """ |
|---|
| 2072 | """ |
|---|
| 2073 | self.getCurrentStatus().withdraw(resp,comment) |
|---|
| 2074 | |
|---|
| 2075 | def recover( self ): |
|---|
| 2076 | """Puts a withdrawn abstract back in the list of submitted abstracts. |
|---|
| 2077 | HAS NOTHING TO DO WITH THE RECOVERY PROCESS... |
|---|
| 2078 | """ |
|---|
| 2079 | #we must clear any track judgement |
|---|
| 2080 | #self._clearTrackAcceptances() |
|---|
| 2081 | #self._clearTrackRejections() |
|---|
| 2082 | #self._clearTrackReallocations() |
|---|
| 2083 | self.getCurrentStatus().recover() #status change |
|---|
| 2084 | #if succeeded we must reset the submission date |
|---|
| 2085 | self._setSubmissionDate( nowutc() ) |
|---|
| 2086 | self._notifyModification() |
|---|
| 2087 | |
|---|
| 2088 | def getTrackJudgement( self, track ): |
|---|
| 2089 | """ |
|---|
| 2090 | """ |
|---|
| 2091 | try: |
|---|
| 2092 | if self._trackAcceptances: |
|---|
| 2093 | pass |
|---|
| 2094 | except AttributeError, e: |
|---|
| 2095 | self._trackAcceptances = OOBTree() |
|---|
| 2096 | try: |
|---|
| 2097 | if self._trackRejections: |
|---|
| 2098 | pass |
|---|
| 2099 | except AttributeError, e: |
|---|
| 2100 | self._trackRejections = OOBTree() |
|---|
| 2101 | try: |
|---|
| 2102 | if self._trackReallocations: |
|---|
| 2103 | pass |
|---|
| 2104 | except AttributeError, e: |
|---|
| 2105 | self._trackReallocations = OOBTree() |
|---|
| 2106 | |
|---|
| 2107 | if self._trackAcceptances.has_key( track.getId() ): |
|---|
| 2108 | return self._trackAcceptances[ track.getId() ] |
|---|
| 2109 | elif self._trackRejections.has_key( track.getId() ): |
|---|
| 2110 | return self._trackRejections[ track.getId() ] |
|---|
| 2111 | elif self._trackReallocations.has_key( track.getId() ): |
|---|
| 2112 | return self._trackReallocations[ track.getId() ] |
|---|
| 2113 | return None |
|---|
| 2114 | |
|---|
| 2115 | def getTrackAcceptanceList( self ): |
|---|
| 2116 | try: |
|---|
| 2117 | if self._trackAcceptances: |
|---|
| 2118 | pass |
|---|
| 2119 | except AttributeError, e: |
|---|
| 2120 | self._trackAcceptances = OOBTree() |
|---|
| 2121 | res = [] |
|---|
| 2122 | for trackId in intersection( self._tracks, self._trackAcceptances ): |
|---|
| 2123 | res.append( self._trackAcceptances[ trackId ] ) |
|---|
| 2124 | return res |
|---|
| 2125 | |
|---|
| 2126 | def getNumProposedToAccept( self ): |
|---|
| 2127 | try: |
|---|
| 2128 | if self._trackAcceptances: |
|---|
| 2129 | pass |
|---|
| 2130 | except AttributeError, e: |
|---|
| 2131 | self._trackAcceptances = OOBTree() |
|---|
| 2132 | return len( intersection( self._tracks, self._trackAcceptances ) ) |
|---|
| 2133 | |
|---|
| 2134 | def getNumProposedToReject( self ): |
|---|
| 2135 | try: |
|---|
| 2136 | if self._trackRejections: |
|---|
| 2137 | pass |
|---|
| 2138 | except AttributeError, e: |
|---|
| 2139 | self._trackRejections = OOBTree() |
|---|
| 2140 | return len( intersection( self._tracks, self._trackRejections ) ) |
|---|
| 2141 | |
|---|
| 2142 | def getNumJudgements( self ): |
|---|
| 2143 | """ |
|---|
| 2144 | """ |
|---|
| 2145 | try: |
|---|
| 2146 | if self._trackAcceptances: |
|---|
| 2147 | pass |
|---|
| 2148 | except AttributeError, e: |
|---|
| 2149 | self._trackAcceptances = OOBTree() |
|---|
| 2150 | try: |
|---|
| 2151 | if self._trackRejections: |
|---|
| 2152 | pass |
|---|
| 2153 | except AttributeError, e: |
|---|
| 2154 | self._trackRejections = OOBTree() |
|---|
| 2155 | try: |
|---|
| 2156 | if self._trackReallocations: |
|---|
| 2157 | pass |
|---|
| 2158 | except AttributeError, e: |
|---|
| 2159 | self._trackReallocations = OOBTree() |
|---|
| 2160 | tmp1 = union( self._trackAcceptances, self._trackRejections ) |
|---|
| 2161 | judgements = union( tmp1, self._trackReallocations ) |
|---|
| 2162 | return len( intersection( self._tracks, judgements ) ) |
|---|
| 2163 | |
|---|
| 2164 | def getReallocationTargetedList( self, track ): |
|---|
| 2165 | try: |
|---|
| 2166 | if self._trackReallocations: |
|---|
| 2167 | pass |
|---|
| 2168 | except AttributeError, e: |
|---|
| 2169 | self._trackReallocations = OOBTree() |
|---|
| 2170 | #XXX: not optimal |
|---|
| 2171 | res = [] |
|---|
| 2172 | for r in self._trackReallocations.values(): |
|---|
| 2173 | if track in r.getProposedTrackList(): |
|---|
| 2174 | res.append( r ) |
|---|
| 2175 | return res |
|---|
| 2176 | |
|---|
| 2177 | def getContribution( self ): |
|---|
| 2178 | try: |
|---|
| 2179 | if self._contribution: |
|---|
| 2180 | pass |
|---|
| 2181 | except AttributeError: |
|---|
| 2182 | self._contribution = None |
|---|
| 2183 | status = self.getCurrentStatus() |
|---|
| 2184 | if isinstance(status,AbstractStatusAccepted) and \ |
|---|
| 2185 | self._contribution is None: |
|---|
| 2186 | self._contribution=status.getContribution() |
|---|
| 2187 | return self._contribution |
|---|
| 2188 | |
|---|
| 2189 | def _setContribution(self,contrib): |
|---|
| 2190 | self._contribution = contrib |
|---|
| 2191 | |
|---|
| 2192 | def getIntCommentList(self): |
|---|
| 2193 | try: |
|---|
| 2194 | if self._intComments: |
|---|
| 2195 | pass |
|---|
| 2196 | except AttributeError: |
|---|
| 2197 | self._intComments=PersistentList() |
|---|
| 2198 | return self._intComments |
|---|
| 2199 | |
|---|
| 2200 | def addIntComment(self,newComment): |
|---|
| 2201 | try: |
|---|
| 2202 | if self._intComments: |
|---|
| 2203 | pass |
|---|
| 2204 | except AttributeError: |
|---|
| 2205 | self._intComments=PersistentList() |
|---|
| 2206 | try: |
|---|
| 2207 | if self._intCommentsGen: |
|---|
| 2208 | pass |
|---|
| 2209 | except AttributeError: |
|---|
| 2210 | self._intCommentsGen=Counter() |
|---|
| 2211 | if newComment in self._intComments: |
|---|
| 2212 | return |
|---|
| 2213 | id = newComment.getId() |
|---|
| 2214 | if id == "": |
|---|
| 2215 | id = self._authorGen.newCount() |
|---|
| 2216 | newComment.includeInAbstract(self, id) |
|---|
| 2217 | self._intComments.append(newComment) |
|---|
| 2218 | |
|---|
| 2219 | def getIntCommentById(self,id): |
|---|
| 2220 | try: |
|---|
| 2221 | if self._intComments: |
|---|
| 2222 | pass |
|---|
| 2223 | except AttributeError: |
|---|
| 2224 | self._intComments=PersistentList() |
|---|
| 2225 | for comment in self._intComments: |
|---|
| 2226 | if id.strip()==comment.getId(): |
|---|
| 2227 | return comment |
|---|
| 2228 | return None |
|---|
| 2229 | |
|---|
| 2230 | def clearIntCommentList(self): |
|---|
| 2231 | while len(self.getIntCommentList()) > 0: |
|---|
| 2232 | self.removeIntComment(self.getIntCommentList()[0]) |
|---|
| 2233 | |
|---|
| 2234 | def removeIntComment(self,comment): |
|---|
| 2235 | try: |
|---|
| 2236 | if self._intComments: |
|---|
| 2237 | pass |
|---|
| 2238 | except AttributeError: |
|---|
| 2239 | self._intComments=PersistentList() |
|---|
| 2240 | if comment not in self._intComments: |
|---|
| 2241 | return |
|---|
| 2242 | self._intComments.remove(comment) |
|---|
| 2243 | comment.delete() |
|---|
| 2244 | |
|---|
| 2245 | def recoverIntComment(self, comment): |
|---|
| 2246 | self.addIntComment(comment) |
|---|
| 2247 | comment.recover() |
|---|
| 2248 | |
|---|
| 2249 | def markAsDuplicated(self,responsible,originalAbstract,comments="", track=None): |
|---|
| 2250 | """ |
|---|
| 2251 | """ |
|---|
| 2252 | self.getCurrentStatus().markAsDuplicated(responsible,originalAbstract,comments) |
|---|
| 2253 | |
|---|
| 2254 | if track is not None: |
|---|
| 2255 | jud = AbstractMarkedAsDuplicated( track, responsible, originalAbstract ) |
|---|
| 2256 | jud.setComment( comments ) |
|---|
| 2257 | self._addTrackJudgementToHistorical(jud) |
|---|
| 2258 | else: |
|---|
| 2259 | for t in self.getTrackList(): |
|---|
| 2260 | jud = AbstractMarkedAsDuplicated( t, responsible, originalAbstract ) |
|---|
| 2261 | jud.setComment( comments ) |
|---|
| 2262 | self._addTrackJudgementToHistorical(jud) |
|---|
| 2263 | |
|---|
| 2264 | def unMarkAsDuplicated(self,responsible,comments="", track=None): |
|---|
| 2265 | """ |
|---|
| 2266 | """ |
|---|
| 2267 | |
|---|
| 2268 | #we must clear any track judgement |
|---|
| 2269 | self._clearTrackAcceptances() |
|---|
| 2270 | self._clearTrackRejections() |
|---|
| 2271 | self._clearTrackReallocations() |
|---|
| 2272 | #self.getCurrentStatus().recover() #status change |
|---|
| 2273 | self.getCurrentStatus().unMarkAsDuplicated(responsible,comments) |
|---|
| 2274 | |
|---|
| 2275 | if track is not None: |
|---|
| 2276 | jud = AbstractUnMarkedAsDuplicated(track, responsible ) |
|---|
| 2277 | jud.setComment( comments ) |
|---|
| 2278 | self._addTrackJudgementToHistorical(jud) |
|---|
| 2279 | else: |
|---|
| 2280 | for t in self.getTrackList(): |
|---|
| 2281 | jud = AbstractUnMarkedAsDuplicated( t, responsible ) |
|---|
| 2282 | jud.setComment( comments ) |
|---|
| 2283 | self._addTrackJudgementToHistorical(jud) |
|---|
| 2284 | |
|---|
| 2285 | self._notifyModification() |
|---|
| 2286 | |
|---|
| 2287 | def mergeInto(self,responsible,targetAbs,mergeAuthors=False,comments=""): |
|---|
| 2288 | """ |
|---|
| 2289 | """ |
|---|
| 2290 | self.getCurrentStatus().mergeInto(responsible,targetAbs,comments) |
|---|
| 2291 | targetAbs.addMergeFromAbstract(self) |
|---|
| 2292 | if mergeAuthors: |
|---|
| 2293 | #for auth in self.getAuthorList(): |
|---|
| 2294 | # newAuth=targetAbs.newAuthor() |
|---|
| 2295 | # newAuth.setFromAbstractParticipation(auth) |
|---|
| 2296 | # if self.isPrimaryAuthor(auth): |
|---|
| 2297 | # targetAbs.addPrimaryAuthor(newAuth) |
|---|
| 2298 | for auth in self.getPrimaryAuthorList(): |
|---|
| 2299 | newAuth=targetAbs.newPrimaryAuthor() |
|---|
| 2300 | newAuth.setFromAbstractParticipation(auth) |
|---|
| 2301 | for auth in self.getCoAuthorList(): |
|---|
| 2302 | newAuth=targetAbs.newCoAuthor() |
|---|
| 2303 | newAuth.setFromAbstractParticipation(auth) |
|---|
| 2304 | |
|---|
| 2305 | def notify(self,notificator,responsible): |
|---|
| 2306 | """notifies the abstract responsibles with a matching template |
|---|
| 2307 | """ |
|---|
| 2308 | tpl=self.getOwner().getNotifTplForAbstract(self) |
|---|
| 2309 | if not tpl: |
|---|
| 2310 | return |
|---|
| 2311 | notificator.notify(self,tpl) |
|---|
| 2312 | self.getNotificationLog().addEntry(NotifLogEntry(responsible,tpl)) |
|---|
| 2313 | |
|---|
| 2314 | def unMerge(self,responsible,comments=""): |
|---|
| 2315 | #we must clear any track judgement |
|---|
| 2316 | self._clearTrackAcceptances() |
|---|
| 2317 | self._clearTrackRejections() |
|---|
| 2318 | self._clearTrackReallocations() |
|---|
| 2319 | self.getCurrentStatus().getTargetAbstract().removeMergeFromAbstract(self) |
|---|
| 2320 | self.getCurrentStatus().unMerge(responsible,comments) |
|---|
| 2321 | self._notifyModification() |
|---|
| 2322 | |
|---|
| 2323 | def getNotificationLog(self): |
|---|
| 2324 | try: |
|---|
| 2325 | if self._notifLog: |
|---|
| 2326 | pass |
|---|
| 2327 | except AttributeError: |
|---|
| 2328 | self._notifLog=NotificationLog(self) |
|---|
| 2329 | return self._notifLog |
|---|
| 2330 | |
|---|
| 2331 | # Rating methods |
|---|
| 2332 | def getRating(self): |
|---|
| 2333 | """ Get the average rating of the abstract """ |
|---|
| 2334 | try: |
|---|
| 2335 | if self._rating: |
|---|
| 2336 | pass |
|---|
| 2337 | except AttributeError: |
|---|
| 2338 | self._rating = None |
|---|
| 2339 | return self._rating |
|---|
| 2340 | |
|---|
| 2341 | def updateRating(self, scale = None): |
|---|
| 2342 | """ |
|---|
| 2343 | Update the average rating of the abstract which is calculated with the average of each judgement. |
|---|
| 2344 | If the scale (tuple with lower,higher) is passed, the judgement are re-adjusted to the new scale. |
|---|
| 2345 | """ |
|---|
| 2346 | self._rating = None |
|---|
| 2347 | # calculate the total valoration |
|---|
| 2348 | judNum = 0 |
|---|
| 2349 | ratingSum = 0 |
|---|
| 2350 | for track in self.getTrackListSorted(): |
|---|
| 2351 | for jud in self.getJudgementHistoryByTrack(track): |
|---|
| 2352 | if scale: |
|---|
| 2353 | # calculate the new values for each judgement |
|---|
| 2354 | scaleLower, scaleHigher = scale |
|---|
| 2355 | jud.recalculateJudgementValues(scaleLower, scaleHigher) |
|---|
| 2356 | if jud.getJudValue() != None: # it means there is a numeric value for the judgement |
|---|
| 2357 | ratingSum += jud.getJudValue() |
|---|
| 2358 | judNum += 1 |
|---|
| 2359 | # Calculate the average |
|---|
| 2360 | if judNum != 0: |
|---|
| 2361 | self._rating = float(ratingSum) / judNum |
|---|
| 2362 | |
|---|
| 2363 | def getQuestionsAverage(self): |
|---|
| 2364 | '''Get the list of questions answered in the reviews for an abstract ''' |
|---|
| 2365 | dTotals = {} # {idQ1: total_value, idQ2: total_value ...} |
|---|
| 2366 | dTimes = {} # {idQ1: times_answered, idQ2: times_answered} |
|---|
| 2367 | for track in self.getTrackListSorted(): |
|---|
| 2368 | for jud in self.getJudgementHistoryByTrack(track): |
|---|
| 2369 | for answer in jud.getAnswers(): |
|---|
| 2370 | # check if the question is in d and sum the answers value or insert in d the new question |
|---|
| 2371 | if dTotals.has_key(answer.getQuestion().getText()): |
|---|
| 2372 | dTotals[answer.getQuestion().getText()] += answer.getValue() |
|---|
| 2373 | dTimes[answer.getQuestion().getText()] += 1 |
|---|
| 2374 | else: # first time |
|---|
| 2375 | dTotals[answer.getQuestion().getText()] = answer.getValue() |
|---|
| 2376 | dTimes[answer.getQuestion().getText()] = 1 |
|---|
| 2377 | # get the questions average |
|---|
| 2378 | questionsAverage = {} |
|---|
| 2379 | for q, v in dTotals.iteritems(): |
|---|
| 2380 | # insert the element and calculate the average for the value |
|---|
| 2381 | questionsAverage[q] = float(v)/dTimes[q] |
|---|
| 2382 | return questionsAverage |
|---|
| 2383 | |
|---|
| 2384 | def removeAnswersOfQuestion(self, questionId): |
|---|
| 2385 | ''' Remove the answers of the question with questionId value ''' |
|---|
| 2386 | for track in self.getTrackListSorted(): |
|---|
| 2387 | for jud in self.getJudgementHistoryByTrack(track): |
|---|
| 2388 | jud.removeAnswer(questionId) |
|---|
| 2389 | |
|---|
| 2390 | |
|---|
| 2391 | |
|---|
| 2392 | class AbstractJudgement( Persistent ): |
|---|
| 2393 | """This class represents each of the judgements made by a track about a |
|---|
| 2394 | certain abstract. Each track for which an abstract is proposed can |
|---|
| 2395 | make a judgement proposing the abstract to be accepted or rejected. |
|---|
| 2396 | Different track judgements must be kept so the referees who have to |
|---|
| 2397 | take the final decission can overview different opinions from the |
|---|
| 2398 | track coordinators. |
|---|
| 2399 | Together with the judgement some useful information like the date when |
|---|
| 2400 | it was done and the user who did it will be kept. |
|---|
| 2401 | """ |
|---|
| 2402 | |
|---|
| 2403 | def __init__( self, track, responsible, answers ): |
|---|
| 2404 | self._track = track |
|---|
| 2405 | self._setResponsible( responsible ) |
|---|
| 2406 | self._date = nowutc() |
|---|
| 2407 | self._comment = "" |
|---|
| 2408 | self._answers = answers |
|---|
| 2409 | self._judValue = self.calculateJudgementAverage() # judgement average value |
|---|
| 2410 | self._totalJudValue = self.calculateAnswersTotalValue() |
|---|
| 2411 | |
|---|
| 2412 | |
|---|
| 2413 | def _setResponsible( self, newRes ): |
|---|
| 2414 | self._responsible = newRes |
|---|
| 2415 | |
|---|
| 2416 | def getResponsible( self ): |
|---|
| 2417 | return self._responsible |
|---|
| 2418 | |
|---|
| 2419 | def getDate( self ): |
|---|
| 2420 | return self._date |
|---|
| 2421 | |
|---|
| 2422 | def setDate(self, date): |
|---|
| 2423 | self._date = date |
|---|
| 2424 | |
|---|
| 2425 | def getTrack( self ): |
|---|
| 2426 | return self._track |
|---|
| 2427 | |
|---|
| 2428 | def setComment( self, newComment ): |
|---|
| 2429 | self._comment = newComment.strip() |
|---|
| 2430 | |
|---|
| 2431 | def getComment( self ): |
|---|
| 2432 | return self._comment |
|---|
| 2433 | |
|---|
| 2434 | def getAnswers(self): |
|---|
| 2435 | try: |
|---|
| 2436 | if self._answers: |
|---|
| 2437 | pass |
|---|
| 2438 | except AttributeError: |
|---|
| 2439 | self._answers = [] |
|---|
| 2440 | return self._answers |
|---|
| 2441 | |
|---|
| 2442 | def calculateJudgementAverage(self): |
|---|
| 2443 | '''Calculate the average value of the given answers''' |
|---|
| 2444 | result = 0 |
|---|
| 2445 | if (len(self.getAnswers()) != 0): |
|---|
| 2446 | # convert the values into float types |
|---|
| 2447 | floatList = [ans.getValue() for ans in self._answers] |
|---|
| 2448 | result = sum(floatList) / float(len(floatList)) # calculate the average |
|---|
| 2449 | else: |
|---|
| 2450 | # there are no questions |
|---|
| 2451 | result = None |
|---|
| 2452 | return result |
|---|
| 2453 | |
|---|
| 2454 | def getJudValue(self): |
|---|
| 2455 | try: |
|---|
| 2456 | if self._judValue: |
|---|
| 2457 | pass |
|---|
| 2458 | except AttributeError: |
|---|
| 2459 | self._judValue = self.calculateJudgementAverage() # judgement average value |
|---|
| 2460 | return self._judValue |
|---|
| 2461 | |
|---|
| 2462 | def getTotalJudValue(self): |
|---|
| 2463 | try: |
|---|
| 2464 | if self._totalJudValue: |
|---|
| 2465 | pass |
|---|
| 2466 | except AttributeError: |
|---|
| 2467 | self._totalJudValue = self.calculateAnswersTotalValue() |
|---|
| 2468 | return self._totalJudValue |
|---|
| 2469 | |
|---|
| 2470 | def calculateAnswersTotalValue(self): |
|---|
| 2471 | ''' Calculate the sum of all the ratings ''' |
|---|
| 2472 | result = 0 |
|---|
| 2473 | for ans in self.getAnswers(): |
|---|
| 2474 | result += ans.getValue() |
|---|
| 2475 | return result |
|---|
| 2476 | |
|---|
| 2477 | def recalculateJudgementValues(self, scaleLower, scaleHigher): |
|---|
| 2478 | ''' Update the values of the judgement. This function is called when the scale is changed.''' |
|---|
| 2479 | for ans in self.getAnswers(): |
|---|
| 2480 | ans.calculateRatingValue(scaleLower, scaleHigher) |
|---|
| 2481 | self._judValue = self.calculateJudgementAverage() |
|---|
| 2482 | self._totalJudValue = self.calculateAnswersTotalValue() |
|---|
| 2483 | |
|---|
| 2484 | def removeAnswer(self, questionId): |
|---|
| 2485 | ''' Remove the current answers of the questionId ''' |
|---|
| 2486 | for ans in self.getAnswers(): |
|---|
| 2487 | if ans.getQuestion().getId() == questionId: |
|---|
| 2488 | self._answers.remove(ans) |
|---|
| 2489 | self._notifyModification() |
|---|
| 2490 | |
|---|
| 2491 | def _notifyModification(self): |
|---|
| 2492 | self._p_changed = 1 |
|---|
| 2493 | |
|---|
| 2494 | |
|---|
| 2495 | class AbstractAcceptance( AbstractJudgement ): |
|---|
| 2496 | |
|---|
| 2497 | def __init__( self, track, responsible, contribType, answers ): |
|---|
| 2498 | AbstractJudgement.__init__( self, track, responsible, answers ) |
|---|
| 2499 | self._contribType = contribType |
|---|
| 2500 | |
|---|
| 2501 | def clone(self,track): |
|---|
| 2502 | aa = AbstractAcceptance(track,self.getResponsible(), self.getContribType(), self.getAnswers()) |
|---|
| 2503 | return aa |
|---|
| 2504 | |
|---|
| 2505 | def getContribType( self ): |
|---|
| 2506 | try: |
|---|
| 2507 | if self._contribType: |
|---|
| 2508 | pass |
|---|
| 2509 | except AttributeError, e: |
|---|
| 2510 | self._contribType = None |
|---|
| 2511 | return self._contribType |
|---|
| 2512 | |
|---|
| 2513 | |
|---|
| 2514 | class AbstractRejection( AbstractJudgement ): |
|---|
| 2515 | |
|---|
| 2516 | def clone(self, track): |
|---|
| 2517 | arj = AbstractRejection(track,self.getResponsible(), self.getAnswers()) |
|---|
| 2518 | return arj |
|---|
| 2519 | |
|---|
| 2520 | class AbstractReallocation( AbstractJudgement ): |
|---|
| 2521 | |
|---|
| 2522 | def __init__( self, track, responsible, propTracks ): |
|---|
| 2523 | AbstractJudgement.__init__( self, track, responsible ) |
|---|
| 2524 | self._proposedTracks = PersistentList( propTracks ) |
|---|
| 2525 | |
|---|
| 2526 | def clone(self, track): |
|---|
| 2527 | arl = AbstractReallocation(track, self.getResponsible(), self.getProposedTrackList()) |
|---|
| 2528 | return arl |
|---|
| 2529 | |
|---|
| 2530 | def getProposedTrackList( self ): |
|---|
| 2531 | return self._proposedTracks |
|---|
| 2532 | |
|---|
| 2533 | class AbstractMarkedAsDuplicated( AbstractJudgement ): |
|---|
| 2534 | |
|---|
| 2535 | def __init__( self, track, responsible, originalAbst ): |
|---|
| 2536 | AbstractJudgement.__init__( self, track, responsible ) |
|---|
| 2537 | self._originalAbst=originalAbst |
|---|
| 2538 | |
|---|
| 2539 | def clone(self,track): |
|---|
| 2540 | amad = AbstractMarkedAsDuplicated(track,self.getResponsible(), self.getOriginalAbstract()) |
|---|
| 2541 | return amad |
|---|
| 2542 | |
|---|
| 2543 | def getOriginalAbstract(self): |
|---|
| 2544 | return self._originalAbst |
|---|
| 2545 | |
|---|
| 2546 | |
|---|
| 2547 | class AbstractUnMarkedAsDuplicated( AbstractJudgement ): |
|---|
| 2548 | |
|---|
| 2549 | def clone(self,track): |
|---|
| 2550 | auad = AbstractUnMarkedAsDuplicated(track,self.getResponsible()) |
|---|
| 2551 | return auad |
|---|
| 2552 | |
|---|
| 2553 | |
|---|
| 2554 | class AbstractStatus( Persistent ): |
|---|
| 2555 | """This class represents any of the status in which an abstract can be. |
|---|
| 2556 | From the moment they are submitted (and therefore created), abstracts |
|---|
| 2557 | can go throuugh different status each having a different meaning. |
|---|
| 2558 | As there can be many status, the transitions between them are quite |
|---|
| 2559 | complex and as the system evolves we could require to add or delete |
|---|
| 2560 | new status the "Status" pattern is applied. This is the base class. |
|---|
| 2561 | Apart from giving information about the status of an abstract, this |
|---|
| 2562 | class is responsible to store information about how the status was |
|---|
| 2563 | reached (who provoke the transition, when, ...). |
|---|
| 2564 | """ |
|---|
| 2565 | _name = "" |
|---|
| 2566 | |
|---|
| 2567 | def __init__( self, abstract ): |
|---|
| 2568 | self._setAbstract( abstract ) |
|---|
| 2569 | self._setDate( nowutc() ) |
|---|
| 2570 | |
|---|
| 2571 | def getName(self): |
|---|
| 2572 | return self._name |
|---|
| 2573 | |
|---|
| 2574 | def _setAbstract( self, abs ): |
|---|
| 2575 | self._abstract = abs |
|---|
| 2576 | |
|---|
| 2577 | def getAbstract( self ): |
|---|
| 2578 | return self._abstract |
|---|
| 2579 | |
|---|
| 2580 | def _setDate( self, date ): |
|---|
| 2581 | self._date = date |
|---|
| 2582 | |
|---|
| 2583 | def getDate( self ): |
|---|
| 2584 | return self._date |
|---|
| 2585 | |
|---|
| 2586 | def accept(self,responsible,destTrack,type,comments=""): |
|---|
| 2587 | """ |
|---|
| 2588 | """ |
|---|
| 2589 | s = AbstractStatusAccepted(self.getAbstract(),responsible,destTrack,type,comments) |
|---|
| 2590 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 2591 | |
|---|
| 2592 | def reject( self, responsible, comments = "" ): |
|---|
| 2593 | """ |
|---|
| 2594 | """ |
|---|
| 2595 | s = AbstractStatusRejected( self.getAbstract(), responsible, comments ) |
|---|
| 2596 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 2597 | |
|---|
| 2598 | def _getStatusClass( self ): |
|---|
| 2599 | """ |
|---|
| 2600 | """ |
|---|
| 2601 | numAccepts = self._abstract.getNumProposedToAccept() |
|---|
| 2602 | numJudgements = self._abstract.getNumJudgements() |
|---|
| 2603 | if numJudgements>0: |
|---|
| 2604 | numTracks = self._abstract.getNumTracks() |
|---|
| 2605 | if numTracks == numJudgements: |
|---|
| 2606 | if numAccepts == 1: |
|---|
| 2607 | s = AbstractStatusProposedToAccept |
|---|
| 2608 | elif numAccepts == 0: |
|---|
| 2609 | s = AbstractStatusProposedToReject |
|---|
| 2610 | else: |
|---|
| 2611 | s = AbstractStatusInConflict |
|---|
| 2612 | else: |
|---|
| 2613 | s=AbstractStatusUnderReview |
|---|
| 2614 | else: |
|---|
| 2615 | s=AbstractStatusSubmitted |
|---|
| 2616 | return s |
|---|
| 2617 | |
|---|
| 2618 | |
|---|
| 2619 | def update( self ): |
|---|
| 2620 | """ |
|---|
| 2621 | """ |
|---|
| 2622 | newStatusClass = self._getStatusClass() |
|---|
| 2623 | if self.__class__ != newStatusClass: |
|---|
| 2624 | self.getAbstract().setCurrentStatus( newStatusClass( self._abstract ) ) |
|---|
| 2625 | |
|---|
| 2626 | def proposeToAccept( self ): |
|---|
| 2627 | """ |
|---|
| 2628 | """ |
|---|
| 2629 | s = self._getStatusClass()( self._abstract ) |
|---|
| 2630 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 2631 | |
|---|
| 2632 | def proposeToReject( self ): |
|---|
| 2633 | """ |
|---|
| 2634 | """ |
|---|
| 2635 | s = self._getStatusClass()( self._abstract ) |
|---|
| 2636 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 2637 | |
|---|
| 2638 | def proposeToReallocate( self ): |
|---|
| 2639 | """ |
|---|
| 2640 | """ |
|---|
| 2641 | s = self._getStatusClass()( self._abstract ) |
|---|
| 2642 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 2643 | |
|---|
| 2644 | def withdraw(self,resp,comments=""): |
|---|
| 2645 | """ |
|---|
| 2646 | """ |
|---|
| 2647 | s=AbstractStatusWithdrawn(self.getAbstract(), resp, self, comments) |
|---|
| 2648 | self.getAbstract().setCurrentStatus(s) |
|---|
| 2649 | |
|---|
| 2650 | def recover( self ): |
|---|
| 2651 | """ |
|---|
| 2652 | """ |
|---|
| 2653 | raise MaKaCError( _("only withdrawn abstracts can be recovered")) |
|---|
| 2654 | |
|---|
| 2655 | def markAsDuplicated(self,responsible,originalAbs,comments=""): |
|---|
| 2656 | """ |
|---|
| 2657 | """ |
|---|
| 2658 | if self.getAbstract()==originalAbs: |
|---|
| 2659 | raise MaKaCError( _("the original abstract is the same as the duplicated one")) |
|---|
| 2660 | if isinstance(originalAbs.getCurrentStatus(),AbstractStatusDuplicated): |
|---|
| 2661 | raise MaKaCError( _("cannot set as original abstract one which is already marked as duplicated")) |
|---|
| 2662 | s=AbstractStatusDuplicated(self.getAbstract(),responsible,originalAbs,comments) |
|---|
| 2663 | self.getAbstract().setCurrentStatus(s) |
|---|
| 2664 | |
|---|
| 2665 | def unMarkAsDuplicated(self,responsible,comments=""): |
|---|
| 2666 | """ |
|---|
| 2667 | """ |
|---|
| 2668 | raise MaKaCError( _("Only duplicated abstract can be unmark as duplicated")) |
|---|
| 2669 | |
|---|
| 2670 | def mergeInto(self,responsible,targetAbs,comments=""): |
|---|
| 2671 | """ |
|---|
| 2672 | """ |
|---|
| 2673 | if self.getAbstract()==targetAbs: |
|---|
| 2674 | raise MaKaCError( _("An abstract cannot be merged into itself")) |
|---|
| 2675 | if targetAbs.getCurrentStatus().__class__ not in [AbstractStatusSubmitted,AbstractStatusUnderReview,AbstractStatusProposedToAccept,AbstractStatusProposedToReject,AbstractStatusInConflict]: |
|---|
| 2676 | raise MaKaCError(_("Target abstract is in a status which cannot receive mergings")) |
|---|
| 2677 | s=AbstractStatusMerged(self.getAbstract(),responsible,targetAbs,comments) |
|---|
| 2678 | self.getAbstract().setCurrentStatus(s) |
|---|
| 2679 | |
|---|
| 2680 | def unMerge(self,responsible,comments=""): |
|---|
| 2681 | """ |
|---|
| 2682 | """ |
|---|
| 2683 | raise MaKaCError( _("Only merged abstracts can be unmerged")) |
|---|
| 2684 | |
|---|
| 2685 | |
|---|
| 2686 | |
|---|
| 2687 | class AbstractStatusSubmitted( AbstractStatus ): |
|---|
| 2688 | """ |
|---|
| 2689 | """ |
|---|
| 2690 | |
|---|
| 2691 | def clone(self,abstract): |
|---|
| 2692 | ass = AbstractStatusSubmitted(abstract) |
|---|
| 2693 | return ass |
|---|
| 2694 | |
|---|
| 2695 | def update( self ): |
|---|
| 2696 | #if an abstract that has been submitted has no judgement it |
|---|
| 2697 | # must remain in the submitted status |
|---|
| 2698 | if self._abstract.getNumJudgements() == 0: |
|---|
| 2699 | return |
|---|
| 2700 | AbstractStatus.update( self ) |
|---|
| 2701 | |
|---|
| 2702 | |
|---|
| 2703 | class AbstractStatusAccepted( AbstractStatus ): |
|---|
| 2704 | """ |
|---|
| 2705 | """ |
|---|
| 2706 | def __init__(self,abstract,responsible,destTrack,type,comments=""): |
|---|
| 2707 | AbstractStatus.__init__( self, abstract ) |
|---|
| 2708 | self._setResponsible( responsible ) |
|---|
| 2709 | self._setTrack( destTrack ) |
|---|
| 2710 | self._setComments( comments ) |
|---|
| 2711 | self._setType( type ) |
|---|
| 2712 | self._contrib = None |
|---|
| 2713 | |
|---|
| 2714 | def clone(self,abstract): |
|---|
| 2715 | asa = AbstractStatusAccepted(abstract,self.getResponsible(), self.getTrack(), self.getType(), self.getComments()) |
|---|
| 2716 | return asa |
|---|
| 2717 | |
|---|
| 2718 | def _setResponsible( self, res ): |
|---|
| 2719 | self._responsible = res |
|---|
| 2720 | |
|---|
| 2721 | def getResponsible( self ): |
|---|
| 2722 | return self._responsible |
|---|
| 2723 | |
|---|
| 2724 | def _setComments( self, comments ): |
|---|
| 2725 | self._comments = str( comments ).strip() |
|---|
| 2726 | |
|---|
| 2727 | def getComments( self ): |
|---|
| 2728 | try: |
|---|
| 2729 | if self._comments: |
|---|
| 2730 | pass |
|---|
| 2731 | except AttributeError: |
|---|
| 2732 | self._comments = "" |
|---|
| 2733 | return self._comments |
|---|
| 2734 | |
|---|
| 2735 | def _setTrack( self, track ): |
|---|
| 2736 | self._track = track |
|---|
| 2737 | |
|---|
| 2738 | def getTrack( self ): |
|---|
| 2739 | try: |
|---|
| 2740 | if self._track: |
|---|
| 2741 | pass |
|---|
| 2742 | except AttributeError: |
|---|
| 2743 | self._track = None |
|---|
| 2744 | return self._track |
|---|
| 2745 | |
|---|
| 2746 | def _setType( self, type ): |
|---|
| 2747 | self._contribType = type |
|---|
| 2748 | |
|---|
| 2749 | def getType( self ): |
|---|
| 2750 | try: |
|---|
| 2751 | if self._contribType: |
|---|
| 2752 | pass |
|---|
| 2753 | except AttributeError: |
|---|
| 2754 | self._contribType = None |
|---|
| 2755 | return self._contribType |
|---|
| 2756 | |
|---|
| 2757 | def setContribution( self, newContrib ): |
|---|
| 2758 | self._contrib = newContrib |
|---|
| 2759 | |
|---|
| 2760 | def getContribution( self ): |
|---|
| 2761 | try: |
|---|
| 2762 | if self._contrib: |
|---|
| 2763 | pass |
|---|
| 2764 | except AttributeError: |
|---|
| 2765 | self._contrib = None |
|---|
| 2766 | return self._contrib |
|---|
| 2767 | |
|---|
| 2768 | def update( self ): |
|---|
| 2769 | return |
|---|
| 2770 | |
|---|
| 2771 | def accept(self,responsible,destTrack,type,comments="" ): |
|---|
| 2772 | raise MaKaCError( _("Cannot accept an abstract which is already accepted")) |
|---|
| 2773 | |
|---|
| 2774 | def reject( self, responsible, comments="" ): |
|---|
| 2775 | raise MaKaCError( _("Cannot reject an abstract which is already accepted")) |
|---|
| 2776 | |
|---|
| 2777 | def proposeToAccept( self ): |
|---|
| 2778 | raise MaKaCError( _("Cannot propose for acceptance an abstract which is already accepted")) |
|---|
| 2779 | |
|---|
| 2780 | def proposeToReject( self ): |
|---|
| 2781 | raise MaKaCError( _("Cannot propose for rejection an abstract which is already accepted")) |
|---|
| 2782 | |
|---|
| 2783 | def proposeToReallocate( self ): |
|---|
| 2784 | raise MaKaCError( _("Cannot propose for reallocation an abstract which is already accepted")) |
|---|
| 2785 | |
|---|
| 2786 | #def withdraw( self, comments="" ): |
|---|
| 2787 | # raise MaKaCError( "Cannot withdraw an ACCEPTED abstract" ) |
|---|
| 2788 | |
|---|
| 2789 | def markAsDuplicated(self,responsible,originalAbs,comments=""): |
|---|
| 2790 | raise MaKaCError( _("Cannot mark as duplicated an abstract which is accepted")) |
|---|
| 2791 | |
|---|
| 2792 | def unMarkAsDuplicated(self,responsible,comments=""): |
|---|
| 2793 | """ |
|---|
| 2794 | """ |
|---|
| 2795 | raise MaKaCError( _("Only duplicated abstract can be unmark as duplicated")) |
|---|
| 2796 | |
|---|
| 2797 | def mergeInto(self,responsible,targetAbs,comments=""): |
|---|
| 2798 | raise MaKaCError( _("Cannot merge an abstract which is already accepted")) |
|---|
| 2799 | |
|---|
| 2800 | def withdraw(self,resp,comments=""): |
|---|
| 2801 | """ |
|---|
| 2802 | """ |
|---|
| 2803 | contrib=self.getContribution() |
|---|
| 2804 | #this import is made here and not at the top of the file in order to |
|---|
| 2805 | # avoid recursive import troubles |
|---|
| 2806 | from MaKaC.conference import ContribStatusWithdrawn |
|---|
| 2807 | if contrib is not None and \ |
|---|
| 2808 | not isinstance(contrib.getCurrentStatus(),ContribStatusWithdrawn): |
|---|
| 2809 | contrib.withdraw(resp, _(""" _("abstract withdrawn"): %s""")%comments) |
|---|
| 2810 | AbstractStatus.withdraw(self,resp,comments) |
|---|
| 2811 | |
|---|
| 2812 | |
|---|
| 2813 | class AbstractStatusRejected( AbstractStatus ): |
|---|
| 2814 | """ |
|---|
| 2815 | """ |
|---|
| 2816 | def __init__( self, abstract, responsible, comments = "" ): |
|---|
| 2817 | AbstractStatus.__init__( self, abstract ) |
|---|
| 2818 | self._setResponsible( responsible ) |
|---|
| 2819 | self._setComments( comments ) |
|---|
| 2820 | |
|---|
| 2821 | def clone(self,abstract): |
|---|
| 2822 | asr = AbstractStatusRejected(abstract, self.getResponsible(), self.getComments()) |
|---|
| 2823 | return asr |
|---|
| 2824 | |
|---|
| 2825 | def _setResponsible( self, res ): |
|---|
| 2826 | self._responsible = res |
|---|
| 2827 | |
|---|
| 2828 | def getResponsible( self ): |
|---|
| 2829 | return self._responsible |
|---|
| 2830 | |
|---|
| 2831 | def _setComments( self, comments ): |
|---|
| 2832 | self._comments = str( comments ).strip() |
|---|
| 2833 | |
|---|
| 2834 | def getComments( self ): |
|---|
| 2835 | try: |
|---|
| 2836 | if self._comments: |
|---|
| 2837 | pass |
|---|
| 2838 | except AttributeError: |
|---|
| 2839 | self._comments = "" |
|---|
| 2840 | return self._comments |
|---|
| 2841 | |
|---|
| 2842 | def update( self ): |
|---|
| 2843 | return |
|---|
| 2844 | |
|---|
| 2845 | def reject( self, responsible, comments="" ): |
|---|
| 2846 | raise MaKaCError( _("Cannot reject an abstract which is already rejected")) |
|---|
| 2847 | |
|---|
| 2848 | def proposeToAccept( self ): |
|---|
| 2849 | raise MaKaCError( _("Cannot propose for acceptance an abstract which is already rejected")) |
|---|
| 2850 | |
|---|
| 2851 | def proposeToReject( self ): |
|---|
| 2852 | raise MaKaCError( _("Cannot propose for rejection an abstract which is already rejected")) |
|---|
| 2853 | |
|---|
| 2854 | def proposeToReallocate( self ): |
|---|
| 2855 | raise MaKaCError( _("Cannot propose for reallocation an abstract which is already rejected")) |
|---|
| 2856 | |
|---|
| 2857 | def withdraw(self,resp,comments=""): |
|---|
| 2858 | raise MaKaCError( _("Cannot withdraw a REJECTED abstract")) |
|---|
| 2859 | |
|---|
| 2860 | def markAsDuplicated(self,responsible,originalAbs,comments=""): |
|---|
| 2861 | raise MaKaCError( _("Cannot mark as duplicated an abstract which is rejected")) |
|---|
| 2862 | |
|---|
| 2863 | def unMarkAsDuplicated(self,responsible,comments=""): |
|---|
| 2864 | """ |
|---|
| 2865 | """ |
|---|
| 2866 | raise MaKaCError( _("Only duplicated abstract can be unmark as duplicated")) |
|---|
| 2867 | |
|---|
| 2868 | def mergeInto(self,responsible,targetAbs,comments=""): |
|---|
| 2869 | raise MaKaCError( _("Cannot merge an abstract which is rejected")) |
|---|
| 2870 | |
|---|
| 2871 | |
|---|
| 2872 | class AbstractStatusUnderReview( AbstractStatus ): |
|---|
| 2873 | """ |
|---|
| 2874 | """ |
|---|
| 2875 | def clone(self,abstract): |
|---|
| 2876 | asur = AbstractStatusUnderReview(abstract) |
|---|
| 2877 | return asur |
|---|
| 2878 | |
|---|
| 2879 | class AbstractStatusProposedToAccept( AbstractStatus ): |
|---|
| 2880 | """ |
|---|
| 2881 | """ |
|---|
| 2882 | def clone(self, abstract): |
|---|
| 2883 | aspta = AbstractStatusProposedToAccept(abstract) |
|---|
| 2884 | return aspta |
|---|
| 2885 | |
|---|
| 2886 | def getTrack(self): |
|---|
| 2887 | jud=self.getAbstract().getTrackAcceptanceList()[0] |
|---|
| 2888 | return jud.getTrack() |
|---|
| 2889 | |
|---|
| 2890 | def getType(self): |
|---|
| 2891 | jud=self.getAbstract().getTrackAcceptanceList()[0] |
|---|
| 2892 | return jud.getContribType() |
|---|
| 2893 | |
|---|
| 2894 | |
|---|
| 2895 | class AbstractStatusProposedToReject( AbstractStatus ): |
|---|
| 2896 | """ |
|---|
| 2897 | """ |
|---|
| 2898 | def clone(self, abstract): |
|---|
| 2899 | asptr = AbstractStatusProposedToReject(abstract) |
|---|
| 2900 | return asptr |
|---|
| 2901 | |
|---|
| 2902 | class AbstractStatusInConflict( AbstractStatus ): |
|---|
| 2903 | """ |
|---|
| 2904 | """ |
|---|
| 2905 | def clone(self,abstract): |
|---|
| 2906 | asic = AbstractStatusInConflict(abstract) |
|---|
| 2907 | return asic |
|---|
| 2908 | |
|---|
| 2909 | class AbstractStatusWithdrawn(AbstractStatus): |
|---|
| 2910 | """ |
|---|
| 2911 | """ |
|---|
| 2912 | def __init__(self,abstract,responsible, prevStatus,comments=""): |
|---|
| 2913 | AbstractStatus.__init__(self,abstract) |
|---|
| 2914 | self._setComments(comments) |
|---|
| 2915 | self._setResponsible(responsible) |
|---|
| 2916 | self._prevStatus=prevStatus |
|---|
| 2917 | |
|---|
| 2918 | def clone(self,abstract): |
|---|
| 2919 | asw = AbstractStatusWithdrawn(abstract,self.getResponsible(),self.getComments()) |
|---|
| 2920 | return asw |
|---|
| 2921 | |
|---|
| 2922 | def _setResponsible(self,newResp): |
|---|
| 2923 | self._responsible=newResp |
|---|
| 2924 | |
|---|
| 2925 | def getResponsible(self): |
|---|
| 2926 | try: |
|---|
| 2927 | if self._responsible: |
|---|
| 2928 | pass |
|---|
| 2929 | except AttributeError,e: |
|---|
| 2930 | self._responsible=self._abstract.getSubmitter().getAvatar() |
|---|
| 2931 | return self._responsible |
|---|
| 2932 | |
|---|
| 2933 | def getPrevStatus(self): |
|---|
| 2934 | try: |
|---|
| 2935 | if self._prevStatus: |
|---|
| 2936 | pass |
|---|
| 2937 | except AttributeError,e: |
|---|
| 2938 | self._prevStatus=None |
|---|
| 2939 | return self._prevStatus |
|---|
| 2940 | |
|---|
| 2941 | def _setComments( self, comments ): |
|---|
| 2942 | self._comments = str( comments ).strip() |
|---|
| 2943 | |
|---|
| 2944 | def getComments( self ): |
|---|
| 2945 | return self._comments |
|---|
| 2946 | |
|---|
| 2947 | def update( self ): |
|---|
| 2948 | return |
|---|
| 2949 | |
|---|
| 2950 | def accept(self,responsible,destTrack,type,comments=""): |
|---|
| 2951 | raise MaKaCError( _("Cannot accept an abstract wich is withdrawn")) |
|---|
| 2952 | |
|---|
| 2953 | def reject( self, responsible, comments="" ): |
|---|
| 2954 | raise MaKaCError( _("Cannot reject an abstract which is withdrawn")) |
|---|
| 2955 | |
|---|
| 2956 | def proposeToAccept( self ): |
|---|
| 2957 | raise MaKaCError( _("Cannot propose for acceptance an abstract which withdrawn")) |
|---|
| 2958 | |
|---|
| 2959 | def proposeToReject( self ): |
|---|
| 2960 | raise MaKaCError( _("Cannot propose for rejection an abstract which is withdrawn")) |
|---|
| 2961 | |
|---|
| 2962 | def recover( self ): |
|---|
| 2963 | if self.getPrevStatus() is None: |
|---|
| 2964 | # reset all the judgments |
|---|
| 2965 | self._clearTrackAcceptances() |
|---|
| 2966 | self._clearTrackRejections() |
|---|
| 2967 | self._clearTrackReallocations() |
|---|
| 2968 | # setting the status |
|---|
| 2969 | contrib=self.getAbstract().getContribution() |
|---|
| 2970 | if contrib is None: |
|---|
| 2971 | s = AbstractStatusSubmitted( self.getAbstract() ) |
|---|
| 2972 | else: |
|---|
| 2973 | s = AbstractStatusAccepted(self.getAbstract(),self.getResponsible(),contrib.getTrack(),contrib.getType(),"") |
|---|
| 2974 | else: |
|---|
| 2975 | contrib=self.getAbstract().getContribution() |
|---|
| 2976 | if contrib is not None and not isinstance(self.getPrevStatus(), AbstractStatusAccepted): |
|---|
| 2977 | s = AbstractStatusAccepted(self.getAbstract(),self.getResponsible(),contrib.getTrack(),contrib.getType(),"") |
|---|
| 2978 | else: |
|---|
| 2979 | s=self.getPrevStatus() |
|---|
| 2980 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 2981 | |
|---|
| 2982 | def markAsDuplicated(self,responsible,originalAbs,comments=""): |
|---|
| 2983 | raise MaKaCError( _("Cannot mark as duplicated an abstract which is withdrawn")) |
|---|
| 2984 | |
|---|
| 2985 | def unMarkAsDuplicated(self,responsible,comments=""): |
|---|
| 2986 | """ |
|---|
| 2987 | """ |
|---|
| 2988 | raise MaKaCError( _("Only duplicated abstract can be unmark as duplicated")) |
|---|
| 2989 | |
|---|
| 2990 | def mergeInto(self,responsible,targetAbs,comments=""): |
|---|
| 2991 | raise MaKaCError( _("Cannot merge an abstract which is withdrawn")) |
|---|
| 2992 | |
|---|
| 2993 | def withdraw(self,resp,comments=""): |
|---|
| 2994 | raise MaKaCError( _("This abstract is already withdrawn")) |
|---|
| 2995 | |
|---|
| 2996 | |
|---|
| 2997 | |
|---|
| 2998 | class AbstractStatusDuplicated(AbstractStatus): |
|---|
| 2999 | """ |
|---|
| 3000 | """ |
|---|
| 3001 | def __init__( self,abstract,responsible,originalAbstract,comments=""): |
|---|
| 3002 | AbstractStatus.__init__(self,abstract) |
|---|
| 3003 | self._setResponsible(responsible) |
|---|
| 3004 | self._setComments(comments) |
|---|
| 3005 | self._setOriginalAbstract(originalAbstract) |
|---|
| 3006 | |
|---|
| 3007 | def clone(self, abstract): |
|---|
| 3008 | asd = AbstractStatusDuplicated(abstract,self.getResponsible(),self.getOriginal(),self.getComments()) |
|---|
| 3009 | return asd |
|---|
| 3010 | |
|---|
| 3011 | def _setResponsible( self, res ): |
|---|
| 3012 | self._responsible = res |
|---|
| 3013 | |
|---|
| 3014 | def getResponsible(self): |
|---|
| 3015 | return self._responsible |
|---|
| 3016 | |
|---|
| 3017 | def _setComments( self, comments ): |
|---|
| 3018 | self._comments = str( comments ).strip() |
|---|
| 3019 | |
|---|
| 3020 | def getComments( self ): |
|---|
| 3021 | return self._comments |
|---|
| 3022 | |
|---|
| 3023 | def _setOriginalAbstract(self,abs): |
|---|
| 3024 | self._original=abs |
|---|
| 3025 | |
|---|
| 3026 | def getOriginal(self): |
|---|
| 3027 | return self._original |
|---|
| 3028 | |
|---|
| 3029 | def update( self ): |
|---|
| 3030 | return |
|---|
| 3031 | |
|---|
| 3032 | def reject( self, responsible, comments="" ): |
|---|
| 3033 | raise MaKaCError( _("Cannot reject an abstract which is duplicated")) |
|---|
| 3034 | |
|---|
| 3035 | def proposeToAccept( self ): |
|---|
| 3036 | raise MaKaCError( _("Cannot propose for acceptance an abstract which is duplicated")) |
|---|
| 3037 | |
|---|
| 3038 | def proposeToReject( self ): |
|---|
| 3039 | raise MaKaCError( _("Cannot propose for rejection an abstract which is duplicated")) |
|---|
| 3040 | |
|---|
| 3041 | def proposeToReallocate( self ): |
|---|
| 3042 | raise MaKaCError( _("Cannot propose for reallocation an abstract which is duplicated")) |
|---|
| 3043 | |
|---|
| 3044 | def withdraw(self,resp,comments=""): |
|---|
| 3045 | raise MaKaCError( _("Cannot withdraw a duplicated abstract")) |
|---|
| 3046 | |
|---|
| 3047 | def markAsDuplicated(self,responsible,originalAbs,comments=""): |
|---|
| 3048 | raise MaKaCError( _("This abstract is already duplicated")) |
|---|
| 3049 | |
|---|
| 3050 | def unMarkAsDuplicated(self,responsible,comments=""): |
|---|
| 3051 | s = AbstractStatusSubmitted( self.getAbstract() ) |
|---|
| 3052 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 3053 | |
|---|
| 3054 | def mergeInto(self,responsible,targetAbs,comments=""): |
|---|
| 3055 | raise MaKaCError( _("Cannot merge an abstract which is marked as a duplicate")) |
|---|
| 3056 | |
|---|
| 3057 | |
|---|
| 3058 | class AbstractStatusMerged(AbstractStatus): |
|---|
| 3059 | """ |
|---|
| 3060 | """ |
|---|
| 3061 | |
|---|
| 3062 | def __init__(self,abstract,responsible,targetAbstract,comments=""): |
|---|
| 3063 | AbstractStatus.__init__(self,abstract) |
|---|
| 3064 | self._setResponsible(responsible) |
|---|
| 3065 | self._setComments(comments) |
|---|
| 3066 | self._setTargetAbstract(targetAbstract) |
|---|
| 3067 | |
|---|
| 3068 | def clone(self,abstract): |
|---|
| 3069 | asm = AbstractStatusMerged(abstract,self.getResponsible(),self.getTargetAbstract(),self.getComments()) |
|---|
| 3070 | return asm |
|---|
| 3071 | |
|---|
| 3072 | def _setResponsible( self, res ): |
|---|
| 3073 | self._responsible = res |
|---|
| 3074 | |
|---|
| 3075 | def getResponsible( self ): |
|---|
| 3076 | return self._responsible |
|---|
| 3077 | |
|---|
| 3078 | def _setComments( self, comments ): |
|---|
| 3079 | self._comments = str( comments ).strip() |
|---|
| 3080 | |
|---|
| 3081 | def getComments( self ): |
|---|
| 3082 | return self._comments |
|---|
| 3083 | |
|---|
| 3084 | def _setTargetAbstract(self,abstract): |
|---|
| 3085 | self._target=abstract |
|---|
| 3086 | |
|---|
| 3087 | def getTargetAbstract(self): |
|---|
| 3088 | return self._target |
|---|
| 3089 | |
|---|
| 3090 | def update( self ): |
|---|
| 3091 | return |
|---|
| 3092 | |
|---|
| 3093 | def reject( self, responsible, comments="" ): |
|---|
| 3094 | raise MaKaCError( _("Cannot reject an abstract which is merged into another one")) |
|---|
| 3095 | |
|---|
| 3096 | def proposeToAccept( self ): |
|---|
| 3097 | raise MaKaCError( _("Cannot propose for acceptance an abstract which is merged into another one")) |
|---|
| 3098 | |
|---|
| 3099 | def proposeToReject( self ): |
|---|
| 3100 | raise MaKaCError( _("Cannot propose for rejection an abstract which is merged into another one")) |
|---|
| 3101 | |
|---|
| 3102 | def proposeToReallocate( self ): |
|---|
| 3103 | raise MaKaCError( _("Cannot propose for reallocation an abstract which is merged into another one")) |
|---|
| 3104 | |
|---|
| 3105 | def withdraw(self,resp,comments=""): |
|---|
| 3106 | raise MaKaCError( _("Cannot withdraw an abstract which is merged into another one")) |
|---|
| 3107 | |
|---|
| 3108 | def markAsDuplicated(self,responsible,originalAbs,comments=""): |
|---|
| 3109 | raise MaKaCError( _("Cannot mark as duplicated an abstract which is merged into another one")) |
|---|
| 3110 | |
|---|
| 3111 | def unMarkAsDuplicated(self,responsible,comments=""): |
|---|
| 3112 | """ |
|---|
| 3113 | """ |
|---|
| 3114 | raise MaKaCError( _("Only duplicated abstract can be unmark as duplicated")) |
|---|
| 3115 | |
|---|
| 3116 | def mergeInto(self,responsible,target,comments=""): |
|---|
| 3117 | raise MaKaCError( _("This abstract is already merged into another one")) |
|---|
| 3118 | |
|---|
| 3119 | def unMerge(self,responsible,comments=""): |
|---|
| 3120 | s = AbstractStatusSubmitted( self.getAbstract() ) |
|---|
| 3121 | self.getAbstract().setCurrentStatus( s ) |
|---|
| 3122 | |
|---|
| 3123 | class AbstractStatusNone(AbstractStatus): |
|---|
| 3124 | # This is a special status we assign to abstracts that are put in the trash can. |
|---|
| 3125 | |
|---|
| 3126 | def __init__(self,abstract): |
|---|
| 3127 | AbstractStatus.__init__(self,abstract) |
|---|
| 3128 | |
|---|
| 3129 | def clone(self,abstract): |
|---|
| 3130 | asn = AbstractStatusNone(abstract) |
|---|
| 3131 | return asn |
|---|
| 3132 | |
|---|
| 3133 | class NotificationTemplate(Persistent): |
|---|
| 3134 | |
|---|
| 3135 | def __init__(self): |
|---|
| 3136 | self._owner=None |
|---|
| 3137 | self._id="" |
|---|
| 3138 | self._name="" |
|---|
| 3139 | self._description="" |
|---|
| 3140 | self._tplSubject="" |
|---|
| 3141 | self._tplBody="" |
|---|
| 3142 | self._fromAddr = "" |
|---|
| 3143 | self._ccAddrList=PersistentList() |
|---|
| 3144 | self._toAddrs = PersistentList() |
|---|
| 3145 | self._conditions=PersistentList() |
|---|
| 3146 | self._toAddrGenerator=Counter() |
|---|
| 3147 | self._condGenerator=Counter() |
|---|
| 3148 | |
|---|
| 3149 | def clone(self): |
|---|
| 3150 | tpl = NotificationTemplate() |
|---|
| 3151 | tpl.setName(self.getName()) |
|---|
| 3152 | tpl.setDescription(self.getDescription()) |
|---|
| 3153 | tpl.setTplSubject(self.getTplSubject()) |
|---|
| 3154 | tpl.setTplBody(self.getTplBody()) |
|---|
| 3155 | tpl.setFromAddr(self.getFromAddr()) |
|---|
| 3156 | |
|---|
| 3157 | for cc in self.getCCAddrList() : |
|---|
| 3158 | tpl.addCCAddr(cc) |
|---|
| 3159 | for to in self.getToAddrList() : |
|---|
| 3160 | tpl.addToAddr(to) |
|---|
| 3161 | |
|---|
| 3162 | for con in self.getConditionList() : |
|---|
| 3163 | tpl.addCondition(con.clone(tpl)) |
|---|
| 3164 | |
|---|
| 3165 | # kto to jest OWNER..?? |
|---|
| 3166 | # bo nie konferencja..!! |
|---|
| 3167 | |
|---|
| 3168 | return tpl |
|---|
| 3169 | |
|---|
| 3170 | def delete(self): |
|---|
| 3171 | self.clearToAddrs() |
|---|
| 3172 | self.clearCCAddrList() |
|---|
| 3173 | self.clearConditionList() |
|---|
| 3174 | TrashCanManager().add(self) |
|---|
| 3175 | |
|---|
| 3176 | def recover(self): |
|---|
| 3177 | TrashCanManager().remove(self) |
|---|
| 3178 | |
|---|
| 3179 | ## def getResponsible( self ): |
|---|
| 3180 | ## return self._responsible |
|---|
| 3181 | ## |
|---|
| 3182 | ## def _setComments( self, comments ): |
|---|
| 3183 | ## self._comments = str( comments ).strip() |
|---|
| 3184 | ## |
|---|
| 3185 | ## def getComments( self ): |
|---|
| 3186 | ## return self._comments |
|---|
| 3187 | ## |
|---|
| 3188 | ## def _setOriginalAbstract(self,abstract): |
|---|
| 3189 | ## self._original=abstract |
|---|
| 3190 | |
|---|
| 3191 | def canModify(self, aw): |
|---|
| 3192 | return self.getConference().canModify(aw) |
|---|
| 3193 | |
|---|
| 3194 | def getLocator(self): |
|---|
| 3195 | loc = self.getOwner().getConference().getLocator() |
|---|
| 3196 | loc["notifTplId"] = self._id |
|---|
| 3197 | return loc |
|---|
| 3198 | |
|---|
| 3199 | def getConference(self): |
|---|
| 3200 | return self._owner.getConference() |
|---|
| 3201 | |
|---|
| 3202 | def includeInOwner(self,owner,id): |
|---|
| 3203 | self._owner=owner |
|---|
| 3204 | self._id=id |
|---|
| 3205 | |
|---|
| 3206 | def getOwner(self): |
|---|
| 3207 | return self._owner |
|---|
| 3208 | |
|---|
| 3209 | def getId(self): |
|---|
| 3210 | return self._id |
|---|
| 3211 | |
|---|
| 3212 | def setName(self,newName): |
|---|
| 3213 | self._name=newName.strip() |
|---|
| 3214 | |
|---|
| 3215 | def getName(self): |
|---|
| 3216 | return self._name |
|---|
| 3217 | |
|---|
| 3218 | def setDescription(self,newDesc): |
|---|
| 3219 | self._description=newDesc.strip() |
|---|
| 3220 | |
|---|
| 3221 | def getDescription(self): |
|---|
| 3222 | return self._description |
|---|
| 3223 | |
|---|
| 3224 | def setTplSubject(self,newSubject, varList): |
|---|
| 3225 | self._tplSubject=self.parseTplContent(newSubject, varList).strip() |
|---|
| 3226 | |
|---|
| 3227 | def getTplSubject(self): |
|---|
| 3228 | return self._tplSubject |
|---|
| 3229 | |
|---|
| 3230 | def getTplSubjectShow(self, varList): |
|---|
| 3231 | return self.parseTplContentUndo(self._tplSubject, varList) |
|---|
| 3232 | |
|---|
| 3233 | def setTplBody(self,newBody, varList): |
|---|
| 3234 | self._tplBody=self.parseTplContent(newBody, varList).strip() |
|---|
| 3235 | |
|---|
| 3236 | def getTplBody(self): |
|---|
| 3237 | return self._tplBody |
|---|
| 3238 | |
|---|
| 3239 | def getTplBodyShow(self, varList): |
|---|
| 3240 | return self.parseTplContentUndo(self._tplBody, varList) |
|---|
| 3241 | |
|---|
| 3242 | def getCCAddrList(self): |
|---|
| 3243 | try: |
|---|
| 3244 | if self._ccAddrList: |
|---|
| 3245 | pass |
|---|
| 3246 | except AttributeError: |
|---|
| 3247 | self._ccAddrList=PersistentList() |
|---|
| 3248 | return self._ccAddrList |
|---|
| 3249 | |
|---|
| 3250 | def addCCAddr(self,newAddr): |
|---|
| 3251 | try: |
|---|
| 3252 | if self._ccAddrList: |
|---|
| 3253 | pass |
|---|
| 3254 | except AttributeError: |
|---|
| 3255 | self._ccAddrList=PersistentList() |
|---|
| 3256 | ccAddr=newAddr.strip() |
|---|
| 3257 | if ccAddr!="" and ccAddr not in self._ccAddrList: |
|---|
| 3258 | self._ccAddrList.append(ccAddr) |
|---|
| 3259 | |
|---|
| 3260 | def setCCAddrList(self,l): |
|---|
| 3261 | self.clearCCAddrList() |
|---|
| 3262 | for addr in l: |
|---|
| 3263 | self.addCCAddr(addr) |
|---|
| 3264 | |
|---|
| 3265 | def clearCCAddrList(self): |
|---|
| 3266 | self._ccAddrList=PersistentList() |
|---|
| 3267 | |
|---|
| 3268 | def getFromAddr(self): |
|---|
| 3269 | try: |
|---|
| 3270 | return self._fromAddr |
|---|
| 3271 | except AttributeError: |
|---|
| 3272 | self._fromAddr = self._owner.getConference().getSupportEmail() |
|---|
| 3273 | return self._fromAddr |
|---|
| 3274 | |
|---|
| 3275 | def setFromAddr(self, addr): |
|---|
| 3276 | self._fromAddr = addr |
|---|
| 3277 | |
|---|
| 3278 | def addToAddr(self,toAddr): |
|---|
| 3279 | """ |
|---|
| 3280 | """ |
|---|
| 3281 | if self.hasToAddr(toAddr.__class__): |
|---|
| 3282 | return |
|---|
| 3283 | try: |
|---|
| 3284 | if self._toAddrGenerator: |
|---|
| 3285 | pass |
|---|
| 3286 | except AttributeError, e: |
|---|
| 3287 | self._toAddrGenerator = Counter() |
|---|
| 3288 | id = toAddr.getId() |
|---|
| 3289 | if id == -1: |
|---|
| 3290 | id = int(self._toAddrGenerator.newCount()) |
|---|
| 3291 | toAddr.includeInTpl(self,id) |
|---|
| 3292 | self.getToAddrList().append(toAddr) |
|---|
| 3293 | |
|---|
| 3294 | def removeToAddr(self,toAddr): |
|---|
| 3295 | """ |
|---|
| 3296 | """ |
|---|
| 3297 | if not self.hasToAddr(toAddr.__class__): |
|---|
| 3298 | return |
|---|
| 3299 | self.getToAddrList().remove(toAddr) |
|---|
| 3300 | toAddr.includeInTpl(None,toAddr.getId()) |
|---|
| 3301 | toAddr.delete() |
|---|
| 3302 | |
|---|
| 3303 | def recoverToAddr(self, toAddr): |
|---|
| 3304 | self.addToAddr(toAddr) |
|---|
| 3305 | toAddr.recover() |
|---|
| 3306 | |
|---|
| 3307 | def getToAddrs(self, abs): |
|---|
| 3308 | users = [] |
|---|
| 3309 | for toAddr in self.getToAddrList(): |
|---|
| 3310 | users += toAddr.getToAddrList(abs) |
|---|
| 3311 | return users |
|---|
| 3312 | |
|---|
| 3313 | def getToAddrList(self): |
|---|
| 3314 | """ |
|---|
| 3315 | """ |
|---|
| 3316 | try: |
|---|
| 3317 | if self._toAddrs: |
|---|
| 3318 | pass |
|---|
| 3319 | except AttributeError, e: |
|---|
| 3320 | self._toAddrs = PersistentList() |
|---|
| 3321 | return self._toAddrs |
|---|
| 3322 | |
|---|
| 3323 | def getToAddrById(self,id): |
|---|
| 3324 | """ |
|---|
| 3325 | """ |
|---|
| 3326 | for toAddr in self.getToAddrList(): |
|---|
| 3327 | if toAddr.getId()==int(id): |
|---|
| 3328 | return toAddr |
|---|
| 3329 | return None |
|---|
| 3330 | |
|---|
| 3331 | def hasToAddr(self,toAddrKlass): |
|---|
| 3332 | """Returns True if the TPL contains a "toAddr" which class is "toAddrKlass" |
|---|
| 3333 | """ |
|---|
| 3334 | for toAddr in self.getToAddrList(): |
|---|
| 3335 | if toAddr.__class__ == toAddrKlass: |
|---|
| 3336 | return True |
|---|
| 3337 | return False |
|---|
| 3338 | |
|---|
| 3339 | def clearToAddrs(self): |
|---|
| 3340 | while(len(self.getToAddrList())>0): |
|---|
| 3341 | self.removeToAddr(self.getToAddrList()[0]) |
|---|
| 3342 | |
|---|
| 3343 | def addCondition(self,cond): |
|---|
| 3344 | """ |
|---|
| 3345 | """ |
|---|
| 3346 | if cond in self._conditions: |
|---|
| 3347 | return |
|---|
| 3348 | id = cond.getId() |
|---|
| 3349 | if id == -1: |
|---|
| 3350 | id = int(self._condGenerator.newCount()) |
|---|
| 3351 | cond.includeInTpl(self, id) |
|---|
| 3352 | self._conditions.append(cond) |
|---|
| 3353 | |
|---|
| 3354 | def removeCondition(self,cond): |
|---|
| 3355 | """ |
|---|
| 3356 | """ |
|---|
| 3357 | if cond not in self._conditions: |
|---|
| 3358 | return |
|---|
| 3359 | self._conditions.remove(cond) |
|---|
| 3360 | cond.delete() |
|---|
| 3361 | |
|---|
| 3362 | def recoverCondition(self, cond): |
|---|
| 3363 | self.addCondition(cond) |
|---|
| 3364 | cond.recover() |
|---|
| 3365 | |
|---|
| 3366 | def getConditionList(self): |
|---|
| 3367 | """ |
|---|
| 3368 | """ |
|---|
| 3369 | return self._conditions |
|---|
| 3370 | |
|---|
| 3371 | def getConditionById(self,id): |
|---|
| 3372 | """ |
|---|
| 3373 | """ |
|---|
| 3374 | for cond in self._conditions: |
|---|
| 3375 | if cond.getId()==int(id): |
|---|
| 3376 | return cond |
|---|
| 3377 | return None |
|---|
| 3378 | |
|---|
| 3379 | def clearConditionList(self): |
|---|
| 3380 | while(len(self.getConditionList())>0): |
|---|
| 3381 | self.removeCondition(self.getConditionList()[0]) |
|---|
| 3382 | |
|---|
| 3383 | def satisfies(self,abs): |
|---|
| 3384 | """ |
|---|
| 3385 | """ |
|---|
| 3386 | for cond in self._conditions: |
|---|
| 3387 | if cond.satisfies(abs): |
|---|
| 3388 | return True |
|---|
| 3389 | return False |
|---|
| 3390 | |
|---|
| 3391 | def parseTplContent(self, content, varList): |
|---|
| 3392 | # replace the % in order to avoid exceptions |
|---|
| 3393 | result = content.replace("%", "%%") |
|---|
| 3394 | # find the vars and make the expressions, it is necessary to do in reverse in order to find the longest tags first |
|---|
| 3395 | for var in varList: |
|---|
| 3396 | result = result.replace("|"+var.getName()+"|", "%("+var.getName()+")s") |
|---|
| 3397 | return result |
|---|
| 3398 | |
|---|
| 3399 | def parseTplContentUndo(self, content, varList): |
|---|
| 3400 | # The body content is shown without "%()" and with "%" in instead of "%%" but it is not modified |
|---|
| 3401 | result = content |
|---|
| 3402 | for var in varList: |
|---|
| 3403 | result = result.replace("%("+var.getName()+")s", "|"+var.getName()+"|") |
|---|
| 3404 | # replace the %% by % |
|---|
| 3405 | result = result.replace("%%", "%") |
|---|
| 3406 | return result |
|---|
| 3407 | |
|---|
| 3408 | class NotifTplToAddr(Persistent): |
|---|
| 3409 | """ |
|---|
| 3410 | """ |
|---|
| 3411 | |
|---|
| 3412 | def __init__(self): |
|---|
| 3413 | self._tpl=None |
|---|
| 3414 | self._id=-1 |
|---|
| 3415 | |
|---|
| 3416 | def clone(self): |
|---|
| 3417 | ntta = NotifTplToAddr() |
|---|
| 3418 | return ntta |
|---|
| 3419 | |
|---|
| 3420 | def delete(self): |
|---|
| 3421 | TrashCanManager().add(self) |
|---|
| 3422 | |
|---|
| 3423 | def recover(self): |
|---|
| 3424 | TrashCanManager().remove(self) |
|---|
| 3425 | |
|---|
| 3426 | def includeInTpl(self,newTpl,newId): |
|---|
| 3427 | self._tpl=newTpl |
|---|
| 3428 | self._id=newId |
|---|
| 3429 | |
|---|
| 3430 | def getTpl(self): |
|---|
| 3431 | return self._tpl |
|---|
| 3432 | |
|---|
| 3433 | def getId(self): |
|---|
| 3434 | return self._id |
|---|
| 3435 | |
|---|
| 3436 | def getToAddrList(self,absList): |
|---|
| 3437 | """ |
|---|
| 3438 | Return a list with all the emails for a group. |
|---|
| 3439 | """ |
|---|
| 3440 | return [] |
|---|
| 3441 | |
|---|
| 3442 | |
|---|
| 3443 | class NotifTplToAddrSubmitter(NotifTplToAddr): |
|---|
| 3444 | |
|---|
| 3445 | def getToAddrList(self,abs): |
|---|
| 3446 | l = [] |
|---|
| 3447 | l.append(abs.getSubmitter()) |
|---|
| 3448 | return l |
|---|
| 3449 | |
|---|
| 3450 | def clone(self): |
|---|
| 3451 | nttas = NotifTplToAddrSubmitter() |
|---|
| 3452 | return nttas |
|---|
| 3453 | |
|---|
| 3454 | class NotifTplToAddrPrimaryAuthors(NotifTplToAddr): |
|---|
| 3455 | |
|---|
| 3456 | def getToAddrList(self,abs): |
|---|
| 3457 | l = [] |
|---|
| 3458 | for pa in abs.getPrimaryAuthorList(): |
|---|
| 3459 | l.append(pa) |
|---|
| 3460 | return l |
|---|
| 3461 | |
|---|
| 3462 | def clone(self): |
|---|
| 3463 | nttapa = NotifTplToAddrPrimaryAuthors() |
|---|
| 3464 | return nttapa |
|---|
| 3465 | |
|---|
| 3466 | class NotifTplCondition(Persistent): |
|---|
| 3467 | """ |
|---|
| 3468 | """ |
|---|
| 3469 | |
|---|
| 3470 | def __init__(self): |
|---|
| 3471 | self._tpl=None |
|---|
| 3472 | self._id=-1 |
|---|
| 3473 | |
|---|
| 3474 | def clone(self, template): |
|---|
| 3475 | con = NotifyCondition() |
|---|
| 3476 | con.includeInTpl(template) |
|---|
| 3477 | return con |
|---|
| 3478 | |
|---|
| 3479 | def delete(self): |
|---|
| 3480 | TrashCanManager().add(self) |
|---|
| 3481 | |
|---|
| 3482 | def recover(self): |
|---|
| 3483 | TrashCanManager().remove(self) |
|---|
| 3484 | |
|---|
| 3485 | def includeInTpl(self,newTpl,newId): |
|---|
| 3486 | self._tpl=newTpl |
|---|
| 3487 | self._id=newId |
|---|
| 3488 | |
|---|
| 3489 | def getTpl(self): |
|---|
| 3490 | return self._tpl |
|---|
| 3491 | |
|---|
| 3492 | def getId(self): |
|---|
| 3493 | return self._id |
|---|
| 3494 | |
|---|
| 3495 | def satisfies(self,abs): |
|---|
| 3496 | return True |
|---|
| 3497 | |
|---|
| 3498 | |
|---|
| 3499 | class NotifTplCondAccepted(NotifTplCondition): |
|---|
| 3500 | |
|---|
| 3501 | def __init__(self,track="--any--",contribType="--any--"): |
|---|
| 3502 | NotifTplCondition.__init__(self) |
|---|
| 3503 | self._track=track |
|---|
| 3504 | self._contribType=contribType |
|---|
| 3505 | |
|---|
| 3506 | def clone(self, conference, template): |
|---|
| 3507 | ntca = NotifTplCondAccepted() |
|---|
| 3508 | for newtrack in conference.getTrackList() : |
|---|
| 3509 | if newtrack.getTitle() == self.getTrack().getTitle() : |
|---|
| 3510 | ntca.setTrack(newtrack) |
|---|
| 3511 | for newtype in conference.getContribTypeList() : |
|---|
| 3512 | if newtype.getName() == self.getContribType() : |
|---|
| 3513 | ntca.setContribType(newtype) |
|---|
| 3514 | |
|---|
| 3515 | return ntca |
|---|
| 3516 | |
|---|
| 3517 | def setContribType(self, ct="--any--"): |
|---|
| 3518 | self._contribType = ct |
|---|
| 3519 | |
|---|
| 3520 | def getContribType(self): |
|---|
| 3521 | return self._contribType |
|---|
| 3522 | |
|---|
| 3523 | def setTrack(self, tr="--any--"): |
|---|
| 3524 | self._track = tr |
|---|
| 3525 | |
|---|
| 3526 | def getTrack(self): |
|---|
| 3527 | try: |
|---|
| 3528 | if self._track: |
|---|
| 3529 | pass |
|---|
| 3530 | except AttributeError: |
|---|
| 3531 | self._track="--any--" |
|---|
| 3532 | return self._track |
|---|
| 3533 | |
|---|
| 3534 | def _satifiesContribType(self,abs): |
|---|
| 3535 | status=abs.getCurrentStatus() |
|---|
| 3536 | if self._contribType=="--any--": |
|---|
| 3537 | return True |
|---|
| 3538 | else: |
|---|
| 3539 | if self._contribType=="" or self._contribType==None or \ |
|---|
| 3540 | self._contribType=="--none--": |
|---|
| 3541 | return status.getType()=="" or status.getType()==None |
|---|
| 3542 | return status.getType()==self._contribType |
|---|
| 3543 | return False |
|---|
| 3544 | |
|---|
| 3545 | def _satifiesTrack(self,abs): |
|---|
| 3546 | status=abs.getCurrentStatus() |
|---|
| 3547 | if self.getTrack()=="--any--": |
|---|
| 3548 | return True |
|---|
| 3549 | else: |
|---|
| 3550 | if self.getTrack()=="" or self.getTrack() is None or \ |
|---|
| 3551 | self.getTrack()=="--none--": |
|---|
| 3552 | return status.getTrack()=="" or status.getTrack()==None |
|---|
| 3553 | return status.getTrack()==self.getTrack() |
|---|
| 3554 | return False |
|---|
| 3555 | |
|---|
| 3556 | def satisfies(self,abs): |
|---|
| 3557 | if not isinstance(abs.getCurrentStatus(),AbstractStatusAccepted): |
|---|
| 3558 | return False |
|---|
| 3559 | else: |
|---|
| 3560 | return self._satifiesContribType(abs) and self._satifiesTrack(abs) |
|---|
| 3561 | |
|---|
| 3562 | |
|---|
| 3563 | class NotifTplCondRejected(NotifTplCondition): |
|---|
| 3564 | |
|---|
| 3565 | def satisfies(self,abs): |
|---|
| 3566 | return isinstance(abs.getCurrentStatus(),AbstractStatusRejected) |
|---|
| 3567 | |
|---|
| 3568 | def clone(self, conference, template): |
|---|
| 3569 | ntcr = NotifTplCondRejected() |
|---|
| 3570 | ntcr.includeInTpl(template) |
|---|
| 3571 | return ntcr |
|---|
| 3572 | |
|---|
| 3573 | class NotifTplCondMerged(NotifTplCondition): |
|---|
| 3574 | |
|---|
| 3575 | def satisfies(self,abs): |
|---|
| 3576 | return isinstance(abs.getCurrentStatus(),AbstractStatusMerged) |
|---|
| 3577 | |
|---|
| 3578 | def clone(self, conference, template): |
|---|
| 3579 | ntcm = NotifTplCondMerged() |
|---|
| 3580 | ntcm.includeInTpl(newTpl, newId) |
|---|
| 3581 | |
|---|
| 3582 | class NotificationLog(Persistent): |
|---|
| 3583 | |
|---|
| 3584 | def __init__(self,abstract): |
|---|
| 3585 | self._abstract=abstract |
|---|
| 3586 | self._entries=PersistentList() |
|---|
| 3587 | |
|---|
| 3588 | def getAbstract(self): |
|---|
| 3589 | return self._abstract |
|---|
| 3590 | |
|---|
| 3591 | def addEntry(self,newEntry): |
|---|
| 3592 | if newEntry!=None and newEntry not in self._entries: |
|---|
| 3593 | self._entries.append(newEntry) |
|---|
| 3594 | |
|---|
| 3595 | def getEntryList(self): |
|---|
| 3596 | return self._entries |
|---|
| 3597 | |
|---|
| 3598 | # The 3 following metods are used only for recovery purposes: |
|---|
| 3599 | |
|---|
| 3600 | def removeEntry(self, entry): |
|---|
| 3601 | if entry!=None and entry in self._entries: |
|---|
| 3602 | self._entries.remove(entry) |
|---|
| 3603 | entry.delete() |
|---|
| 3604 | |
|---|
| 3605 | def recoverEntry(self, entry): |
|---|
| 3606 | self.addEntry(entry) |
|---|
| 3607 | entry.recover() |
|---|
| 3608 | |
|---|
| 3609 | def clearEntryList(self): |
|---|
| 3610 | while len(self.getEntryList()) > 0: |
|---|
| 3611 | self.removeEntry(self.getEntryList()[0]) |
|---|
| 3612 | |
|---|
| 3613 | # ----------------------------------------------------------- |
|---|
| 3614 | |
|---|
| 3615 | class NotifLogEntry(Persistent): |
|---|
| 3616 | |
|---|
| 3617 | def __init__(self,responsible,tpl): |
|---|
| 3618 | self._setDate(nowutc()) |
|---|
| 3619 | self._setResponsible(responsible) |
|---|
| 3620 | self._setTpl(tpl) |
|---|
| 3621 | |
|---|
| 3622 | def _setDate(self,newDate): |
|---|
| 3623 | self._date=newDate |
|---|
| 3624 | |
|---|
| 3625 | def getDate(self): |
|---|
| 3626 | return self._date |
|---|
| 3627 | |
|---|
| 3628 | def _setResponsible(self,newResp): |
|---|
| 3629 | self._responsible=newResp |
|---|
| 3630 | |
|---|
| 3631 | def getResponsible(self): |
|---|
| 3632 | return self._responsible |
|---|
| 3633 | |
|---|
| 3634 | def _setTpl(self,newTpl): |
|---|
| 3635 | self._tpl=newTpl |
|---|
| 3636 | |
|---|
| 3637 | def getTpl(self): |
|---|
| 3638 | return self._tpl |
|---|
| 3639 | |
|---|
| 3640 | def delete(self): |
|---|
| 3641 | TrashCanManager().add(self) |
|---|
| 3642 | |
|---|
| 3643 | def recover(self): |
|---|
| 3644 | TrashCanManager().remove(self) |
|---|