[zopeorg-checkins] CVS: Products/Ratings - BoundedRankSet.py:1.1 RankingAlgorithm.py:1.1 RatingTool.py:1.1 Ratings.py:1.1 __init__.py:1.1
Kapil Thangavelu
kvthan at wm.edu
Wed Jun 12 12:25:48 EDT 2002
Update of /cvs-zopeorg/Products/Ratings
In directory cvs.zope.org:/tmp/cvs-serv24689
Added Files:
BoundedRankSet.py RankingAlgorithm.py RatingTool.py Ratings.py
__init__.py
Log Message:
adding ratings
=== Added File Products/Ratings/BoundedRankSet.py ===
from AccessControl import ClassSecurityInfo
from BTrees.OOBTree import OOSet
from BTrees.Length import Length
from Globals import InitializeClass
from OFS.SimpleItem import SimpleItem
class BoundedRankSet(SimpleItem):
meta_type = 'Bounded Rank Set'
security = ClassSecurityInfo()
security.declareObjectPrivate()
def __init__(self, set_bound):
self.ranked_set = OOSet()
self.set_length = Length() # useful for large sets
self.set_bound = set_bound
def setBound(self, size):
"""
sets the bound on the number of
ranked objects we hold.
"""
if size < self.set_bound:
rankings = self.ranked_set.keys()
self.ranked_set.clear()
self.ranked_set.update(rankings[:size])
self.set_length.set(len(self.ranked_set))
self.set_bound = size
def addRating(self, ranking):
"""
attempts to add a rating to the set
if the set has not reached its bound
then the rating is always inserted.
otherwise the ratings ranking value
as determined by the ranking algorithm
function is compared to the lowest
ranked item in the set, and is inserted
if it has a higher value.
"""
path = ranking.getContentPath()
size = ranking.getNumberVotes()
value = ranking.getCumulative()
ranking = ranking_algorithm(size, value)
if self.ranked_set.has_key( (ranking, path) ):
return
if self.set_length() <= self.set_bound:
self.ranked_set.insert( (ranking, path) )
self.set_length.change(1)
else:
key = self.ranked_set.minKey()
if ranking > key[0]:
self.ranked_set.remove(key)
self.ranked_set.insert(
(ranking, path)
)
def removeRating(self, ranking, path):
self.ranked_set.remove( (ranking, path) )
self.set_length.change(-1)
def getRankedSet(self):
set = self.ranked_set.keys()
set.reverse()
return set
InitializeClass(BoundedRankSet)
=== Added File Products/Ratings/RankingAlgorithm.py ===
def ranking_algorithm(set_size, cumulative_value):
return cumulative_value
=== Added File Products/Ratings/RatingTool.py ===
"""
(C) Copyright 2002 Kapil Thangavelu <kvthan at wm.edu>
All Rights Reserved
this file is part of Ratings
Ratings 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.
Ratings 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 Gideon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from Globals import InitializeClass, DTMLFile
from AccessControl import ClassSecurityInfo
from OFS.SimpleItem import SimpleItem
from Products.CMFCore.utils import UniqueObject, getToolByName
from Products.CMFCore import CMFCorePermissions
from Acquisition import aq_base
from BTrees.OOBTree import OOSet
from BTrees.Length import Length
from BoundedRankSet import BoundedRankSet
from Ratings import Rating
from RankingAlgorithm import ranking_algorithm
class RatingNotAllowed(Exception): pass
class RatingTool (UniqueObject, SimpleItem):
"""
a rating tool to encapsulate object ratings.
we use a bounded set to store the highest ranked
objects instead of the catalog since we get
less churn that way per vote.
ratings are stored local to the object.
"""
id = 'portal_ratings'
meta_type= 'CMF Rating Tool'
security = ClassSecurityInfo()
plone_tool = 1
# after change call store.setSize
_default_set_length = 10
# don't change if you have existing ratings
_rating_name = 'rating'
__factory_meta_type__ = meta_type
icon = 'misc_/%s/%s' % ('Rating', 'tool.gif')
manage_options = ( {'label':'Overview', 'action':'manage_overview'}, )
security.declareProtected( CMFCorePermissions.ManagePortal,
'manage_overview' )
manage_overview = DTMLFile('ui/RatingToolManageOverView', globals())
def __init__(self):
self.store = BoundedRankSet(self._default_set_length)
security.declarePublic('getHighestRatedObjects')
def getHighestRatedObjects(self):
""" return the objects with the highest ratings"""
res = []
traverse = self.unrestrictedTraverse
#print self.store.ranked_set.keys()
for r,p in self.store.getRankedSet():
try: res.append( traverse(p) )
except: self.store.removeRating( (r,p) )
return res
security.declarePublic('getRatingForObject')
def getRatingFor(self, content):
""" return the rating for an object creating if nesc """
if hasattr(content.aq_base, self._rating_name):
return getattr(content, self._rating_name)
elif self.isRatingAllowedFor(content):
setattr(content, self._rating_name, Rating() )
return getattr(content, self._rating_name)
else:
raise RatingNotAllowed
security.declarePublic('isRatingAllowedForObject')
def isRatingAllowedFor(self, content):
""" for later integration """
return 1
def _changeRating(self, rating):
""" this is an internal 'callback' interface for
ratings to talk to the tool when their updated """
self.store.addRating(rating)
InitializeClass(RatingTool)
=== Added File Products/Ratings/Ratings.py ===
"""
(C) Copyright 2002 Kapil Thangavelu <kvthan at wm.edu>
All Rights Reserved
this file is part of Ratings
Ratings 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.
Ratings 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 Gideon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
# $Id: Ratings.py,v 1.1 2002/06/12 16:25:48 k_vertigo Exp $
"""
Ratings.py
"""
from AccessControl import ClassSecurityInfo, getSecurityManager
from BTrees.IIBTree import IIBTree
from BTrees.Length import Length
from Globals import InitializeClass, DTMLFile
from OFS.SimpleItem import SimpleItem
from Products.CMFCore.utils import UniqueObject, getToolByName
manage_addRatingsForm = None
def manage_addRatings(self,
id='Ratings',
REQUEST=None
):
self._setObject(id, Rating(id))
if REQUEST is not None:
REQUEST.RESPONSE.redirect('manage_main')
class Rating(SimpleItem):
id = 'Ratings'
security = ClassSecurityInfo()
security.declarePublic('__call__')# logical
__call__ = DTMLFile('ui/RatingView', globals())
index_html = None
security.declarePublic('thank_you')
thank_you = DTMLFile('ui/RatingThankYou', globals())
security.declarePublic('already_voted')
already_voted = DTMLFile('ui/RatingAlreadyVoted', globals())
_scale = 6 # means we allow votes from 1 to scale
def __init__(self, id='Ratings'):
self.id = 'Ratings'
self._data = IIBTree()
self._num_votes = Length(0)
self._vote_sum = Length(0)
security.declareProtected('Rate Content', 'add_rating')
def addRating(self, value=None, RESPONSE=None):
""" """
try:
value = int(value)
except:
if RESPONSE is not None:
return RESPONSE.redirect(self.getContentPath())
if value not in range(1, self._scale,1):
if RESPONSE is not None:
return RESPONSE.redirect(self.getContentPath())
uname = getSecurityManager().getUser().getId()
if uname == 'Anonymous User':
return RESPONSE.redirect(self.getContentPath())
if self._data.has_key(hash(uname)):
return self.already_voted(self)
self._data[hash(uname)]=int(value)
self._num_votes.change(1)
self._vote_sum.change(value)
getToolByName(self, 'portal_ratings')._changeRating(self)
if RESPONSE is not None:
RESPONSE.redirect(self.getContentPath())
security.declarePublic('getNumberVotes')
def getNumberVotes(self):
""" """
return self._num_votes()
security.declarePublic('getCumulativeScore')
def getCumulative(self):
""" """
return self._vote_sum()
security.declarePublic('getAverageRating')
def getAverage(self):
""" return rating as string formated float """
if self._num_votes():
return "%1.1f"%(self._vote_sum()/float(
self._num_votes()))
else: return 'N/A'
security.declarePublic('getVoteUrl')
def getVoteUrl(self):
return self.absolute_url()+'/addRating'
security.declarePrivate('getContentPath')
def getContentPath(self):
return '/'.join(self.aq_inner.aq_parent.getPhysicalPath())
security.setPermissionDefault('Rate Content', ('Authenticated',))
InitializeClass(Rating)
=== Added File Products/Ratings/__init__.py ===
"""
(C) Copyright 2002 Kapil Thangavelu <kvthan at wm.edu>
All Rights Reserved
This file is part of Ratings.
Ratings 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.
Ratings 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 Gideon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
# $Id: __init__.py,v 1.1 2002/06/12 16:25:48 k_vertigo Exp $
from Products.CMFCore import utils
import RatingTool
tools = ( RatingTool.RatingTool, )
def initialize(context):
utils.ToolInit(meta_type = 'CMF Rating Tool',
tools = tools,
product_name = 'Ratings',
icon = 'tool.gif',
).initialize( context )
More information about the zopeorg-checkins
mailing list