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