abstract submission confirmation email
authorroot <root@indico.ffzg.hr>
Wed, 27 Jan 2016 15:06:53 +0000 (16:06 +0100)
committerroot <root@indico.ffzg.hr>
Wed, 27 Jan 2016 15:06:53 +0000 (16:06 +0100)
MaKaC/webinterface/rh/CFADisplay.py [new file with mode: 0644]

diff --git a/MaKaC/webinterface/rh/CFADisplay.py b/MaKaC/webinterface/rh/CFADisplay.py
new file mode 100644 (file)
index 0000000..844a7b8
--- /dev/null
@@ -0,0 +1,500 @@
+# -*- coding: utf-8 -*-
+##
+##
+## This file is part of Indico.
+## Copyright (C) 2002 - 2014 European Organization for Nuclear Research (CERN).
+##
+## Indico is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 3 of the
+## License, or (at your option) any later version.
+##
+## Indico is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Indico;if not, see <http://www.gnu.org/licenses/>.
+from flask import request
+
+from textwrap import TextWrapper
+
+from BTrees.IOBTree import IOBTree
+from cStringIO import StringIO
+
+import MaKaC.webinterface.urlHandlers as urlHandlers
+import MaKaC.webinterface.mail as mail
+import MaKaC.webinterface.pages.abstracts as abstracts
+import MaKaC.review as review
+from MaKaC.webinterface.rh.conferenceDisplay import RHConferenceBaseDisplay
+from MaKaC.webinterface.rh.base import RHModificationBaseProtected
+from indico.core.db import DBMgr
+from MaKaC.review import AbstractStatusSubmitted, AbstractStatusAccepted
+from MaKaC.PDFinterface.conference import AbstractToPDF, AbstractsToPDF
+from MaKaC.errors import MaKaCError, NoReportError
+import MaKaC.common.timezoneUtils as timezoneUtils
+from MaKaC.i18n import _
+from indico.util.i18n import i18nformat
+from indico.web.flask.util import send_file
+from MaKaC.webinterface.common.abstractDataWrapper import AbstractParam
+from MaKaC.webinterface.rh.fileAccess import RHFileAccess
+from MaKaC.webinterface.common.tools import cleanHTMLHeaderFilename
+from MaKaC.PDFinterface.base import LatexRunner
+
+
+class RHBaseCFA( RHConferenceBaseDisplay ):
+
+    def _processIfActive( self ):
+        """only override this method if the CFA must be activated for
+            carrying on the handler execution"""
+        return "cfa"
+
+    def _process( self ):
+        #if the CFA is not activated we show up a form informing about that.
+        #   This must be done at RH level because there can be some RH not
+        #   displaying pages.
+        cfaMgr = self._conf.getAbstractMgr()
+        if not cfaMgr.isActive() or not self._conf.hasEnabledSection("cfa"):
+            p = abstracts.WPCFAInactive( self, self._conf )
+            return p.display()
+        else:
+            return self._processIfActive()
+
+
+class RHConferenceCFA( RHBaseCFA ):
+    _uh = urlHandlers.UHConferenceCFA
+
+    def _processIfActive( self ):
+        p = abstracts.WPConferenceCFA( self, self._target )
+        return p.display()
+
+
+class RHAbstractSubmissionBase(RHBaseCFA):
+
+    def _checkProtection(self):
+        self._checkSessionUser()
+        RHBaseCFA._checkProtection(self)
+
+    def _processIfOpened(self):
+        """only override this method if the submission period must be opened
+            for the request handling"""
+        return "cfa opened"
+
+    def _processIfActive(self):
+        cfaMgr = self._conf.getAbstractMgr()
+        #if the user is in the autorized list, don't check period
+        if self._getUser() in cfaMgr.getAuthorizedSubmitterList():
+            return self._processIfOpened()
+        #if the submission period is not yet opened we show up a form informing
+        #   about that.
+        if timezoneUtils.nowutc() < cfaMgr.getStartSubmissionDate():
+        #if the submission period is already closed we show up a form informing
+        #   about that.
+            p = abstracts.WPCFANotYetOpened(self, self._conf)
+            return p.display()
+        elif timezoneUtils.nowutc() > cfaMgr.getEndSubmissionDate():
+            p = abstracts.WPCFAClosed(self, self._conf, False)
+            return p.display()
+        else:
+            return self._processIfOpened()
+
+
+class _AbstractSubmissionNotification:
+
+    def __init__(self, abstract):
+        self._abstract = abstract
+        self._conf = self._abstract.getConference()
+        self._subject = _("Abstract submission confirmation (%s)") % self._conf.getTitle()
+
+    def getAttachments(self):
+        return []
+
+    def getSubject(self):
+        return self._subject
+
+    def setSubject(self, s):
+        self._subject = s
+
+    def getDestination(self):
+        return self._abstract.getSubmitter()
+
+    def getFromAddr(self):
+        return self._conf.getSupportInfo().getEmail(returnNoReply=True)
+
+    def getCCList(self):
+        return self._abstract.getOwner().getSubmissionNotification().getCCList()
+
+    def getToList(self):
+        return self._abstract.getOwner().getSubmissionNotification().getToList()
+
+    def getMsg(self):
+        primary_authors = []
+        for auth in self._abstract.getPrimaryAuthorList():
+            primary_authors.append("""%s (%s) <%s>""" % (auth.getFullName(), auth.getAffiliation(), auth.getEmail()))
+        co_authors = []
+        for auth in self._abstract.getCoAuthorList():
+            email = ""
+            if auth.getEmail() != "":
+                email = " <%s>" % auth.getEmail()
+            co_authors.append("""%s (%s)%s""" % (auth.getFullName(), auth.getAffiliation(), email))
+        speakers = []
+        for spk in self._abstract.getSpeakerList():
+            speakers.append(spk.getFullName())
+        tracks = []
+        for track in self._abstract.getTrackListSorted():
+            tracks.append("""%s""" % track.getTitle())
+        tw = TextWrapper()
+        msg = [i18nformat("""_("Dear") %s,""") % self._abstract.getSubmitter().getStraightFullName()]
+        msg.append("")
+        msg.append(tw.fill(_("The submission of your abstract has been successfully processed.")))
+        msg.append("")
+        tw.break_long_words = False
+        msg.append(tw.fill(i18nformat("""_("Abstract submitted"):\n<%s>.""") % urlHandlers.UHUserAbstracts.getURL(self._conf)))
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Status of your abstract"):\n<%s>.""") % urlHandlers.UHAbstractDisplay.getURL(self._abstract)))
+        msg.append("")
+        tw.subsequent_indent = ""
+        msg.append(tw.fill(i18nformat("""_("See below a detailed summary of your submitted abstract"):""")))
+        msg.append("")
+        tw.subsequent_indent = " "*3
+        msg.append(tw.fill(i18nformat("""_("Conference"): %s""") % self._conf.getTitle()))
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Submitted by"): %s""") % self._abstract.getSubmitter().getFullName()))
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Submitted on"): %s""") % self._abstract.getSubmissionDate().strftime("%d %B %Y %H:%M")))
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Title"): %s""") % self._abstract.getTitle()))
+        msg.append("")
+        for f in self._conf.getAbstractMgr().getAbstractFieldsMgr().getFields():
+            msg.append(tw.fill(f.getCaption()))
+            msg.append(str(self._abstract.getField(f.getId())))
+            msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Primary Authors"):""")))
+        msg += primary_authors
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Co-authors"):""")))
+        msg += co_authors
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Abstract presenters"):""")))
+        msg += speakers
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Track classification"):""")))
+        msg += tracks
+        msg.append("")
+        ctype = i18nformat("""--_("not specified")--""")
+        if self._abstract.getContribType() is not None:
+            ctype = self._abstract.getContribType().getName()
+        msg.append(tw.fill(i18nformat("""_("Presentation type"): %s""") % ctype))
+        msg.append("")
+        msg.append(tw.fill(i18nformat("""_("Comments"): %s""") % self._abstract.getComments()))
+        msg.append("")
+        return "\n".join(msg)
+
+    def getBody(self):
+        msg = self.getMsg()
+        return i18nformat("""
+_("The following email has been sent to %s"):
+
+===
+
+%s""") % (self.getDestination().getFullName(), msg)
+
+
+class RHAbstractModificationAction(RHAbstractSubmissionBase, AbstractParam):
+
+    def __init__(self, req):
+        RHAbstractSubmissionBase.__init__(self, req)
+        AbstractParam.__init__(self)
+
+    def _checkParams( self, params ):
+        RHAbstractSubmissionBase._checkParams(self, params)
+        #if the user is not logged in we return immediately as this form needs
+        #   the user to be logged in and therefore all the checking below is not
+        #   necessary
+        if self._getUser() is None:
+            return
+
+        AbstractParam._checkParams(self, params, self._conf, request.content_length)
+
+
+class RHAbstractSubmission( RHAbstractModificationAction ):
+    _uh = urlHandlers.UHAbstractSubmission
+
+    def _doValidate( self ):
+        #First, one must validate that the information is fine
+        errors = self._abstractData.check()
+        if errors:
+            p = abstracts.WPAbstractSubmission( self, self._target )
+            pars = self._abstractData.toDict()
+            pars["action"] = self._action
+            pars["attachments"] = []
+            return p.display( **pars )
+        #Then, we create the abstract object and set its data to the one
+        #   received
+        cfaMgr = self._target.getAbstractMgr()
+        abstract = cfaMgr.newAbstract( self._getUser() )
+        self._abstractData.setAbstractData(abstract)
+        #The commit must be forced before sending the confirmation
+        DBMgr.getInstance().commit()
+        #Email confirmation about the submission
+        mail.Mailer.send( _AbstractSubmissionNotification( abstract ), self._conf.getSupportInfo().getEmail(returnNoReply=True) )
+        #Email confirmation about the submission to coordinators
+        if cfaMgr.getSubmissionNotification().hasDestination():
+            asn=_AbstractSubmissionNotification( abstract )
+            asn.setSubject(_("[Indico] New abstract submission: %s")%asn.getDestination().getFullName())
+            mail.GenericMailer.send( asn )
+        #We must perform some actions: email warning to the authors
+        #Finally, we display a confirmation form
+        self._redirect( urlHandlers.UHAbstractSubmissionConfirmation.getURL( abstract ) )
+
+    def _processIfOpened( self ):
+        if self._action == "CANCEL":
+            self._redirect( urlHandlers.UHConferenceCFA.getURL( self._conf ) )
+        elif self._action == "VALIDATE":
+            return self._doValidate()
+        else:
+            p = abstracts.WPAbstractSubmission( self, self._target )
+            pars = self._abstractData.toDict()
+            return p.display( **pars )
+
+
+class RHAbstractModify(RHAbstractModificationAction, RHModificationBaseProtected):
+    _uh = urlHandlers.UHAbstractModify
+
+    def _checkProtection(self):
+        RHModificationBaseProtected._checkProtection(self)
+
+    def _checkParams(self, params):
+        RHAbstractModificationAction._checkParams(self, params)
+        if self._getUser() is None:
+            return
+        if self._action == "":
+            #First call
+            afm = self._conf.getAbstractMgr().getAbstractFieldsMgr()
+            self._abstractData.title = self._abstract.getTitle()
+            for f in afm.getFields():
+                id = f.getId()
+                self._abstractData.setFieldValue(id, self._abstract.getField(id))
+            self._abstractData.type = self._abstract.getContribType()
+            trackIds = []
+            for track in self._abstract.getTrackListSorted():
+                trackIds.append(track.getId())
+            self._abstractData.tracks = trackIds
+            self._abstractData.comments = self._abstract.getComments()
+
+    def _processIfActive(self):
+        #We overload this method to allow modification after the CFA is closed if the modification deadline is after the submission deadline
+        cfaMgr = self._conf.getAbstractMgr()
+        modifDeadLine = cfaMgr.getModificationDeadline()
+        if not modifDeadLine:
+            modifDeadLine = cfaMgr.getEndSubmissionDate()
+        #if the user is in the autorized list, don't check period
+        if self._getUser() in cfaMgr.getAuthorizedSubmitterList():
+            return self._processIfOpened()
+        #if the submission period is not yet opened we show up a form informing
+        #   about that.
+        if timezoneUtils.nowutc() < cfaMgr.getStartSubmissionDate():
+        #if the submission period is already closed we show up a form informing
+        #   about that.
+            p = abstracts.WPCFANotYetOpened(self, self._conf)
+            return p.display()
+        #elif timezoneUtils.nowutc() > cfaMgr.getEndSubmissionDate() :
+        elif timezoneUtils.nowutc() > cfaMgr.getEndSubmissionDate() and timezoneUtils.nowutc() > modifDeadLine:
+            p = abstracts.WPCFAClosed(self, self._conf, True)
+            return p.display()
+        else:
+            return self._processIfOpened()
+
+    def _doValidate(self):
+        #First, one must validate that the information is fine
+        errors = self._abstractData.check()
+        if errors:
+            p = abstracts.WPAbstractModify(self, self._target)
+            pars = self._abstractData.toDict()
+            pars["action"] = self._action
+            # restart the current value of the param attachments to show the existing files
+            pars["attachments"] = self._abstract.getAttachments().values()
+            return p.display(**pars)
+        self._abstract.clearAuthors()
+        self._abstractData.setAbstractData(self._abstract)
+        self._redirect(urlHandlers.UHAbstractDisplay.getURL(self._abstract))
+
+    def _processIfOpened(self):
+        #check if the modification period is not over or if the abstract
+        #   is in a different status than Submitted
+        if not self._conf.getAbstractMgr().inModificationPeriod() or \
+                not isinstance(self._abstract.getCurrentStatus(),
+                               AbstractStatusSubmitted):
+            wp = abstracts.WPAbstractCannotBeModified(self, self._abstract)
+            return wp.display()
+        if self._action == "CANCEL":
+            self._redirect(urlHandlers.UHAbstractDisplay.getURL(self._abstract))
+        elif self._action == "VALIDATE":
+            return self._doValidate()
+        else:
+            p = abstracts.WPAbstractModify(self, self._target)
+            pars = self._abstractData.toDict()
+            pars["action"] = self._action
+            return p.display(**pars)
+
+
+class RHUserAbstracts( RHAbstractSubmissionBase ):
+    _uh = urlHandlers.UHUserAbstracts
+
+    def _processIfActive( self ):
+        p = abstracts.WPUserAbstracts( self, self._conf )
+        return p.display()
+
+
+class RHAbstractDisplayBase( RHAbstractSubmissionBase ):
+
+    def _checkParams( self, params ):
+        RHAbstractSubmissionBase._checkParams( self, params )
+        cfaMgr = self._conf.getAbstractMgr()
+        if not params.has_key("abstractId") and params.has_key("contribId"):
+            params["abstractId"] = params["contribId"]
+        self._abstract = self._target = cfaMgr.getAbstractById( params["abstractId"] )
+        if self._abstract == None:
+            raise NoReportError(_("The abstract you are trying to access does not exist or has been deleted"))
+
+
+class RHAbstractSubmissionConfirmation( RHAbstractDisplayBase ):
+    _uh = urlHandlers.UHAbstractSubmissionConfirmation
+
+    def _processIfOpened( self ):
+        p = abstracts.WPAbstractSubmissionConfirmation( self, self._target )
+        return p.display()
+
+
+class RHAbstractDisplay( RHAbstractDisplayBase ):
+    _uh = urlHandlers.UHAbstractDisplay
+
+    def _processIfActive( self ):
+        p = abstracts.WPAbstractDisplay( self, self._target )
+        return p.display()
+
+
+class RHAbstractDisplayPDF( RHAbstractDisplayBase ):
+
+    def _checkProtection( self ):
+        RHConferenceBaseDisplay._checkProtection(self)
+        if not self._conf.getAbstractMgr().isActive() or not self._conf.hasEnabledSection("cfa"):
+            raise MaKaCError( _("The Call For Abstracts was disabled by the conference managers"))
+
+    def _process(self):
+        tz = timezoneUtils.DisplayTZ(self._aw, self._conf).getDisplayTZ()
+        filename = '%s - Abstract.pdf' % self._target.getTitle()
+        pdf = AbstractToPDF(self._target, tz=tz)
+        return send_file(filename, pdf.generate(), 'PDF')
+
+
+class RHUserAbstractsPDF(RHAbstractSubmissionBase):
+
+    def _processIfActive(self):
+        tz = timezoneUtils.DisplayTZ(self._aw, self._conf).getDisplayTZ()
+        cfaMgr = self._conf.getAbstractMgr()
+        abstracts = set(cfaMgr.getAbstractListForAvatar(self._aw.getUser()))
+        abstracts |= set(cfaMgr.getAbstractListForAuthorEmail(self._aw.getUser().getEmail()))
+        self._abstractIds = sorted(abstract.getId() for abstract in abstracts)
+        if not self._abstractIds:
+            return _("No abstract to print")
+
+        filename = 'my-abstracts.pdf'
+        pdf = AbstractsToPDF(self._conf, self._abstractIds, tz=tz)
+        return send_file(filename, pdf.generate(), 'PDF')
+
+
+class RHAbstractModificationBase(RHAbstractDisplayBase, RHModificationBaseProtected):
+
+    def _checkProtection(self):
+        RHModificationBaseProtected._checkProtection(self)
+
+    def _processIfActive(self):
+        #We overload this method to alow modification after the CFA is closed if the modification deadline is after the submission deadline
+        cfaMgr = self._conf.getAbstractMgr()
+        modifDeadLine = cfaMgr.getModificationDeadline()
+        if not modifDeadLine:
+            modifDeadLine = cfaMgr.getEndSubmissionDate()
+        #if the user is in the autorized list, don't check period
+        if self._getUser() in cfaMgr.getAuthorizedSubmitterList():
+            return self._processIfOpened()
+        #if the submission period is not yet opened we show up a form informing
+        #   about that.
+        if timezoneUtils.nowutc() < cfaMgr.getStartSubmissionDate():
+        #if the submission period is already closed we show up a form informing
+        #   about that.
+            p = abstracts.WPCFANotYetOpened(self, self._conf)
+            return p.display()
+        #elif timezoneUtils.nowutc() > cfaMgr.getEndSubmissionDate() :
+        elif timezoneUtils.nowutc() > cfaMgr.getEndSubmissionDate() and timezoneUtils.nowutc() > modifDeadLine:
+            p = abstracts.WPCFAClosed(self, self._conf, True)
+            return p.display()
+        else:
+            return self._processIfOpened()
+
+
+class RHAbstractWithdraw( RHAbstractModificationBase ):
+    _uh = urlHandlers.UHAbstractWithdraw
+
+    def _checkParams( self, params ):
+        RHAbstractModificationBase._checkParams( self, params )
+        self._action = ""
+        self._comments = params.get( "comment", "" )
+        if params.has_key("OK"):
+            self._action = "WITHDRAW"
+        elif params.has_key("cancel"):
+            self._action = "CANCEL"
+
+    def _processIfOpened( self ):
+        if self._action == "CANCEL":
+            self._redirect( urlHandlers.UHAbstractDisplay.getURL( self._abstract ) )
+        elif self._action == "WITHDRAW":
+            if self._abstract.getCurrentStatus().__class__ not in \
+                    [review.AbstractStatusSubmitted,
+                    review.AbstractStatusUnderReview,
+                    review.AbstractStatusInConflict,
+                    review.AbstractStatusProposedToAccept,
+                    review.AbstractStatusProposedToReject]:
+                raise MaKaCError( _("this abstract cannot be withdrawn, please contact the conference organisers in order to do so"))
+            self._abstract.withdraw(self._getUser(),self._comments)
+            self._redirect( urlHandlers.UHAbstractDisplay.getURL( self._abstract ) )
+        else:
+            wp = abstracts.WPAbstractWithdraw( self, self._abstract )
+            return wp.display()
+
+
+class RHAbstractRecovery( RHAbstractModificationBase ):
+    _uh = urlHandlers.UHAbstractWithdraw
+
+    def _checkParams( self, params ):
+        RHAbstractModificationBase._checkParams( self, params )
+        self._action = ""
+        if params.has_key("OK"):
+            self._action = "RECOVER"
+        elif params.has_key("cancel"):
+            self._action = "CANCEL"
+
+    def _processIfOpened( self ):
+        if self._action == "CANCEL":
+            self._redirect( urlHandlers.UHAbstractDisplay.getURL( self._abstract ) )
+        elif self._action == "RECOVER":
+            status=self._abstract.getCurrentStatus()
+            if isinstance(status,review.AbstractStatusWithdrawn):
+                if status.getResponsible()!=self._getUser():
+                    raise MaKaCError( _("you are not allowed to recover this abstract"))
+                self._abstract.recover()
+            self._redirect( urlHandlers.UHAbstractDisplay.getURL( self._abstract ) )
+        else:
+            wp = abstracts.WPAbstractRecovery( self, self._abstract )
+            return wp.display()
+
+class RHGetAttachedFile(RHFileAccess):
+
+    def _checkProtection( self ):
+        if not self._conf.getAbstractMgr().showAttachedFilesContribList():
+            # Same protection as the abstract
+            temptarget=self._target
+            self._target = self._target.getOwner()
+            RHFileAccess._checkProtection( self )
+            self._target = temptarget