# -*- 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