[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