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/>.
17 from flask
import request
20 import MaKaC
.webinterface
.locators
as locators
21 import MaKaC
.webinterface
.urlHandlers
as urlHandlers
22 import MaKaC
.webinterface
.pages
.category
as category
23 from MaKaC
.webinterface
.user
import UserListModificationBase
24 from indico
.core
.config
import Config
25 from MaKaC
.common
.utils
import validMail
26 from MaKaC
.webinterface
.rh
.base
import RHModificationBaseProtected
27 from MaKaC
.errors
import MaKaCError
, FormValuesError
, NotFoundError
28 import MaKaC
.conference
as conference
30 from indico
.modules
.users
.legacy
import AvatarUserWrapper
31 from indico
.modules
.groups
.legacy
import GroupWrapper
32 from indico
.util
.i18n
import _
35 class RHCategModifBase( RHModificationBaseProtected
):
37 def _checkProtection(self
):
38 if self
._target
.canModify( self
.getAW() ):
39 RHModificationBaseProtected
._checkProtection
(self
)
42 self
._doProcess
= False
43 self
._redirect
(urlHandlers
.UHCategoryDisplay
.getURL(self
._target
))
45 def _checkParams(self
, params
):
46 l
= locators
.CategoryWebLocator(params
)
47 self
._target
= l
.getObject()
48 if self
._target
is None:
49 raise NotFoundError(_("The category with id '{}' does not exist or has been deleted").format(
51 title
=_("Category not found"))
54 class RHCategoryModification(RHCategModifBase
):
55 _uh
= urlHandlers
.UHCategoryModification
58 p
= category
.WPCategoryModification(self
, self
._target
)
62 class RHCategoryDataModif( RHCategModifBase
):
63 _uh
= urlHandlers
.UHCategoryDataModif
66 p
= category
.WPCategoryDataModification( self
, self
._target
)
70 class RHCategoryPerformModification( RHCategModifBase
):
71 _uh
= urlHandlers
.UHCategoryPerformModification
73 def _checkParams(self
, params
):
74 RHCategModifBase
._checkParams
(self
, params
)
75 if params
.get("name", "").strip() =="":
76 raise FormValuesError("Please, provide a name for the new subcategory")
78 def _getNewTempFile( self
):
79 cfg
= Config
.getInstance()
80 tempPath
= cfg
.getUploadedFilesTempDir()
81 tempFileName
= tempfile
.mkstemp( suffix
="Indico.tmp", dir = tempPath
)[1]
84 def _saveFileToTemp(self
, fs
):
85 fileName
= self
._getNewTempFile
()
90 params
= self
._getRequestParams
()
92 if not "cancel" in params
:
93 if (params
.get("subcats","")):
97 if (params
.get("modifyConfTZ","")):
101 tz
= params
.get("defaultTimezone", "UTC")
102 self
._target
.setTimezone( tz
)
104 self
._target
.changeConfTimezones( tz
)
106 if params
.get("name", "") != self
._target
.getName():
107 self
._target
.setName( params
.get("name", "") )
109 self
._target
.setDescription( params
.get("description", "") )
110 self
._target
.setDefaultStyle("simple_event",params
.get("defaultSimpleEventStyle", ""),subcat
)
111 self
._target
.setDefaultStyle("meeting",params
.get("defaultMeetingStyle", ""),subcat
)
112 if self
._target
.getVisibility() != int(params
.get("visibility",999)):
113 self
._target
.setVisibility(params
.get("visibility",999))
114 if self
._getUser
().isAdmin():
115 self
._target
.setSuggestionsDisabled('disableSuggestions' in request
.form
)
116 if "delete" in params
and self
._target
.getIcon() is not None:
117 self
._target
.removeIcon()
118 if "icon" in params
and type(params
["icon"]) != str and \
119 params
["icon"].filename
.strip() != "":
120 if not hasattr(self
, "_filePath"):
121 # do not save the file again if it has already been done (db conflicts)
122 self
._filePath
= self
._saveFileToTemp
(params
["icon"])
123 self
._tempFilesToDelete
.append(self
._filePath
)
124 self
._fileName
= params
["icon"].filename
126 f
= conference
.LocalFile()
128 f
.setDescription( "This is the icon for the category" )
129 f
.setFileName( self
._fileName
)
130 f
.setFilePath( self
._filePath
)
131 self
._target
.setIcon( f
)
132 if "tasksAllowed" in params
:
133 if params
["tasksAllowed"] == "allowed" :
134 self
._target
.setTasksAllowed()
136 self
._target
.setTasksForbidden()
138 self
._redirect
( urlHandlers
.UHCategoryModification
.getURL( self
._target
) )
141 class RHCategoryTaskOption( RHCategModifBase
):
142 _uh
= urlHandlers
.UHCategoryTasksOption
144 def _process( self
):
146 if self
._target
.tasksAllowed() :
147 self
._target
.setTasksForbidden()
149 self
._target
.setTasksAllowed()
151 self
._redirect
( urlHandlers
.UHCategoryModification
.getURL( self
._target
) )
155 class RHCategoryAC( RHCategModifBase
):
156 _uh
= urlHandlers
.UHCategModifAC
158 def _process( self
):
159 p
= category
.WPCategModifAC( self
, self
._target
)
163 class RHCategoryTools( RHCategModifBase
):
164 _uh
= urlHandlers
.UHCategModifTools
166 def _process( self
):
167 p
= category
.WPCategModifTools( self
, self
._target
)
171 class RHCategoryTasks( RHCategModifBase
):
172 _uh
= urlHandlers
.UHCategModifTasks
174 def _process( self
):
175 p
= category
.WPCategModifTasks( self
, self
._target
)
179 class RHCategoryTasksAction( RHCategModifBase
):
180 _uh
= urlHandlers
.UHCategModifTasksAction
182 def _process( self
):
183 params
= self
._getRequestParams
()
185 if params
.get("accessVisibility","") == _("PRIVATE") :
186 self
._target
.setTasksPrivate()
187 elif params
.get("accessVisibility","") == _("PUBLIC") :
188 self
._target
.setTasksPublic()
192 if params
.get("commentVisibility","") == _("PRIVATE") :
193 self
._target
.setTasksCommentPrivate()
194 elif params
.get("commentVisibility","") == _("PUBLIC") :
195 self
._target
.setTasksCommentPublic()
199 if params
.get("taskAccessAction","") == "Add":
200 chosen
= params
.get("accessChosen",None)
201 if chosen
is not None and chosen
!= "" :
202 person
= self
._findPerson
(chosen
)
203 if person
is not None :
204 self
._target
.addTasksAccessPerson(person
)
205 elif params
.get("taskAccessAction","") == "New":
207 elif params
.get("taskAccessAction","") == "Remove":
208 chosen
= self
._normaliseListParam
(params
.get("access", []))
210 self
._target
.removeTasksAccessPerson(int(c
))
214 if params
.get("taskCommentAction","") == "Add":
215 chosen
= params
.get("commentChosen",None)
216 if chosen
is not None and chosen
!= "" :
217 person
= self
._findPerson
(chosen
)
218 if person
is not None :
219 self
._target
.addTasksCommentator(person
)
220 elif params
.get("taskCommentAction","") == "New":
222 elif params
.get("taskCommentAction","") == "Remove":
223 chosen
= self
._normaliseListParam
(params
.get("commentator", []))
225 self
._target
.removeTasksCommentator(int(c
))
230 if params
.get("taskManagerAction","") == "Add":
231 chosen
= params
.get("managerChosen",None)
232 if chosen
is not None and chosen
!= "" :
233 person
= self
._findPerson
(chosen
)
234 if person
is not None :
235 self
._target
.addTasksManager(person
)
236 elif params
.get("taskManagerAction","") == "New":
238 elif params
.get("taskManagerAction","") == "Remove":
239 chosen
= self
._normaliseListParam
(params
.get("manager", []))
241 self
._target
.removeTasksManager(int(c
))
246 p
= category
.WPCategModifTasks( self
, self
._target
)
249 def _findPerson(self
, idString
):
250 if idString
is None or idString
== "" :
252 if idString
[0] == "c" :
253 return self
.getTasksCommentator(int(idString
[1:]))
254 elif idString
[0] == "a" :
255 return self
._target
.getTasksAccessPerson(int(idString
[1:]))
257 index
= idString
.find("-")
258 eventId
= idString
[1:index
]
259 personId
= idString
[index
+1:]
261 if idString
[0] == "h" :
262 return self
._target
.getConferenceById(eventId
).getChairById(personId
)
263 elif idString
[0] == "m" :
264 return self
._target
.getConferenceById(eventId
).getManagerList()[int(personId
)]
265 elif idString
[0] == "p" :
266 return self
._target
.getConferenceById(eventId
).getParticipation().getParticipantById(personId
)
270 class RHCategoryCreation( RHCategModifBase
):
271 _uh
= urlHandlers
.UHCategoryCreation
273 def _process( self
):
274 p
= category
.WPCategoryCreation( self
, self
._target
)
278 class RHCategoryPerformCreation( RHCategModifBase
):
279 _uh
= urlHandlers
.UHCategoryPerformCreation
281 def _checkParams(self
, params
):
282 RHCategModifBase
._checkParams
(self
, params
)
283 if params
.get("name", "").strip() =="" and not ("cancel" in params
):
284 raise FormValuesError("Please, provide a name for the new subcategory")
286 def _process( self
):
287 params
= self
._getRequestParams
()
288 if not ("cancel" in params
):
290 categAccessProtection
= params
.get("categProtection", "inherit")
292 if categAccessProtection
== "private" :
294 elif categAccessProtection
== "public" :
299 nc
= self
._target
.newSubCategory(protection
)
301 nc
.setTimezone( params
.get("defaultTimezone"))
302 nc
.setName( params
.get("name", "") )
303 nc
.setDescription( params
.get("description", "") )
304 nc
.setDefaultStyle("simple_event",params
.get("defaultSimpleEventStyle", "") )
305 nc
.setDefaultStyle("meeting",params
.get("defaultMeetingStyle", "") )
308 allowedUsers
= self
._getAllowedUsers
(params
)
310 for person
in allowedUsers
:
311 if isinstance(person
, (AvatarUserWrapper
, GroupWrapper
)):
312 nc
.grantAccess(person
)
314 self
._redirect
( urlHandlers
.UHCategoryModification
.getURL( self
._target
) )
317 def _getAllowedUsers(self
, params
):
320 from MaKaC
.services
.interface
.rpc
import json
321 allowedUsersDict
= json
.decode(params
.get("allowedUsers"))
322 if allowedUsersDict
:
323 auAvatars
, auNewUsers
, auEditedAvatars
= UserListModificationBase
.retrieveUsers({"allowedUserList":allowedUsersDict
}, "allowedUserList")
328 class _ActionSubCategDeletion
:
330 def __init__( self
, rh
, target
, selCategs
):
332 self
._target
= target
333 self
._categs
= selCategs
335 def askConfirmation( self
, params
):
336 p
= category
.WPSubCategoryDeletion( self
._rh
, self
._target
)
337 return p
.display( subCategs
=self
._categs
)
340 for categ
in self
._categs
:
341 for manager
in categ
.getManagerList():
342 categ
.revokeModification(manager
)
345 class _ActionSortCategories
:
347 def __init__( self
, rh
):
350 def askConfirmation( self
, params
):
354 cl
= self
._rh
._target
.getSubCategoryList()
355 cl
.sort(key
=lambda c
: c
.getTitle().lower())
357 categ
.setOrder(cl
.index(categ
))
359 class _ActionSubCategMove
:
361 def __init__( self
, rh
, newpos
, oldpos
):
363 self
._newpos
= int(newpos
)
364 self
._oldpos
= int(oldpos
)
366 def askConfirmation( self
, params
):
370 cl
= self
._rh
._target
.getSubCategoryList()
372 movedcateg
= cl
[self
._oldpos
]
374 cl
.insert(self
._newpos
,movedcateg
)
376 categ
.setOrder(cl
.index(categ
))
378 class _ActionSubCategReallocation
:
380 def __init__( self
, rh
, target
, selCategs
):
382 self
._target
= target
383 self
._categs
= selCategs
385 def askConfirmation( self
, params
):
386 p
= category
.WPCategoryReallocation( self
._rh
, self
._target
)
387 params
["subCategs"] = self
._categs
388 return p
.display( **params
)
391 #check if the current user has modification privileges on the
392 # destination category
393 if not self
._target
.canModify( self
._rh
.getAW() ):
394 raise MaKaCError( _("cannot reallocate selected categoried to the selected destination because you are not authorised to modify the destination category"))
395 for categ
in self
._categs
:
396 categ
.move( self
._target
)
399 class RHCategoryActionSubCategs( RHCategModifBase
):
400 _uh
= urlHandlers
.UHCategoryActionSubCategs
402 def _checkParams( self
, params
):
403 RHCategModifBase
._checkParams
( self
, params
)
404 categIdList
= self
._normaliseListParam
(params
.get("selectedCateg", []))
406 self
._confirmation
= params
.has_key("confirm")
407 if "cancel" in params
:
409 cm
= conference
.CategoryManager()
410 for categId
in categIdList
:
411 self
._categs
.append( cm
.getById( categId
) )
412 self
._action
= _ActionSubCategDeletion( self
, self
._target
, self
._categs
)
413 if params
.has_key("reallocate"):
414 self
._action
= _ActionSubCategReallocation( self
, self
._target
, self
._categs
)
415 if params
.has_key("oldpos") and params
["oldpos"]!='':
416 self
._confirmation
= 1
417 self
._action
= _ActionSubCategMove( self
, params
['newpos'+params
['oldpos']], params
['oldpos'] )
418 if params
.has_key("sort"):
419 self
._confirmation
= 1
420 self
._action
= _ActionSortCategories( self
)
422 def _process( self
):
424 if self
._confirmation
:
426 self
._action
.perform()
428 if self
._confirmation
:
430 self
._action
.perform()
432 return self
._action
.askConfirmation(self
._getRequestParams
())
433 self
._redirect
(urlHandlers
.UHCategoryModification
.getURL(self
._target
))
436 class _ActionConferenceDeletion
:
438 def __init__(self
, rh
, target
, selConfs
):
440 self
._target
= target
441 self
._confs
= selConfs
443 def perform(self
, confs
):
447 def askConfirmation(self
, params
):
448 p
= category
.WPConferenceDeletion(self
._rh
, self
._target
)
449 return p
.display(events
=self
._confs
)
452 class _ActionConferenceReallocation
:
454 def __init__( self
, rh
, srcCateg
, selConfs
, target
):
456 self
._categ
= srcCateg
457 self
._confs
= selConfs
460 def askConfirmation( self
, params
):
461 p
= category
.WPConferenceReallocation( self
._rh
, self
._categ
)
462 params
["confs"] = self
._confs
463 return p
.display( **params
)
465 def perform(self
, confs
):
466 # TODO: check if the current user can create conferences on the destination category
469 for conf
in self
._confs
:
470 if self
._categ
== conf
.getOwner():
471 self
._categ
.moveConference(conf
, self
._target
)
474 class RHCategoryActionConferences(RHCategModifBase
):
475 _uh
= urlHandlers
.UHCategoryActionConferences
477 def _checkParams( self
, params
):
478 RHCategModifBase
._checkParams
( self
, params
)
479 confIdList
= self
._normaliseListParam
(params
.get("selectedConf", []))
481 self
._confirmation
= params
.has_key("confirm")
482 if "cancel" in params
:
484 ch
= conference
.ConferenceHolder()
485 for confId
in confIdList
:
486 self
._confs
.append( ch
.getById( confId
) )
487 self
._action
= _ActionConferenceDeletion( self
, self
._target
, self
._confs
, )
488 if params
.has_key("reallocate"):
489 self
._srcCateg
= self
._target
490 if self
._confirmation
:
491 cm
= conference
.CategoryManager()
492 self
._srcCateg
= cm
.getById( params
["srcCategId"] )
493 self
._action
= _ActionConferenceReallocation( self
, self
._srcCateg
, self
._confs
, self
._target
)
495 def _process( self
):
496 if self
._confirmation
:
497 self
._action
.perform(self
._confs
)
498 self
._redirect
( urlHandlers
.UHCategoryModification
.getURL( self
._target
) )
500 self
._redirect
( urlHandlers
.UHCategoryModification
.getURL( self
._target
) )
502 return self
._action
.askConfirmation( self
._getRequestParams
() )
505 class RHCategorySetVisibility( RHCategModifBase
):
506 _uh
= urlHandlers
.UHCategorySetVisibility
508 def _process( self
):
509 params
= self
._getRequestParams
()
510 if params
.has_key("changeToPrivate"):
511 self
._target
.setProtection( 1 )
512 elif params
.has_key("changeToInheriting"):
513 self
._target
.setProtection( 0 )
514 elif params
.has_key("changeToPublic"):
515 # The 'Home' category is handled as a special case.
516 # We maintain the illusion for the user of it being either
517 # private or public, but actually it can be either private
518 # or inheriting for legacy reasons.
519 if params
["type"] == "Home":
520 self
._target
.setProtection( 0 )
522 self
._target
.setProtection( -1 )
523 self
._redirect
( urlHandlers
.UHCategModifAC
.getURL( self
._target
) )
526 class RHCategorySetConfControl( RHCategModifBase
):
527 _uh
= urlHandlers
.UHCategorySetConfCreationControl
529 def _process( self
):
530 params
= self
._getRequestParams
()
531 if "RESTRICT" in self
._getRequestParams
():
532 self
._target
.restrictConferenceCreation()
534 self
._target
.allowConferenceCreation()
535 self
._redirect
( urlHandlers
.UHCategModifAC
.getURL( self
._target
) )
538 class RHCategorySetNotifyCreation( RHCategModifBase
):
539 _uh
= urlHandlers
.UHCategorySetNotifyCreation
541 def _checkParams(self
, params
):
542 RHCategModifBase
._checkParams
(self
, params
)
543 self
._emailList
= params
.get("notifyCreationList","")
544 if self
._emailList
.strip() != "" and not validMail(self
._emailList
):
545 raise FormValuesError(_("The email list contains invalid e-mail addresses or invalid separator"))
547 def _process( self
):
548 self
._target
.setNotifyCreationList(self
._emailList
)
549 self
._redirect
( urlHandlers
.UHCategModifAC
.getURL( self
._target
) )
552 class RHCategoryDeletion(RHCategModifBase
):
553 _uh
= urlHandlers
.UHCategoryDeletion
555 def _checkParams( self
, params
):
556 RHCategModifBase
._checkParams
( self
, params
)
558 if "cancel" in params
:
560 self
._confirmation
= params
.has_key("confirm")
562 def _perform( self
):
563 self
._target
.delete(1)
565 def _process( self
):
567 self
._redirect
( urlHandlers
.UHCategModifTools
.getURL( self
._target
) )
568 elif self
._confirmation
:
569 owner
= self
._target
.getOwner()
571 self
._redirect
(urlHandlers
.UHCategoryModification
.getURL(owner
))
573 p
= category
.WPCategoryDeletion(self
, self
._target
)