# -*- coding: utf-8 # $Id$ # # Copyright 2001, 2002 by IVA Team and contributors # # This file is part of IVA. # # IVA 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 2 of the License, or # (at your option) any later version. # # IVA 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 IVA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Contains class WebtopItem, which contains common methods that are inherited to all specific webtop items.""" __version__ = "$Revision$"[11:-2] #from Globals import Persistent, HTMLFile import AccessControl import Globals import OFS from AccessControl import ClassSecurityInfo from AccessControl.PermissionRole import rolesForPermissionOn from Products.ZCatalog.CatalogPathAwareness import CatalogAware from common import _mergedLocalRoles #from Products.CMFCore.utils import _mergedLocalRoles from common import mkTime from DateTime.DateTime import DateTime import time import re from common import translate import TraversableWrapper #from UserInfo import UserInf from common import perm_view, perm_edit, perm_manage, perm_add_lo, \ get_local_roles, get_roles from Errors import FleError from Cruft import Cruft from zope.interface import implements from interfaces import IWebtopItem, IStatistics from zope.component import adapter, getUtility from zope.component.interfaces import ComponentLookupError from zope.app.container.interfaces import IObjectAddedEvent from OFS.interfaces import IObjectWillBeRemovedEvent START_TIME = DateTime(1000, 0) END_TIME = DateTime(2500, 0) class WebtopItem( CatalogAware, TraversableWrapper.Traversable, AccessControl.Role.RoleManager, Globals.Persistent, Cruft,): """A generic Webtop item. This is an 'abstract' class and should not be used directly. Instantiate a WebtopFile, WebtopFolder, WebtopLink or WebtopMemo instead.""" meta_type = "WebtopItem" security = ClassSecurityInfo() implements(IWebtopItem) def __init__(self, parent, name): """Construct the webtop item object. NOTE: This constructor must be called from the subclass's constructor.""" self.default_catalog = 'catalog_webtop_items' if parent: self.id = parent.generate_id() else: self.id = 'wt0' self.set_name(name) self.set_icon('document_gif.gif') self.do_stamp() self.weight = 1000 self.userComments = [] self.docStatus = 0 self.userRating = None self.userCommentsAllowed = 1 self.commentsVisible = 1 self.ratingVisible = 1 self.userRatingAllowed = 1 self.objPermission = 0 # default viewable by the same course members self.timeFunc = 0 self.timeLimitStart = time.time() #not sure this is needed self.timeLimitEnd = time.time() #not sure this is needed self.subgroup_public = '' def findWeight(self): algus = 1000 suurused = [] for mini in self.aq_parent.objectValues(): try: mid = mini.get_id() except AttributeError: continue if mini.get_id() == self.get_id(): continue if hasattr(mini,'weight'): suurused.append(mini.weight) weight_found = 0 while not weight_found: if algus in suurused: algus = algus - 1 else: self.weight = algus weight_found = 1 return self.weight def getWeight(self): try: return self.weight except AttributeError: return 900 security.declareProtected(perm_view,'get_timestamp') def get_timestamp(self): """Return timestamp in time.time() format.""" try: return self.__timestamp except AttributeError: return 0 security.declarePrivate('set_timestamp') def set_timestamp(self,time): """Set timestamp to new value.""" self.__timestamp=time security.declarePrivate('do_stamp') def do_stamp(self): """Set timestamp to current time.""" self.__timestamp = time.time() security.declareProtected(perm_view, 'getRelativeContentURL') def getRelativeContentURL(self): """ relative url from portal root """ return self.getRelativeURL(self) security.declarePrivate('set_icon') def set_icon(self, img): """Sets the icon path for this webtop item.""" self.iconpath=img security.declareProtected(perm_view,'get_icon') def get_icon(self): """Returns the icon object for the path stored in this item.""" if self.iconpath.endswith('_gif'): self.iconpath += '.gif' try: return self.unrestrictedTraverse(self.iconpath) except KeyError: return None def get_icon_path(self): ico = self.iconpath if 'images' in self.iconpath: self.iconpath = self.iconpath.replace('images/', '') if self.iconpath.endswith('_gif'): return self.iconpath+'.gif' return self.iconpath security.declareProtected(perm_view, 'get_icon_tag') def get_icon_tag(self): """ return img tag """ if self.iconpath.endswith('_gif'): self.iconpath += '.gif' return """""" % (self.fle_root().absolute_url()+'/'+self.iconpath.split('/')[-1]) # FIXME: Add comment security.declareProtected(perm_view,'get_list_item_name') def get_list_item_name(self, REQUEST=None): """Returns the displayable string to be used when the item is shown in a folder contents list.""" return self.get_name() security.declareProtected(perm_view,'get_name') def get_name(self): """Returns the name of this item.""" return self.title security.declareProtected(perm_view,'get_name') def getTitle(self): """Returns the name of this item.""" return self.title security.declarePrivate('set_name') def set_name(self,newname): """Changes the name of this item.""" self.title=newname security.declareProtected(perm_view, 'get_author') def get_author(self): """Return author (owner) of this item.""" return self.getOwnerTuple()[1] def get_author_name(self): owner = self.getOwner() if not owner: return '' try: return owner.name except AttributeError: return owner.getUserName() security.declarePrivate('set_author') def set_author(self,author): """Set the author (owner) of this item.""" self.manage_setLocalRoles(author,('Owner',)) security.declarePrivate('get_content') def get_content(self): """This must be overridden in inherited class""" raise 'FLE Error', 'method get_content() not implemented.' security.declareProtected(perm_view,'get_size') def get_size(self): """Return size (in bytes) of the WebTop item. this must be overridden in inherited class.""" raise 'FLE Error', 'method get_size() not implemented.' def viimaneMuutus(self): "Viimane muutmisaeg" return self.get_timestamp() security.declareProtected(perm_view,'get_printable_size') def get_printable_size(self, size, REQUEST): """Return pritable size: scaled size + unit.""" #size = self.get_size() if hasattr(size, 'im_func'): size = size() if size >= 1024*1024: size = size / (1024.0 * 1024) retval = str(round(size, 1)) + ' ' + translate(self,'MB',target=self.giveLanguage(REQUEST)) elif size >= 1024: size = size / 1024.0 retval = str(round(size, 1)) + ' ' + translate(self,'KB',target=self.giveLanguage(REQUEST)) else: # Why don't we return the real size of small objects? retval = '1 ' + translate(self,'KB',target=self.giveLanguage(REQUEST)) return retval security.declareProtected(perm_edit, 're_index') def re_index(self): """ reindexes webtop """ raskus = 1000 for wi in self.objectValues(): wi.weight = raskus raskus = raskus + 1 self.reindex_object() return "done, hit back button" security.declareProtected(perm_edit, 'kaal') def kaal(self,REQUEST,alla=0,yles=0): """ kaal """ if not alla: alla = 0 if not yles: yles = 0 if not alla and not yles: return miinimum = 10000 maksimum = 1 for mini in self.aq_parent.objectValues(): mid = None try: mid = mini.get_id() except AttributeError: continue if mid == self.get_id(): continue try: if mini.weight < miinimum: miinimum = mini.weight if mini.weight > maksimum: maksimum = mini.weight except AttributeError: mini.findWeight() if alla: if self.weight > miinimum or self.weight == miinimum: self.weight = self.weight-1 else: if self.weight < maksimum or self.weight == maksimum: self.weight = self.weight+1 suurused = [] for mini in self.aq_parent.objectValues(): mid = None try: mid = mini.get_id() except AttributeError: continue if mid == self.get_id(): continue if mini.weight == self.weight: if alla: mini.weight = mini.weight + 1 else: mini.weight = mini.weight - 1 mini.reindex_object() found_weight = 0 while not found_weight: if self.weight in suurused: self.weight = self.weight + 1 else: found_weight = 1 #return dir(self) self.reindex_object() return REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url()+"?suund=getWeight") def may_edit(self,uname): """Returns whether user may edit this object or not.""" ## raise 'foo',str(self.get_local_roles()) + " vs. " + str(get_local_roles(self,uname)) + " with " + uname ## raise 'foo',self.get_name() + str(get_local_roles(self,uname)) objs = self.aq_chain for x in objs: if hasattr(x, '_is_subgroup'): if x._is_subgroup: #XXX: do the role checking lr = x.aq_self.get_local_roles() for y in lr: if str(y[0])==str(uname): return 1 if self.get_id() == 'subgroups': return 0 if 'Owner' in get_local_roles(self,uname): return 1 if 'Teacher' in get_roles(self,uname): return 1 if 'Manager' in get_roles(self,uname): return 1 return 0 def may_editNG(self, REQUEST, obj): """ Returns whether user may edit this object or not.""" # lroles = get_roles(self, str(REQUEST.AUTHENTICATED_USER)) if 'Teacher' in lroles: return 1 if 'Manager' in lroles: return 1 if 'IVAAdmin' in lroles: return 1 er = obj.editRolesAndUsers if callable(er): er = obj.editRolesAndUsers() if 'user:'+str(REQUEST.AUTHENTICATED_USER) in er: return 1 return 0 security.declareProtected(perm_view, 'postComment') def postComment(self, REQUEST=None, addcomment='', comment='notCommentable', rating=None, cStatus=0,uname='',date=0): """ post user comment """ import time error = 0 if comment == 'notCommentable': comment = '' if not self.isCommentable() and not self.isRateable(): return REQUEST.RESPONSE.redirect('wt_usercomments?error=2') if not addcomment: return REQUEST.RESPONSE.redirect('wt_usercomments?error=1') if not self.isCommentable() and self.isRateable() and rating==None: error = 1 if not self.isRateable() and self.isCommentable() and comment=='notCommentable': error = 1 if comment == '' and rating == None: return REQUEST.RESPONSE.redirect('wt_usercomments?error=3') if date: timestamp = date else: timestamp = time.time() input = [] if uname and not REQUEST: input.append(uname) else: input.append(str(REQUEST.AUTHENTICATED_USER)) input.append(cStatus) input.append(timestamp) input.append(str(rating)) input.append(comment) self.userComments.append(input) # self.userComments.append((REQUEST.AUTHENTICATED_USER,str(rating),timestamp,comment),) self.userComments = self.userComments komm = self.getComments() count = 0 total = 0 for x in komm: if x[3] == None or x[3] == 'None' or x[1]!=0: continue count = count + 1 total = total + int(x[3]) if not count or not total: self.userRating = None else: self.userRating = total/count self.userRating = self.userRating if REQUEST: return REQUEST.RESPONSE.redirect('../index_html') else: return 1 security.declareProtected(perm_view, 'getComments') def getComments(self, REQUEST=None): """ get user comment """ return self.userComments security.declareProtected(perm_view, 'getCommentCount') def getCommentCount(self): """ counts comments """ return str(len(self.userComments)) def getDocStatus(self, REQUEST=None): return self.docStatus def hasComments(self): if self.userComments != []: return 1 else: return 0 def hasRating(self): if self.userRating != None: return 1 else: return 0 def getRating(self): return self.userRating def wordStatus(self,REQUEST, number): number = int(number) stats = ('Unset','','Draft','','Revising','','Final') return stats[number] def wordRating(self,REQUEST, number): if number == None: return 'not rated' if number == 'None': number = 0 else: try: number = int(number) except: number = 6 ratings = ('not rated','Bad','Poor','Average','Good','Excellent','System error') return ratings[number] def zeroComments(self): """ deletes all comments """ self.userComments = [] self.userComments = self.userComments return "done" def isCommentable(self): return getattr(self.aq_self, 'userCommentsAllowed') def isCommentsVisible(self): return getattr(self.aq_self, 'commentsVisible') def isRatingVisible(self): return getattr(self.aq_self, 'ratingVisible') security.declarePrivate('setCommentsVisible') def setCommentsVisible(self,value=0): self.commentsVisible = int(value) return self.commentsVisible security.declarePrivate('setRatingVisible') def setRatingVisible(self,value=0): self.ratingVisible = int(value) return self.ratingVisible def isRateable(self): return getattr(self.aq_self, 'userRatingAllowed') security.declarePrivate('setCommentable') def setCommentable(self, value=0): if value == '1' or value == 1: self.userCommentsAllowed = 1 else: self.userCommentsAllowed = 0 return self.userCommentsAllowed security.declarePrivate('setRateable') def setRateable(self, value=0): if value == '1': self.userRatingAllowed = 1 else: self.userRatingAllowed = 0 return self.userRatingAllowed security.declarePrivate('setStatus') def setStatus(self, value=0): #XXX: weird things happen if self==folder # wt_itemProp form doesn't have these fields try: self.docStatus = int(value) self.docStatus = self.docStatus except: pass return self.docStatus def getObjPermission(self): return self.objPermission security.declarePrivate('setObjPermission') def setObjPermission(self, value=0): if int(value) == 10: # everyone should be able to access it... self.manage_permission('View', ('Anonymous',), 1) if int(value) == 2: self.manage_permission('View', ('IVAAdmin', 'Items', 'Manager', 'Teacher'), 0) if int(value) == 4: self.manage_permission('View', ('Owner', 'IVAAdmin', 'Manager', 'Teacher'), 0) if int(value) == 6: self.manage_permission('View', ('Manager', 'IVAAdmin', 'Owner'), 0) if int(value) == 0: self.manage_permission('View', (), 1) self.objPermission = int(value) self.objPermission = self.objPermission return self.objPermission security.declarePrivate('setTimeFunc') def setTimeFunc(self, value=0): self.timeFunc = int(value) self.timeFunc = self.timeFunc return self.timeFunc def getTimeFunc(self): return self.timeFunc security.declarePrivate('setTimeLimits') def setTimeLimits(self, start=0, end=0): self.timeLimitStart=start self.timeLimitEnd=end return 1 def getTimeBar(self, muutuja, aeg=0): if not aeg: aeg = time.time() from YlTest import LahendusLuba abi = LahendusLuba() return abi.ajaMuutmisElemendid(muutuja, aeg) def getStartTime(self): return self.timeLimitStart def getEndTime(self): return self.timeLimitEnd def getStartTimeIndex(self): if not self.getTimeFunc(): return START_TIME return DateTime(self.timeLimitStart) def getEndTimeIndex(self): if not self.getTimeFunc(): return END_TIME return DateTime(self.timeLimitEnd) security.declarePrivate('setUsers') def setUsers(self, uname): # gives user a permission to view object #print self.fle_root().fle_users.is_valid_uname(uname) if self.fle_root().fle_users.leiaKasutajaKataloog(uname): old_roles = get_local_roles(self,uname) if 'Items' not in old_roles: new_roles = old_roles+('Items',) else: new_roles = old_roles self.manage_setLocalRoles(uname,new_roles) # try: #XXX: this is wrong! ui = self.fle_root().fle_users.get_user_info(uname) ui.setLongLink(self.aq_parent.absolute_url()+'/'+self.id) # except: # pass else: pass security.declarePrivate('removeUsers') def removeUsers(self,uname): if self.fle_root().fle_users.is_valid_uname(uname): old_roles = self.get_local_roles_for_userid(uname) new_roles = () for role in old_roles: if role!='Items': new_roles += (role,) if not new_roles: self.manage_delLocalRoles((uname,)) #delRoles takes tuple! else: self.manage_setLocalRoles(uname,new_roles) try: ui = self.fle_root().fle_users.get_user_info(uname) ui.unsetLongLink(self.absolute_url()) except: pass return 1 def hasPermissionToView(self,REQUEST): # student who has been assigned peer review task gets permission. Ofcourse, we check if # it IS an assignment folder. is_assign = self.is_assignment() try: is_parent_assign = self.aq_parent.is_assignment() except: is_parent_assign = 0 if is_assign or is_parent_assign: #thisAssign = self.kysiToo(REQUEST) thisAssign = self.get_assignment() m = self.absolute_url().split('/') jargmine = 0 selle_kausta_omanik = '' for x in m: if jargmine: selle_kausta_omanik = x break if x == 'fle_users': jargmine = 1 #get list of assignments. #get id of this assignment #filter out peer review assignments and see if list has this assignment id in it. nr = self.jooksva_kursuse_nr(REQUEST) as = getattr(self.fle_root().courses, str(nr)).kodutood list = as.listAssignments() tmp = [] for x in list: if int(x.getRawType()) == 4: tmp.append(x) for x in tmp: if x.hwID == thisAssign.get_id(): unames = x.getReviewers(str(REQUEST.AUTHENTICATED_USER)) if selle_kausta_omanik in unames: return 1 return 1 perm = self.getObjPermission() if perm == 10: return 1 if self.getOwnerTuple()[1] == str(REQUEST.AUTHENTICATED_USER): return 1 if self.getTimeFunc() and self.getStartTime()time.time(): # we fit timelimits pass elif not self.getTimeFunc(): pass else: # TODO: check roles here. allow teachers and manager inside folder perm = 4 #return 0 if perm == 0: #XXX:check once more, if user is in give course if self.is_student(REQUEST) or self.kas_opetaja(REQUEST): return 1 elif perm == 6: #XXX:check if given user is owner of this object if self.getOwnerTuple()[1]==str(REQUEST.AUTHENTICATED_USER): return 1 else: return 0 elif perm == 4: if self.kas_opetaja(REQUEST): return 1 else: return 0 elif perm == 2: # see if given user has some rights if 'Items' in self.get_local_roles_for_userid(str(REQUEST.AUTHENTICATED_USER)): return 1 else: return 0 if perm == 20: tmp = getattr(self.fle_root().courses, self.jooksva_kursuse_nr(REQUEST)).subgroups # XXX: gives error. try: x = getattr(tmp, self.getSubgroupName()) except AttributeError: # if we can't get subgroup name, assume user can view it return 1 #XXX: do the role checking lr = x.aq_self.get_local_roles() for y in lr: if str(y[0])==str(REQUEST.AUTHENTICATED_USER): return 1 return 0 def listLocalUserRoles(self,roll): """ lists userroles """ roles = self.get_local_roles() uname=() for role in roles: if roll in role[1]: uname += (role[0],) return uname def hasLocalRole(self,uid,role): """ if user has local role """ if role in self.get_local_roles_for_userid(uid): return 1 else: return 0 def getSubgroupName(self): """ return subgroup name for which object is public """ sg = self.aq_self.subgroup_public if not sg: for x in self.aq_chain[:-1]: try: if x.aq_self.subgroup_public: self.setSubgroupName(x.aq_self.subgroup_public) return x.aq_self.subgroup_public except: return "" else: return sg security.declarePrivate('setSubgroupName') def setSubgroupName(self, sgname): """ set subgroup name for which object is public """ self.aq_self.subgroup_public = sgname security.declareProtected(perm_edit,'itemPropPoster') def itemPropPoster(self, REQUEST, ifcomment=0, saveProp='', ifrateable=0, docStatus='', objPermission='', ifShowComment=0, ifShowRating=0, permissionWho=0, timeFunc=0,subgroup_name=''): """ saves object properties """ if not saveProp: return REQUEST.RESPONSE.redirect('wt_itemProperties?error=1') self.setCommentable(ifcomment) self.setRateable(ifrateable) self.setStatus(docStatus) self.setObjPermission(objPermission) if subgroup_name and int(objPermission)==20: self.setSubgroupName(subgroup_name) self.setCommentsVisible(ifShowComment) self.setRatingVisible(ifShowRating) # self.setExtendedPermission(permissionWho) self.setTimeFunc(timeFunc) self.setTimeLimits(mkTime(REQUEST,'Starting'), mkTime(REQUEST,'Ending')) self.reindex_object() return REQUEST.RESPONSE.redirect('index_html') security.declareProtected(perm_edit, 'itemPropUsers') def itemPropUsers(self, REQUEST=None, removePropUser='', savePropUser='', unames='', uname_hand=''): """ gives or takes permission to view object """ import types if savePropUser: if unames: if type(unames) is types.StringType: unames = (unames,) for uname in unames: self.setUsers(uname) if uname_hand: self.setUsers(uname_hand) elif removePropUser: if type(unames) is types.StringType: unames = (unames,) for uname in unames: self.removeUsers(uname) self.reindex_object() if REQUEST is not None: return REQUEST.RESPONSE.redirect("wt_userForm") else: return 1 security.declareProtected(perm_view, 'isFreshObject') def isFreshObject(self, REQUEST, brain = None, cnr=None): """ has user seen this object or is this new or changed """ lastChange = None if not brain: rurl = self.getRelativeURL(self) lastChange = self.lastModification(cnr=cnr) else: # these might also be Zope objects not ZCatalog brains if hasattr(brain.lastModification, 'im_func'): lastChange = float(brain.lastModification()) rurl = brain.getRelativeContentURL() else: lastChange = float(brain.lastModification) rurl = brain.getRelativeContentURL lastVisit = getUtility(IStatistics).getLastVisitTime( REQUEST, rurl, str(REQUEST.AUTHENTICATED_USER) ) return lastChange>lastVisit security.declareProtected(perm_view, 'is_assignment') def is_assignment(self): """ this is not assignment folder """ return 0 def allowedRolesAndUsers(self, perm='View'): """ Return a list of roles and users with View permission. """ allowed = {} for r in rolesForPermissionOn(perm, self): allowed[r] = 1 localroles = _mergedLocalRoles(self, limit=True) for user, roles in localroles.items(): for role in roles: if allowed.has_key(role): allowed['user:' + user] = 1 if allowed.has_key('Owner'): del allowed['Owner'] if not allowed.has_key('IVAAdmin'): allowed['IVAAdmin'] = 1 if not allowed.has_key('Manager'): allowed['Manager'] = 1 return list(allowed.keys()) def editRolesAndUsers(self): """ Return a list of roles and users with Edit permission. """ return self.allowedRolesAndUsers('Edit') Globals.InitializeClass(WebtopItem) @adapter(IWebtopItem, IObjectWillBeRemovedEvent) def removing(obj, event): # it seems ZCatalog's manage_beforeDelete is doing the unindexing now... #obj.unindex_object() url = obj.getRelativeURL(obj) try: getUtility(IStatistics).delObjectHistory(url) except ComponentLookupError: pass @adapter(IWebtopItem, IObjectAddedEvent) def added(obj, event): """...""" # Check if we're being added inside a Webtop (not inside a GroupFolder) # and if our owner differs from the webtop owner, change ownership import Webtop ob=obj.parent() whi_alg = time.time() while 1: if isinstance(ob,Webtop.Webtop): #raise 'foo',"YES, it's a webtop!" if obj.get_author_name() != ob.parent().get_uname(): obj.set_author(ob.parent().get_uname()) try: ob=ob.parent() except: break whi_lopp = time.time() obj.findWeight() for x in obj.aq_chain[:-1]: try: if x.is_assignment(): obj.setObjPermission(4) #self.setObjPermission(x.getObjPermission()) if getattr(x, 'subgroup_top', None): obj.setObjPermission(20) except AttributeError: pass obj.index_object() # EOF