def app(app_id, user_hash=None): """ Return details about an application. """ try: db = ReviewsDatabase(os.environ) db.event_info(_get_client_address(), user_hash, app_id, "getting") reviews = db.review_get_for_app_id(app_id) except CursorError as e: return json_error(str(e)) # add key if user_hash specified items_new = [] for review in reviews: if review.reported > 0: continue item = review.__dict__ if user_hash: item['user_skey'] = _get_user_key(user_hash, review.app_id) items_new.append(item) dat = json.dumps(items_new, sort_keys=True, indent=4, separators=(',', ': ')) return Response(response=dat, status=200, \ mimetype="application/json")
def stats(): """ Return the statistics page as HTML. """ try: db = ReviewsDatabase(os.environ) stats = db.get_stats() except CursorError as e: return error_internal(str(e)) # stats results_stats = [] for item in sorted(stats): results_stats.append((item, stats[item])) # popularity view results_viewed = [] for review in db.get_analytics_fetch(): results_viewed.append((review[0], review[1])) # popularity reviews results_submitted = [] for review in db.get_stats_fetch('reviewed'): results_submitted.append((review[0], review[1])) return render_template('stats.html', results_stats=results_stats, results_viewed=results_viewed, results_submitted=results_submitted)
def delete_force(review_id): """ Delete a review """ try: db = ReviewsDatabase(os.environ) review = db.review_get_for_id(review_id) except CursorError as e: return error_internal(str(e)) if not review: return error_internal('no review with that ID') db.review_delete(review) return redirect(url_for('.show_all'))
def users_all(): """ Return all the users as HTML. """ try: db = ReviewsDatabase(os.environ) users1 = db.get_users_by_karma(best=True) users2 = db.get_users_by_karma(best=False) except CursorError as e: return error_internal(str(e)) return render_template('users.html', users1=users1, users2=users2)
def unremove(review_id): """ Unreport a perfectly valid review """ try: db = ReviewsDatabase(os.environ) review = db.review_get_for_id(review_id) except CursorError as e: return error_internal(str(e)) if not review: return error_internal('no review with that ID') review.date_deleted = 0 db.review_modify(review) return redirect(url_for('.review', review_id=review_id))
def review(review_id): """ Show a specific review as HTML. """ try: db = ReviewsDatabase(os.environ) review = db.review_get_for_id(review_id) except CursorError as e: return error_internal(str(e)) if not review: return error_internal('no review with that ID') return render_template('show.html', r=review)
def anonify(review_id): """ Removes the username from the review """ try: db = ReviewsDatabase(os.environ) review = db.review_get_for_id(review_id) except CursorError as e: return error_internal(str(e)) if not review: return error_internal('no review with that ID') review.user_display = None db.review_modify(review) return redirect(url_for('.review', review_id=review_id))
def stats(): """ Return the statistics page as HTML. """ try: db = ReviewsDatabase(os.environ) stats = db.get_stats() except CursorError as e: return error_internal(str(e)) results = [] for item in sorted(stats): results.append((item, stats[item])) return render_template('stats.html', results=results)
def users_all(): """ Return all the users as HTML. """ try: db = ReviewsDatabase(os.environ) users_awesome = db.get_users_by_karma(best=True) users_haters = db.get_users_by_karma(best=False) except CursorError as e: return error_internal(str(e)) return render_template('users.html', users_awesome=users_awesome, users_haters=users_haters)
def rating_for_id(app_id): """ Get the star ratings for a specific application. """ try: db = ReviewsDatabase(os.environ) ratings = db.reviews_get_rating_for_app_id(app_id) except CursorError as e: return json_error(str(e)) dat = json.dumps(ratings, sort_keys=True, indent=4, separators=(',', ': ')) return Response(response=dat, status=200, \ mimetype="application/json")
def show_lang(locale): """ Return all the reviews from a user on the server as HTML. """ reviews_filtered = [] try: db = ReviewsDatabase(os.environ) reviews = db.review_get_all() for review in reviews: if review.locale == locale: reviews_filtered.append(review) except CursorError as e: return error_internal(str(e)) return render_template('show-all.html', reviews=reviews_filtered)
def graph_month(): """ Show nice graph graphs. """ try: db = ReviewsDatabase(os.environ) except CursorError as e: return error_internal(str(e)) data_fetch = db.get_analytics_by_interval(30, 1) data_review = db.get_stats_by_interval(30, 1, 'reviewed') return render_template('graph-month.html', labels=_get_chart_labels_days()[::-1], data_requests=data_fetch[::-1], data_submitted=data_review[::-1])
def englishify(review_id): """ Marks a review as writen in English """ try: db = ReviewsDatabase(os.environ) review = db.review_get_for_id(review_id) except CursorError as e: return error_internal(str(e)) if not review: return error_internal('no review with that ID') parts = review.locale.split('_') if len(parts) == 1: review.locale = 'en' else: review.locale = 'en_' + parts[1] db.review_modify(review) return redirect(url_for('.review', review_id=review_id))
def popularity(): """ Return the popularity page as HTML. """ try: db = ReviewsDatabase(os.environ) except CursorError as e: return error_internal(str(e)) results1 = [] for review in db.get_analytics_fetch(): results1.append((review[0].replace('.desktop', ''), review[1])) results2 = [] for review in db.get_stats_fetch('reviewed'): results2.append((review[0].replace('.desktop', ''), review[1])) return render_template('popularity.html', results1=results1, results2=results2)
def show_all(page): """ Return all the reviews on the server as HTML. """ try: db = ReviewsDatabase(os.environ) reviews = db.review_get_all() except CursorError as e: return error_internal(str(e)) if not reviews and page != 1: abort(404) reviews_per_page = 20 pagination = Pagination(page, reviews_per_page, len(reviews)) # FIXME: do this database side... reviews = reviews[(page-1) * reviews_per_page:page * reviews_per_page] return render_template('show-all.html', pagination=pagination, reviews=reviews)
def login(): if request.method != 'POST': return render_template('login.html') username = request.form['username'] password = request.form['password'] try: db = ReviewsDatabase(os.environ) user = db.user_get_with_login(request.form['username'], request.form['password']) except CursorError as e: flash(str(e)) return render_template('error.html'), 503 if not user: flash('Credentials are not valid.') return redirect(url_for('.login')) login_user(user, remember=False) flash('Logged in successfully.') return redirect(url_for('.index'))
def show_all(page): """ Return all the reviews on the server as HTML. """ try: db = ReviewsDatabase(os.environ) reviews = db.review_get_all() except CursorError as e: return error_internal(str(e)) if not reviews and page != 1: abort(404) reviews_per_page = 20 pagination = Pagination(page, reviews_per_page, len(reviews)) # FIXME: do this database side... reviews = reviews[(page - 1) * reviews_per_page:page * reviews_per_page] return render_template('show-all.html', pagination=pagination, reviews=reviews)
def distros(): """ Return the statistics page as HTML. """ try: db = ReviewsDatabase(os.environ) stats = db.get_stats_distro(8) except CursorError as e: return error_internal(str(e)) labels = [] data = [] for s in stats: name = s[0] for suffix in [' Linux', ' GNU/Linux', ' OS', ' Linux']: if name.endswith(suffix): name = name[:-len(suffix)] labels.append(str(name)) data.append(s[1]) return render_template('distros.html', labels=labels, data=data)
def distros(): """ Return the statistics page as HTML. """ try: db = ReviewsDatabase(os.environ) stats = db.get_stats_distro(8) except CursorError as e: return error_internal(str(e)) labels = [] data = [] for s in stats: name = s[0] for suffix in [' Linux', ' GNU/Linux', ' OS', ' Linux']: if name.endswith(suffix): name = name[:-len(suffix)] labels.append(name) data.append(s[1]) return render_template('distros.html', labels=labels, data=data)
def ratings(): """ Get the star ratings for a specific application. """ item = {} try: db = ReviewsDatabase(os.environ) app_ids = db.get_all_apps() for app_id in app_ids: ratings = db.reviews_get_rating_for_app_id(app_id, 2) if len(ratings) == 0: continue item[app_id] = ratings except CursorError as e: return json_error(str(e)) dat = json.dumps(item, sort_keys=True, indent=4, separators=(',', ': ')) return Response(response=dat, status=200, \ mimetype="application/json")
def modify(review_id): """ Change details about a review """ try: db = ReviewsDatabase(os.environ) review = db.review_get_for_id(review_id) except CursorError as e: return error_internal(str(e)) if not review: return error_internal('no review with that ID') review.distro = request.form['distro'] review.locale = request.form['locale'] if len(request.form['user_display']) == 0: review.user_display = None else: review.user_display = request.form['user_display'] review.user_hash = request.form['user_hash'] review.description = request.form['description'] review.summary = request.form['summary'] review.version = request.form['version'] db.review_modify(review) return redirect(url_for('.review', review_id=review_id))
def moderate(user_hash, locale=None): """ Return all the reviews on the server the user can moderate. """ try: db = ReviewsDatabase(os.environ) db.event_info(_get_client_address(), user_hash, None, "getting moderatable reviews") reviews = db.review_get_all() except CursorError as e: return json_error(str(e)) # only return reviews the user has not already voted on items_new = [] for review in reviews: if locale and not _locale_is_compatible(review.locale, locale): continue if not db.vote_exists(review.review_id, user_hash): item = review.__dict__ item['user_skey'] = _get_user_key(user_hash, review.app_id) items_new.append(item) dat = json.dumps(items_new, sort_keys=True, indent=4, separators=(',', ': ')) return Response(response=dat, status=200, \ mimetype="application/json")
def all(user_hash=None): """ Return all the reviews on the server as a JSON object. """ try: db = ReviewsDatabase(os.environ) db.event_info(_get_client_address(), user_hash, None, "getting all reviews") reviews = db.review_get_all() except CursorError as e: return json_error(str(e)) # the user specified a user_hash if user_hash: for review in reviews: if review.reported > 0: continue item = review.__dict__ item['user_skey'] = _get_user_key(user_hash, review.app_id) dat = json.dumps(reviews, sort_keys=True, indent=4, separators=(',', ': ')) return Response(response=dat, status=200, \ mimetype="application/json")
def remove(): """ Remove a review. """ try: item = json.loads(request.data.decode('utf8')) except ValueError as e: return json_error(str(e)) for key in ['review_id', 'app_id', 'user_hash', 'user_skey']: if not key in item: return json_error('invalid data, required %s' % key) if item[key] is None: return json_error('missing data, expected %s' % key) # check format if not len(item['user_hash']) == 40: return json_error('the user_hash is invalid') if not len(item['user_skey']) == 40: return json_error('the user_skey is invalid') # connect to database early try: db = ReviewsDatabase(os.environ) except CursorError as e: return json_error(str(e)) if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']): db.event_warn(_get_client_address(), item['user_hash'], None, "invalid user_skey of %s" % item['user_skey']) return json_error('invalid user_skey') try: # the user already has a review db.review_remove(item['review_id'], item['user_hash']) db.event_info(_get_client_address(), item['user_hash'], item['app_id'], "removed review") except CursorError as e: return json_error(str(e)) return json_success('removed review #%i' % item['review_id'])
def load_user(user_id): db = ReviewsDatabase(os.environ) user = db.user_get_by_id(user_id) return user
def submit(): """ Submits a new review. """ try: item = json.loads(request.data.decode('utf8')) except ValueError as e: return json_error(str(e)) required_fields = [ 'app_id', 'locale', 'summary', 'description', 'user_hash', 'version', 'distro', 'rating', 'user_display' ] for key in required_fields: if not key in item: return json_error('invalid data, expected %s' % key) if item[key] is None: return json_error('missing data, expected %s' % key) # check format if not len(item['user_hash']) == 40: return json_error('the user_hash is invalid') # check fields for markup and length if not item['app_id'].endswith('.desktop'): return json_error('only applications can be reviewed at this time') if len(item['summary']) > 70: return json_error('summary is too long') if len(item['description']) > 3000: return json_error('description is too long') for key in ['summary', 'description']: if not _check_str(item[key]): return json_error('%s is not a valid string' % key) try: db = ReviewsDatabase(os.environ) # user has already reviewed if db.review_exists(item['app_id'], item['user_hash']): db.event_warn(_get_client_address(), item['user_hash'], item['app_id'], "already reviewed") return json_error('already reviewed this app') # check user has not been banned user = db.user_get_by_hash(item['user_hash']) if user and user.is_banned: return json_error('account has been disabled due to abuse') # create new review = OdrsReview() review.app_id = item['app_id'] review.locale = item['locale'] review.summary = item['summary'] review.description = item['description'] review.user_hash = item['user_hash'] review.version = item['version'] review.distro = item['distro'] review.rating = item['rating'] # check if valid user_display_ignore = ['root', 'Live System User', 'Unknown'] if item['user_display'] not in user_display_ignore: review.user_display = item['user_display'] # log and add db.event_info(_get_client_address(), review.user_hash, review.app_id, "reviewed") db.review_add(review, _get_client_address()) except CursorError as e: return json_error(str(e)) return json_success()
def fetch(): """ Return details about an application. """ try: item = json.loads(request.data.decode('utf8')) except ValueError as e: return json_error(str(e)) for key in ['app_id', 'user_hash', 'locale', 'distro', 'limit', 'version']: if not key in item: return json_error('invalid data, expected %s' % key) if item[key] is None: return json_error('missing data, expected %s' % key) # check format if not len(item['user_hash']) == 40: return json_error('the user_hash is invalid') try: db = ReviewsDatabase(os.environ) db.analytics_inc_fetch(item['app_id']) reviews = db.review_get_for_app_id(item['app_id']) except CursorError as e: return json_error(str(e)) # if user does not exist then create user = db.user_get_by_hash(item['user_hash']) if not user: db.user_add(item['user_hash']) # add score for review using secret sauce items_new = [] for review in reviews: if review.reported > 0: continue # the user isn't going to be able to read this if not _locale_is_compatible(review.locale, item['locale']): continue # return all results item_new = review.__dict__ item_new['user_skey'] = _get_user_key(item['user_hash'], review.app_id) item_new['score'] = _get_review_score(review, item) # the UI can hide the vote buttons on reviews already voted on if db.vote_exists(review.review_id, item['user_hash']): item_new['vote_id'] = 1 items_new.append(item_new) # fake something so the user can get the user_skey if len(items_new) == 0: item_new = {} item_new['score'] = 0 item_new['app_id'] = item['app_id'] item_new['user_hash'] = item['user_hash'] item_new['user_skey'] = _get_user_key(item['user_hash'], item['app_id']) items_new.append(item_new) # sort and cut to limit sorted(items_new, key=lambda item: item['score']) items_new = items_new[:item['limit']] dat = json.dumps(items_new, sort_keys=True, indent=4, separators=(',', ': ')) return Response(response=dat, status=200, \ mimetype="application/json")
def vote(val): """ Up or downvote an existing review by @val karma points. """ try: item = json.loads(request.data.decode('utf8')) except ValueError as e: return json_error(str(e)) for key in ['review_id', 'app_id', 'user_hash', 'user_skey']: if not key in item: return json_error('invalid data, required %s' % key) if item[key] is None: return json_error('missing data, expected %s' % key) # check format if not len(item['user_hash']) == 40: return json_error('the user_hash is invalid') if not len(item['user_skey']) == 40: return json_error('the user_skey is invalid') # connect to database early try: db = ReviewsDatabase(os.environ) except CursorError as e: return json_error(str(e)) if item['user_skey'] != _get_user_key(item['user_hash'], item['app_id']): db.event_warn(_get_client_address(), item['user_hash'], None, "invalid user_skey of %s" % item['user_skey']) #print("expected user_skey of %s" % _get_user_key(item['user_hash'], item['app_id'])) return json_error('invalid user_skey') try: # the user already has a review if db.vote_exists(item['review_id'], item['user_hash']): db.event_warn(_get_client_address(), item['user_hash'], item['app_id'], "duplicate vote") return json_error('already voted on this app') # update the per-user karma user = db.user_get_by_hash(item['user_hash']) if not user: db.user_add(item['user_hash']) else: # user is naughty if user.is_banned: return json_error('account has been disabled due to abuse') # the user is too harsh if val < 0 and user.karma < -50: return json_error('all negative karma used up') db.user_update_karma(item['user_hash'], val) # add the vote to the database db.vote_add(item['review_id'], val, item['user_hash']) db.event_info(_get_client_address(), item['user_hash'], item['app_id'], "voted %i on review" % val) except CursorError as e: return json_error(str(e)) return json_success('voted #%i %i' % (item['review_id'], val))