Fix datepicker arrows style on hover
[cds-indico.git] / indico / MaKaC / webinterface / rh / abstractModif.py
blobf52895f35850239a61606a45c5dd319f0e85d555
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
16 from cStringIO import StringIO
17 from flask import request
19 import MaKaC.webinterface.urlHandlers as urlHandlers
20 import MaKaC.webinterface.pages.abstracts as abstracts
21 import MaKaC.review as review
22 from MaKaC.webinterface.rh.base import RHModificationBaseProtected
23 from MaKaC.webinterface.rh.conferenceBase import RHAbstractBase, RHConferenceBase
24 from MaKaC.PDFinterface.conference import ConfManagerAbstractToPDF
25 from MaKaC.common.xmlGen import XMLGen
26 from MaKaC.errors import MaKaCError, ModificationError, FormValuesError, NoReportError
27 from MaKaC.webinterface.common.abstractNotificator import EmailNotificator
28 from indico.core.config import Config
29 from MaKaC.webinterface.common.abstractDataWrapper import AbstractParam
30 from MaKaC.i18n import _
31 from MaKaC.webinterface.rh.conferenceModif import CFAEnabled
32 from MaKaC.paperReviewing import Answer
33 from MaKaC.webinterface.common.tools import cleanHTMLHeaderFilename
34 from indico.web.flask.util import send_file
35 from MaKaC.PDFinterface.base import LatexRunner
38 class RHAbstractModifBase( RHAbstractBase, RHModificationBaseProtected ):
39 """ Base class to be used for abstract modification in the admin interface,
40 when the request can only be performed by Conference managers.
41 """
43 def _checkParams( self, params ):
44 RHAbstractBase._checkParams( self, params )
46 def _checkProtection( self ):
47 target = self._target
48 try:
49 self._target = self._conf
50 RHModificationBaseProtected._checkProtection(self)
51 finally:
52 self._target = target
53 CFAEnabled.checkEnabled(self)
55 def _displayCustomPage( self, wf ):
56 return None
58 def _displayDefaultPage( self ):
59 return None
61 def _process( self ):
62 wf = self.getWebFactory()
63 if wf != None:
64 res = self._displayCustomPage( wf )
65 if res != None:
66 return res
67 return self._displayDefaultPage()
70 class RHAbstractDelete(RHAbstractModifBase):
72 def _checkParams( self, params ):
73 RHAbstractModifBase._checkParams( self, params )
74 self._remove = params.has_key("confirm")
75 self._cancel = params.has_key("cancel")
77 def _process( self ):
78 if self._cancel:
79 self._redirect( urlHandlers.UHAbstractModTools.getURL( self._abstract) )
80 else:
81 if self._remove:
82 self._conf.getAbstractMgr().removeAbstract(self._target)
83 self._redirect( urlHandlers.UHConfAbstractManagment.getURL( self._conf) )
84 else:
85 p = abstracts.WPModRemConfirmation( self, self._abstract )
86 return p.display()
89 class RHAbstractManagment(RHAbstractModifBase):
91 def _process( self ):
92 p = abstracts.WPAbstractManagment( self, self._target )
93 return p.display( **self._getRequestParams() )
96 class RHAbstractDirectAccess(RHAbstractModifBase, RHConferenceBase):
98 def _checkProtection( self ):
99 # if len( self._conf.getCoordinatedTracks( self._getUser() ) ) == 0:
100 RHAbstractModifBase._checkProtection( self )
102 def _checkParams(self, params):
103 RHConferenceBase._checkParams(self, params)
104 self._abstractId = params.get("abstractId","")
105 self._abstractExist = False
106 try:
107 abstract = self._conf.getAbstractMgr().getAbstractById(self._abstractId)
108 self._abstractExist = True
109 RHAbstractModifBase._checkParams(self, params)
110 except KeyError:
111 pass
114 def _process( self ):
115 if self._abstractExist and self._target is not None:
116 p = abstracts.WPAbstractManagment( self, self._target )
117 return p.display( **self._getRequestParams() )
118 else:
119 url = urlHandlers.UHConfAbstractManagment.getURL(self._conf)
120 #url.addParam("directAbstractMsg","There is no abstract number %s in this conference"%self._abstractId)
121 self._redirect(url)
122 return
125 class RHAbstractToPDF(RHAbstractModifBase):
127 def _process( self ):
128 tz = self._conf.getTimezone()
129 filename = "%s - Abstract.pdf" % self._target.getTitle()
130 pdf = ConfManagerAbstractToPDF(self._target, tz=tz)
131 return send_file(filename, pdf.generate(), 'PDF')
134 class RHAbstractToXML(RHAbstractModifBase):
136 def _process( self ):
137 filename = "%s - Abstract.xml"%self._target.getTitle()
139 x = XMLGen()
140 x.openTag("abstract")
141 x.writeTag("Id", self._target.getId())
142 x.writeTag("Title", self._target.getTitle())
143 afm = self._target.getConference().getAbstractMgr().getAbstractFieldsMgr()
144 for f in afm.getFields():
145 id = f.getId()
146 if f.isActive() and str(self._target.getField(id)).strip() != "":
147 x.writeTag("field",self._target.getField(id),[("id",id)])
148 x.writeTag("Conference", self._target.getConference().getTitle())
149 l = []
150 for au in self._target.getAuthorList():
151 if self._target.isPrimaryAuthor(au):
152 x.openTag("PrimaryAuthor")
153 x.writeTag("FirstName", au.getFirstName())
154 x.writeTag("FamilyName", au.getSurName())
155 x.writeTag("Email", au.getEmail())
156 x.writeTag("Affiliation", au.getAffiliation())
157 x.closeTag("PrimaryAuthor")
158 else:
159 l.append(au)
161 for au in l:
162 x.openTag("Co-Author")
163 x.writeTag("FirstName", au.getFirstName())
164 x.writeTag("FamilyName", au.getSurName())
165 x.writeTag("Email", au.getEmail())
166 x.writeTag("Affiliation", au.getAffiliation())
167 x.closeTag("Co-Author")
169 for au in self._target.getSpeakerList():
170 x.openTag("Speaker")
171 x.writeTag("FirstName", au.getFirstName ())
172 x.writeTag("FamilyName", au.getSurName())
173 x.writeTag("Email", au.getEmail())
174 x.writeTag("Affiliation", au.getAffiliation())
175 x.closeTag("Speaker")
177 #To change for the new contribution type system to:
178 #x.writeTag("ContributionType", self._target.getContribType().getName())
179 x.writeTag("ContributionType", self._target.getContribType())
181 for t in self._target.getTrackList():
182 x.writeTag("Track", t.getTitle())
184 x.closeTag("abstract")
186 return send_file(filename, StringIO(x.getXml()), 'XML')
189 class _AbstractWrapper:
191 def __init__(self,status):
192 self._status=status
194 def getCurrentStatus(self):
195 return self._status
198 class RHAbstractManagmentAccept(RHAbstractModifBase):
200 def _checkParams( self, params ):
201 RHAbstractModifBase._checkParams( self, params )
202 self._accept = params.get("accept", None)
203 self._warningShown=params.has_key("confirm")
204 self._trackId = params.get("track", "")
205 self._track=self._conf.getTrackById(params.get("track", ""))
206 self._sessionId = params.get("session", "")
207 self._session=self._conf.getSessionById(params.get("session", ""))
208 self._comments = params.get("comments", "")
209 self._typeId = params.get("type", "")
210 self._doNotify=params.has_key("notify")
212 def _process( self ):
213 if self._accept:
214 cType=self._conf.getContribTypeById(self._typeId)
215 st=review.AbstractStatusAccepted(self._target,None,self._track,cType)
216 wrapper=_AbstractWrapper(st)
217 tpl=self._target.getOwner().getNotifTplForAbstract(wrapper)
218 if self._doNotify and not self._warningShown and tpl is None:
219 p=abstracts.WPModAcceptConfirmation(self,self._target)
220 return p.display(track=self._trackId,comments=self._comments,type=self._typeId,session=self._sessionId)
221 else:
222 self._target.accept(self._getUser(),self._track,cType,self._comments,self._session)
223 if self._doNotify:
224 n=EmailNotificator()
225 self._target.notify(n,self._getUser())
226 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._abstract))
227 else:
228 p = abstracts.WPAbstractManagmentAccept( self, self._target )
229 return p.display( **self._getRequestParams() )
232 class RHAbstractManagmentReject(RHAbstractModifBase):
234 def _checkParams( self, params ):
235 RHAbstractModifBase._checkParams( self, params )
236 self._reject = params.get("reject", None)
237 self._comments = params.get("comments", "")
238 self._doNotify=params.has_key("notify")
239 self._warningShown=params.has_key("confirm")
241 def _process( self ):
242 if self._reject:
243 st=review.AbstractStatusRejected(self._target,None,None)
244 wrapper=_AbstractWrapper(st)
245 tpl=self._target.getOwner().getNotifTplForAbstract(wrapper)
246 if self._doNotify and not self._warningShown and tpl is None:
247 p=abstracts.WPModRejectConfirmation(self,self._target)
248 return p.display(comments=self._comments)
249 else:
250 self._target.reject(self._getUser(), self._comments)
251 if self._doNotify:
252 n=EmailNotificator()
253 self._target.notify(n,self._getUser())
254 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._target))
255 else:
256 p = abstracts.WPAbstractManagmentReject( self, self._target )
257 return p.display( **self._getRequestParams() )
260 class RHMarkAsDup(RHAbstractModifBase):
262 def _checkParams(self, params):
263 RHAbstractModifBase._checkParams(self, params)
264 self._action, self._comments, self._original = "", "", None
265 self._originalId = ""
266 if "OK" in params:
267 self._action = "MARK"
268 self._comments = params.get("comments", "")
269 self._originalId = params.get("id", "")
270 self._original = self._target.getOwner().getAbstractById(self._originalId)
272 def _getErrorsInData(self):
273 res = []
274 if self._original is None or self._target == self._original:
275 res.append(_("invalid original abstract id"))
276 return res
278 def _process(self):
279 errMsg = ""
280 if self._action == "MARK":
281 errorList = self._getErrorsInData()
282 if len(errorList) == 0:
283 self._target.markAsDuplicated(
284 self._getUser(), self._original, self._comments)
285 self._redirect(
286 urlHandlers.UHAbstractManagment.getURL(self._target))
287 return
288 else:
289 errMsg = "<br>".join(errorList)
290 p = abstracts.WPModMarkAsDup(self, self._target)
291 return p.display(comments=self._comments, originalId=self._originalId, errorMsg=errMsg)
294 class RHUnMarkAsDup(RHAbstractModifBase):
296 def _checkParams(self, params):
297 RHAbstractModifBase._checkParams(self, params)
298 self._action, self._comments, self._original = "", "", None
299 self._originalId = ""
300 if "OK" in params:
301 self._action = "UNMARK"
302 self._comments = params.get("comments", "")
304 def _process(self):
305 errMsg = ""
306 if self._action == "UNMARK":
307 self._target.unMarkAsDuplicated(self._getUser(), self._comments)
308 self._redirect(
309 urlHandlers.UHAbstractManagment.getURL(self._target))
310 return
311 p = abstracts.WPModUnMarkAsDup(self, self._target)
312 return p.display(comments=self._comments, originalId=self._originalId, errorMsg=errMsg)
315 class RHMergeInto(RHAbstractModifBase):
317 def _checkParams(self, params):
318 RHAbstractModifBase._checkParams(self, params)
319 self._action, self._comments, self._targetAbs = "", "", None
320 self._targetAbsId, self._includeAuthors, self._doNotify = "", False, True
321 if "OK" in params:
322 self._action = "MERGE"
323 self._comments = params.get("comments", "")
324 self._targetAbsId = params.get("id", "")
325 self._includeAuthors = "includeAuthors" in params
326 self._doNotify = "notify" in params
327 self._targetAbs = self._target.getOwner(
328 ).getAbstractById(self._targetAbsId)
330 def _getErrorsInData(self):
331 res = []
332 if self._targetAbs is None or self._target == self._targetAbs:
333 res.append("invalid target abstract id")
334 return res
336 def _process(self):
337 errMsg = ""
338 if self._action == "MERGE":
339 errorList = self._getErrorsInData()
340 if len(errorList) == 0:
341 self._target.mergeInto(self._getUser(), self._targetAbs, comments=self._comments, mergeAuthors=self._includeAuthors)
342 if self._doNotify:
343 self._target.notify(EmailNotificator(), self._getUser())
344 self._redirect(
345 urlHandlers.UHAbstractManagment.getURL(self._target))
346 return
347 else:
348 errMsg = "<br>".join(errorList)
349 p = abstracts.WPModMergeInto(self, self._target)
350 return p.display(comments=self._comments, targetId=self._targetAbsId, errorMsg=errMsg, includeAuthors=self._includeAuthors, notify=self._doNotify)
352 class RHUnMerge(RHAbstractModifBase):
354 def _checkParams( self, params ):
355 RHAbstractModifBase._checkParams( self, params )
356 self._action,self._comments="",""
357 if params.has_key("OK"):
358 self._action="UNMERGE"
359 self._comments=params.get("comments","")
362 def _process( self ):
363 if self._action=="UNMERGE":
364 self._target.unMerge(self._getUser(),self._comments)
365 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._target))
366 return
367 p=abstracts.WPModUnMerge(self,self._target)
368 return p.display(comments=self._comments)
371 class RHPropBase(RHAbstractModifBase):
373 def _checkProtection(self):
374 try:
375 RHAbstractModifBase._checkProtection(self)
376 except ModificationError,e:
377 if self._target.isAllowedToCoordinate(self._getUser()):
378 return
379 raise
381 def _checkParams( self, params ):
382 RHAbstractModifBase._checkParams(self, params)
383 self._action = ""
384 self._answers = []
385 if params.has_key("OK"):
386 self._action = "GO"
387 conf=self._target.getConference()
388 self._track = conf.getTrackById(params.get("track",""))
389 if self._track is None:
390 raise FormValuesError( _("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 from its management page"))
391 self._contribType = self._conf.getContribTypeById(params.get("contribType",""))
392 self._comment = params.get("comment","")
393 scaleLower = conf.getConfAbstractReview().getScaleLower()
394 scaleHigher = conf.getConfAbstractReview().getScaleHigher()
395 numberOfAnswers = conf.getConfAbstractReview().getNumberOfAnswers()
396 c = 0
397 for question in conf.getConfAbstractReview().getReviewingQuestions():
398 c += 1
399 if not params.has_key("RB_"+str(c)):
400 raise FormValuesError(_("Please, reply to all the reviewing questions. Question \"%s\" is missing the answer.")%question.getText())
401 rbValue = int(params.get("RB_"+str(c),scaleLower))
402 newId = conf.getConfAbstractReview().getNewAnswerId()
403 newAnswer = Answer(newId, rbValue, numberOfAnswers, question)
404 newAnswer.calculateRatingValue(scaleLower, scaleHigher)
405 self._answers.append(newAnswer)
406 elif params.has_key("CANCEL"):
407 self._action="CANCEL"
410 class RHPropToAcc(RHPropBase):
412 def _process( self ):
413 url=urlHandlers.UHAbstractManagment.getURL(self._target)
414 if self._action=="GO":
415 self._abstract.proposeToAccept(self._getUser(),\
416 self._track,self._contribType,self._comment, self._answers)
417 self._redirect(url)
418 elif self._action=="CANCEL":
419 self._redirect(url)
420 else:
421 p=abstracts.WPModPropToAcc(self,self._target)
422 return p.display()
426 class RHPropToRej(RHPropBase):
428 def _process( self ):
429 url=urlHandlers.UHAbstractManagment.getURL(self._target)
430 if self._action=="GO":
431 self._abstract.proposeToReject(self._getUser(),\
432 self._track,self._comment, self._answers)
433 self._redirect(url)
434 elif self._action=="CANCEL":
435 self._redirect(url)
436 else:
437 p=abstracts.WPModPropToRej(self,self._target)
438 return p.display()
441 class RHWithdraw(RHAbstractModifBase):
443 def _checkParams(self,params):
444 RHAbstractModifBase._checkParams(self,params)
445 self._action,self._comments="",""
446 if params.has_key("OK"):
447 self._action="WITHDRAW"
448 self._comment=params.get("comment","")
449 if params.has_key("CANCEL"):
450 self._action="CANCEL"
452 def _process( self ):
453 url=urlHandlers.UHAbstractManagment.getURL(self._target)
454 if self._action=="WITHDRAW":
455 self._target.withdraw(self._getUser(),self._comment)
456 self._redirect(url)
457 return
458 elif self._action=="CANCEL":
459 self._redirect(url)
460 return
461 else:
462 p=abstracts.WPModWithdraw(self,self._target)
463 return p.display()
465 class RHBackToSubmitted(RHAbstractModifBase):
467 def _removeAssociatedContribution(self):
468 contribution = self._abstract.getContribution()
469 contribution.getOwner().getSchedule().removeEntry(contribution.getSchEntry())
470 contribution.delete()
472 def _process( self ):
473 url=urlHandlers.UHAbstractManagment.getURL(self._target)
474 if isinstance(self._abstract.getCurrentStatus(), (review.AbstractStatusWithdrawn, review.AbstractStatusRejected)):
475 self._abstract.setCurrentStatus(review.AbstractStatusSubmitted(self._abstract))
476 elif isinstance(self._abstract.getCurrentStatus(), review.AbstractStatusAccepted):
477 # remove the associated contribution
478 self._removeAssociatedContribution()
479 # set submittted status
480 self._abstract.setCurrentStatus(review.AbstractStatusSubmitted(self._abstract))
481 self._redirect(url)
484 class RHAbstractManagmentChangeTrack(RHAbstractModifBase):
486 def _checkParams( self, params ):
487 self._cancel = params.get("cancel", None)
488 self._save = params.get("save", None)
489 self._tracks = self._normaliseListParam(params.get("tracks", []))
490 RHAbstractModifBase._checkParams( self, params )
492 def _process( self ):
493 if self._save:
494 tracks = []
495 for trackId in self._tracks:
496 tracks.append( self._conf.getTrackById(trackId) )
497 self._target.setTracks( tracks )
498 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._target))
499 elif self._cancel:
500 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._target))
501 else:
502 p = abstracts.WPAbstractManagmentChangeTrack( self, self._target )
503 return p.display( **self._getRequestParams() )
506 class RHAbstractTrackManagment(RHAbstractModifBase):
508 def _process( self ):
509 p = abstracts.WPAbstractTrackManagment( self, self._target )
510 return p.display( **self._getRequestParams() )
512 class RHAbstractTrackOrderByRating(RHAbstractModifBase):
514 def _process( self ):
515 p = abstracts.WPAbstractTrackOrderByRating( self, self._target )
516 return p.display( **self._getRequestParams() )
519 class RHEditData(RHAbstractModifBase, AbstractParam):
521 def __init__(self):
522 RHAbstractModifBase.__init__(self)
523 AbstractParam.__init__(self)
525 def _checkParams(self, params):
526 RHAbstractModifBase._checkParams(self,params)
527 if self._getUser() is None:
528 return
529 AbstractParam._checkParams(self, params, self._conf, request.content_length)
530 if self._action == "":#First call
531 #TODO: remove this code, this should be handle by AbstractData (not method available
532 # because setAbstractData(abstract) is used when saving, so there are specific actions.
533 afm = self._conf.getAbstractMgr().getAbstractFieldsMgr()
534 self._abstractData.title = self._abstract.getTitle()
535 for f in afm.getFields():
536 id = f.getId()
537 self._abstractData.setFieldValue(id, self._abstract.getField(id))
538 self._abstractData.type = self._abstract.getContribType()
539 trackIds = []
540 for track in self._abstract.getTrackListSorted():
541 trackIds.append(track.getId())
542 self._abstractData.tracks = trackIds
543 self._abstractData.comments = self._abstract.getComments()
545 def _doValidate( self ):
546 #First, one must validate that the information is fine
547 errors = self._abstractData.check()
548 if errors:
549 p = abstracts.WPModEditData(self, self._target, self._abstractData)
550 pars = self._abstractData.toDict()
551 pars["errors"] = errors
552 pars["action"] = self._action
553 # restart the current value of the param attachments to show the existing files
554 pars["attachments"] = self._abstract.getAttachments().values()
555 return p.display( **pars )
556 self._abstract.clearAuthors()
557 #self._setAbstractData(self._abstract)
558 self._abstractData.setAbstractData(self._abstract)
559 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._target))
561 def _process( self ):
562 if self._action == "CANCEL":
563 self._redirect(urlHandlers.UHAbstractManagment.getURL(self._target))
564 elif self._action == "VALIDATE":
565 return self._doValidate()
566 else:
567 if isinstance( self._abstract.getCurrentStatus(), review.AbstractStatusAccepted ):
568 raise NoReportError(_("The abstract with id '%s' cannot be edited because it has already been accepted.") % self._abstract.getId())
569 p = abstracts.WPModEditData(self, self._target, self._abstractData)
570 pars = self._abstractData.toDict()
571 return p.display(**pars)
574 class RHIntComments(RHAbstractModifBase):
576 def _process( self ):
577 p = abstracts.WPModIntComments(self,self._target)
578 return p.display()
581 class RHNewIntComment(RHIntComments):
583 def _checkParams(self,params):
584 RHIntComments._checkParams(self,params)
585 self._action=""
586 if params.has_key("OK"):
587 self._action="UPDATE"
588 self._content=params.get("content","")
589 elif params.has_key("CANCEL"):
590 self._action="CANCEL"
592 def _process( self ):
593 if self._action=="UPDATE":
594 c=review.Comment(self._getUser())
595 c.setContent(self._content)
596 self._target.addIntComment(c)
597 self._redirect(urlHandlers.UHAbstractModIntComments.getURL(self._target))
598 return
599 elif self._action=="CANCEL":
600 self._redirect(urlHandlers.UHAbstractModIntComments.getURL(self._target))
601 return
602 p = abstracts.WPModNewIntComment(self,self._target)
603 return p.display()
606 class RHIntCommentBase(RHAbstractModifBase):
608 def _checkParams(self,params):
609 RHAbstractModifBase._checkParams(self,params)
610 id=params.get("intCommentId","")
611 if id=="":
612 raise MaKaCError( _("the internal comment identifier hasn't been specified"))
613 abstract=self._target
614 self._target=abstract.getIntCommentById(id)
617 class RHIntCommentRem(RHIntCommentBase):
619 def _process(self):
620 abstract=self._target.getAbstract()
621 abstract.removeIntComment(self._target)
622 self._redirect(urlHandlers.UHAbstractModIntComments.getURL(abstract))
625 class RHIntCommentEdit(RHIntCommentBase):
627 def _checkParams(self,params):
628 RHIntCommentBase._checkParams(self,params)
629 self._action=""
630 if params.has_key("OK"):
631 self._action="UPDATE"
632 self._content=params.get("content","")
633 elif params.has_key("CANCEL"):
634 self._action="CANCEL"
636 def _process(self):
637 if self._action=="UPDATE":
638 self._target.setContent(self._content)
639 self._redirect(urlHandlers.UHAbstractModIntComments.getURL(self._target.getAbstract()))
640 return
641 elif self._action=="CANCEL":
642 self._redirect(urlHandlers.UHAbstractModIntComments.getURL(self._target.getAbstract()))
643 return
644 p=abstracts.WPModIntCommentEdit(self,self._target)
645 return p.display()
648 class RHNotifLog(RHAbstractModifBase):
650 def _process( self ):
651 p = abstracts.WPModNotifLog(self,self._target)
652 return p.display()
654 class RHTools(RHAbstractModifBase):
656 def _process( self ):
657 p = abstracts.WPModTools(self,self._target)
658 return p.display()