ForgeFeedback/forgefeedback/feedback_main.py (183 lines of code) (raw):

# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import logging import pymongo # Non-stdlib imports from tg import expose, flash, redirect from tg.decorators import with_trailing_slash, without_trailing_slash from tg import tmpl_context as c, app_globals as g from ming.odm import session from ming.odm import session # profanityfilter package from profanityfilter import ProfanityFilter # Pyforge-specific imports from allura import model as M from allura import version from allura.app import ( Application, ) from allura.controllers import BaseController from allura.controllers.feed import FeedController from allura.lib.decorators import require_post from allura.lib.security import (require_access) # Local imports from forgefeedback import model as TM from forgefeedback import version from forgefeedback.model import Feedback log = logging.getLogger(__name__) class ForgeFeedbackApp(Application): __version__ = version.__version__ permissions = [ 'read', 'update', 'create', 'post', 'admin', 'delete' ] permissions_desc = { 'read': 'View ratings.', 'update': 'Edit ratings.', 'create': 'Create ratings.', 'admin': 'Set permissions. Configure option.', 'delete': 'Delete and undelete ratings. View deleted ratings.' } config_options = Application.config_options + [ ] tool_label = 'Feedback' tool_description = """ Feedbacks are given for the tools in the form of reviews and ratings, edit and delete the feedback""" default_mount_label = 'Feedback' default_mount_point = 'feedback' ordinal = 8 max_instances = 1 def __init__(self, project, config): Application.__init__(self, project, config) self.root = RootController() def install(self, project): 'Set up any default permissions and roles here' super().install(project) # Setup permissions role_admin = M.ProjectRole.by_name('Admin')._id role_developer = M.ProjectRole.by_name('Developer')._id role_auth = M.ProjectRole.by_name('*authenticated')._id role_anon = M.ProjectRole.by_name('*anonymous')._id self.config.acl = [ M.ACE.allow(role_anon, 'read'), M.ACE.allow(role_auth, 'post'), M.ACE.allow(role_auth, 'unmoderated_post'), M.ACE.allow(role_auth, 'create'), M.ACE.allow(role_developer, 'update'), M.ACE.allow(role_developer, 'moderate'), M.ACE.allow(role_developer, 'delete'), M.ACE.allow(role_admin, 'configure'), M.ACE.allow(role_admin, 'admin'), ] def uninstall(self, project): """Remove all the tool's artifacts from the database""" app_config_id = {'app_config_id': c.app.config._id} TM.Feedback.query.remove(app_config_id) super().uninstall(project) class RootController(BaseController, FeedController): def _check_security(self): require_access(c.app, 'read') @expose('jinja:forgefeedback:templates/feedback/index.html') def index(self, **kw): require_access(c.app, 'read') user_has_already_reviewed = False rating_by_user = Feedback.query.find({ 'reported_by_id': c.user._id, 'project_id': c.project._id} ).count() if rating_by_user > 0: user_has_already_reviewed = True return dict(review_list=self.get_review_list(), user_has_already_reviewed=user_has_already_reviewed, rating=c.project.rating) """ the list of all the feedbacks given by various users is listed on the index page """ @expose('jinja:forgefeedback:templates/feedback/index.html') def get_review_list(self, **kw): self.review_list = Feedback.query.find({'project_id': c.project._id})\ .sort('created_date', pymongo.DESCENDING).all() return self.review_list """ The new feedback given by the logged in user which includes the review, rating, project id and the user id are all flushed into the database """ @require_post() @expose('jinja:forgefeedback:templates/feedback/index.html') def create_feedback(self, description=None, rating=None, **kw): """saving the review for the first time """ require_access(c.app, 'create') p = Feedback(description=description, rating=rating, user_id=c.user._id, project_id=c.project._id) session(p).flush() flash('Feedback successfully added') M.main_orm_session.flush() g.director.create_activity(c.user, 'posted', p, related_nodes=[ c.project], tags=['description']) self.getRating() # force recalculation redirect(c.app.url) # called on click of the Feedback link @with_trailing_slash @expose('jinja:forgefeedback:templates/feedback/new_feedback.html') def new_feedback(self, **kw): require_access(c.app, 'create') return dict(action=c.app.config.url() + 'create') # called on click of edit review link and displays the previous feedback @expose('jinja:forgefeedback:templates/feedback/edit_feedback.html') def edit_feedback(self, **kw): self.review = Feedback.query.find( {'reported_by_id': c.user._id, 'project_id': c.project._id} ).first() return dict(description=self.review.description, rating=self.review.rating) # The edited feedback will be updated in the index page @require_post() @expose('jinja:forgefeedback:templates/feedback/index.html') def edit_user_review(self, description=None, rating=None, **kw): Feedback.query.update( {'reported_by_id': c.user._id, 'project_id': c.project._id}, {'$set': {'description': description, 'rating': rating}}) self.rating = Feedback.query.find( {'reported_by_id': c.user._id, 'project_id': c.project._id})\ .first() flash('Feedback successfully edited') g.director.create_activity( c.user, 'modified', self.rating, related_nodes=[c.project], tags=['description']) self.getRating() # force recalculation redirect(c.app.url) # called when user clicks on delete link in feedback page @without_trailing_slash @require_post() @expose('jinja:forgefeedback:templates/feedback/index.html') def delete_feedback(self, **kw): user_review = Feedback.query.find( {'reported_by_id': c.user._id, 'project_id': c.project._id} ).first() if user_review: Feedback.query.remove(dict( {'reported_by_id': c.user._id, 'project_id': c.project._id})) M.main_orm_session.flush() self.getRating() # force recalculation flash('Feedback successfully deleted') return 'Success' else: flash('Feedback was not deleted') return 'Failed' # This method is used to check for profanity in feedback text @expose() def feedback_check(self, description=None): pf = ProfanityFilter() if description: result = str(pf.is_profane(description)).lower() else: result = 'None' return result """ This method count the number of stars finds their sum and calculates the average of all the star rating count """ def getRating(self, **kw): onestarcount = TM.Feedback.query.find( {'rating': '1', 'project_id': c.project._id}).count() twostarcount = TM.Feedback.query.find( {'rating': '2', 'project_id': c.project._id}).count() threestarcount = TM.Feedback.query.find( {'rating': '3', 'project_id': c.project._id}).count() fourstarcount = TM.Feedback.query.find( {'rating': '4', 'project_id': c.project._id}).count() fivestarcount = TM.Feedback.query.find( {'rating': '5', 'project_id': c.project._id}).count() sum_of_ratings = float( fivestarcount + fourstarcount + threestarcount + twostarcount + onestarcount) if sum_of_ratings != 0: average_user_ratings = float( (5*fivestarcount) + (4*fourstarcount) + (3*threestarcount) + (2*twostarcount) + (1*onestarcount)) / sum_of_ratings float_rating = float(average_user_ratings) int_rating = int(float_rating) float_point_value = float_rating - int_rating if float_point_value < 0.25: c.project.rating = int_rating elif float_point_value >= 0.25 < 0.75: c.project.rating = 0.5 + int_rating elif float_point_value >= 0.75: c.project.rating = float(int_rating)+1 return average_user_ratings if sum_of_ratings == 0: c.project.rating = 0.0