async def get_ranks(after='1y', sort='top', limit=None): if sort == 'hot': after = '1y' epoch = get_epoch(after) ranks = [] db = DB(DB_FILE) await db.connect() data = await db.get_ranks(epoch, sort, limit) num = 1 async for row in data: bot, link_karma, comment_karma, good_bots, bad_bots, top_score, hot_score, controversial_score = row rank = Bot() rank.name = bot rank.score = top_score votes = Votes() votes.good = good_bots votes.bad = bad_bots rank.votes = votes karma = Karma() karma.link = link_karma karma.comment = comment_karma rank.karma = karma ranks.append(rank) await db.close() for bot in sorted(ranks, key=lambda x: x.score, reverse=True): bot.rank = num num += 1 return ranks
def process_karma(message: Message, message_id: int, db_session: Session, timeout: int): reply = "" # Parse the message for karma modifications karma_items = parse_message_content(message.content) transactions = make_transactions(karma_items, message) transactions = apply_blacklist(transactions, db_session) # If no karma'd items, just return if not transactions: return reply # TODO: Protect from byte-limit length chars # Get karma-ing user user = db_session.query(User).filter( User.user_uid == message.author.id).first() # Get whether the channel is on mini karma or not channel = (db_session.query(MiniKarmaChannel).filter( MiniKarmaChannel.channel == message.channel.id).one_or_none()) if channel is None: karma_mode = MiniKarmaMode.Normal else: karma_mode = MiniKarmaMode.Mini def own_karma_error(topic): if karma_mode == MiniKarmaMode.Normal: return f' • Could not change "{topic}" because you cannot change your own karma! :angry:' else: return f'could not change "**{topic}**" (own name)' def internal_error(topic): if karma_mode == MiniKarmaMode.Normal: return f' • Could not create "{topic}" due to an internal error.' else: return f'could not change "**{topic}**" (internal error)' def cooldown_error(topic, td): # Tell the user that the item is on cooldown if td.seconds < 60: seconds_plural = f"second{'s' if td.seconds != 1 else ''}" duration = f"{td.seconds} {seconds_plural}" else: mins = td.seconds // 60 mins_plural = f"minute{'s' if mins != 1 else ''}" duration = f"{mins} {mins_plural}" if karma_mode == MiniKarmaMode.Normal: return f' • Could not change "{topic}" since it is still on cooldown (last altered {duration} ago).\n' else: return ( f'could not change "**{topic}**" (cooldown, last edit {duration} ago)' ) def success_item(tr: KarmaTransaction): # Give some sass if someone is trying to downvote the bot if (tr.karma_item.topic.casefold() == "apollo" and tr.karma_item.operation.value < 0): apollo_response = ":wink:" else: apollo_response = "" op = str(tr.karma_item.operation) # Build the karma item string if tr.karma_item.reason: if karma_mode == MiniKarmaMode.Normal: if tr.self_karma: return f" • **{truncated_name}** (new score is {karma_change.score}) and your reason has been recorded. *Fool!* that's less karma to you. :smiling_imp:" else: return f" • **{truncated_name}** (new score is {karma_change.score}) and your reason has been recorded. {apollo_response}" else: return f"**{truncated_name}**{op} (now {karma_change.score}, reason recorded)" else: if karma_mode == MiniKarmaMode.Normal: if tr.self_karma: return f" • **{truncated_name}** (new score is {karma_change.score}). *Fool!* that's less karma to you. :smiling_imp:" else: return f" • **{truncated_name}** (new score is {karma_change.score}). {apollo_response}" else: return f"**{truncated_name}**{op} (now {karma_change.score})" # Start preparing the reply string if len(transactions) > 1: transaction_plural = "s" else: transaction_plural = "" items = [] errors = [] # Iterate over the transactions to write them to the database for transaction in transactions: # Truncate the topic safely so we 2000 char karmas can be used truncated_name = ((transaction.karma_item.topic[300:] + ".. (truncated to 300 chars)") if len(transaction.karma_item.topic) > 300 else transaction.karma_item.topic) # Catch any self-karma transactions early if transaction.self_karma and transaction.karma_item.operation.value > -1: errors.append(own_karma_error(truncated_name)) continue # Get the karma item from the database if it exists karma_item = (db_session.query(Karma).filter( func.lower(Karma.name) == func.lower( transaction.karma_item.topic)).one_or_none()) # Update or create the karma item if not karma_item: karma_item = Karma(name=transaction.karma_item.topic) db_session.add(karma_item) try: db_session.commit() except (ScalarListException, SQLAlchemyError) as e: db_session.rollback() logging.error(e) errors.append(internal_error(truncated_name)) continue # Get the last change (or none if there was none) last_change = (db_session.query(KarmaChange).filter( KarmaChange.karma_id == karma_item.id).order_by( desc(KarmaChange.created_at)).first()) if not last_change: # If the bot is being downvoted then the karma can only go up if transaction.karma_item.topic.casefold() == "apollo": new_score = abs(transaction.karma_item.operation.value) else: new_score = transaction.karma_item.operation.value karma_change = KarmaChange( karma_id=karma_item.id, user_id=user.id, message_id=message_id, reason=transaction.karma_item.reason, change=new_score, score=new_score, created_at=datetime.utcnow(), ) db_session.add(karma_change) try: db_session.commit() except (ScalarListException, SQLAlchemyError) as e: db_session.rollback() logging.error(e) errors.append(internal_error(truncated_name)) continue else: time_delta = datetime.utcnow() - last_change if is_in_cooldown(last_change, timeout): errors.append(cooldown_error(truncated_name, time_delta)) continue # If the bot is being downvoted then the karma can only go up if transaction.karma_item.topic.casefold() == "apollo": new_score = last_change.score + abs( transaction.karma_item.operation.value) else: new_score = last_change.score + transaction.karma_item.operation.value karma_change = KarmaChange( karma_id=karma_item.id, user_id=user.id, message_id=message_id, reasons=transaction.karma_item.reason, score=new_score, change=(new_score - last_change.score), created_at=datetime.utcnow(), ) db_session.add(karma_change) try: db_session.commit() except (ScalarListException, SQLAlchemyError) as e: db_session.rollback() logging.error(e) errors.append(internal_error(truncated_name)) karma_change = KarmaChange( karma_id=karma_item.id, user_id=user.id, message_id=message_id, reason=transaction.karma_item.reason, score=new_score, change=(new_score - last_change.score), created_at=datetime.utcnow(), ) db_session.add(karma_change) try: db_session.commit() except (ScalarListException, SQLAlchemyError) as e: db_session.rollback() logging.error(e) errors.append(internal_error(truncated_name)) continue else: errors.append(cooldown_error(truncated_name, time_delta)) continue # Update karma counts if transaction.karma_item.operation.value == 0: karma_item.neutrals = karma_item.neutrals + 1 elif transaction.karma_item.operation.value == 1: karma_item.pluses = karma_item.pluses + 1 elif transaction.karma_item.operation.value == -1: # Make sure the changed operation is updated if transaction.karma_item.topic.casefold() == "apollo": karma_item.pluses = karma_item.pluses + 1 else: karma_item.minuses = karma_item.minuses + 1 items.append(success_item(transaction)) # Get the name, either from discord or irc author_display = get_name_string(message) # Construct the reply string in totality # If you have error(s) and no items processed successfully if karma_mode == MiniKarmaMode.Normal: item_str = "\n".join(items) error_str = "\n".join(errors) if not item_str and error_str: reply = f"Sorry {author_display}, I couldn't karma the requested item{transaction_plural} because of the following problem{transaction_plural}:\n\n{error_str}" # If you have items processed successfully but some errors too elif item_str and error_str: reply = f"Thanks {author_display}, I have made changes to the following item(s) karma:\n\n{item_str}\n\nThere were some issues with the following item(s), too:\n\n{error_str}" # If all items were processed successfully else: reply = f"Thanks {author_display}, I have made changes to the following karma item{transaction_plural}:\n\n{item_str}" else: item_str = " ".join(items) error_str = " ".join(errors) reply = " ".join(filter(None, ["Changes:", item_str, error_str])) # Commit any changes (in case of any DB inconsistencies) try: db_session.commit() except (ScalarListException, SQLAlchemyError) as e: logging.error(e) db_session.rollback() return reply.rstrip()
def process_karma(message: Message, message_id: int, db_session: Session, timeout: int): reply = "" # Parse the message for karma modifications raw_karma = parse_message(message.clean_content, db_session) # If no karma'd items, just return if not raw_karma: return reply # TODO: Protect from byte-limit length chars # If the author was IRC, set the display name to be the irc user that karma'd, else use original display name display_name = message.author.display_name if message.author.id == CONFIG["UWCS_DISCORD_BRIDGE_BOT_ID"]: # Gets the username of the irc user display_name = message.content.split(" ")[0][3:-3] # Process the raw karma tokens into a number of karma transactions transactions = create_transactions(message.author.name, display_name, raw_karma) if not transactions: return reply # Get karma-ing user user = db_session.query(User).filter( User.user_uid == message.author.id).first() # Start preparing the reply string if len(transactions) > 1: transaction_plural = "s" else: transaction_plural = "" item_str = "" error_str = "" # Iterate over the transactions to write them to the database for transaction in transactions: # Truncate the name safely so we 2000 char karmas can be used truncated_name = ((transaction.name[300:] + ".. (truncated to 300 chars)") if len(transaction.name) > 300 else transaction.name) # Catch any self-karma transactions early if transaction.self_karma and transaction.net_karma > -1: error_str += f' • Could not change "{truncated_name}" because you cannot change your own karma! :angry:\n' continue # Get the karma item from the database if it exists karma_item = (db_session.query(Karma).filter( func.lower(Karma.name) == func.lower( transaction.name)).one_or_none()) # Update or create the karma item if not karma_item: karma_item = Karma(name=transaction.name) db_session.add(karma_item) db_session.commit() # Get the last change (or none if there was none) last_change = (db_session.query(KarmaChange).filter( KarmaChange.karma_id == karma_item.id).order_by( desc(KarmaChange.created_at)).first()) if not last_change: # If the bot is being downvoted then the karma can only go up if transaction.name.lower() == "apollo": new_score = abs(transaction.net_karma) else: new_score = transaction.net_karma karma_change = KarmaChange( karma_id=karma_item.id, user_id=user.id, message_id=message_id, reasons=transaction.reasons, change=new_score, score=new_score, created_at=datetime.utcnow(), ) db_session.add(karma_change) db_session.commit() else: time_delta = datetime.utcnow() - last_change.created_at if time_delta.seconds >= timeout: # If the bot is being downvoted then the karma can only go up if transaction.name.lower() == "apollo": new_score = last_change.score + abs(transaction.net_karma) else: new_score = last_change.score + transaction.net_karma karma_change = KarmaChange( karma_id=karma_item.id, user_id=user.id, message_id=message_id, reasons=transaction.reasons, score=new_score, change=(new_score - last_change.score), created_at=datetime.utcnow(), ) db_session.add(karma_change) db_session.commit() else: # Tell the user that the item is on cooldown if time_delta.seconds < 60: error_str += f' • Could not change "{truncated_name}" since it is still on cooldown (last altered {time_delta.seconds} seconds ago).\n' else: mins_plural = "" mins = floor(time_delta.seconds / 60) if time_delta.seconds >= 120: mins_plural = "s" error_str += f' • Could not change "{truncated_name}" since it is still on cooldown (last altered {mins} minute{mins_plural} ago).\n' continue # Update karma counts if transaction.net_karma == 0: karma_item.neutrals = karma_item.neutrals + 1 elif transaction.net_karma == 1: karma_item.pluses = karma_item.pluses + 1 elif transaction.net_karma == -1: # Make sure the changed operation is updated if transaction.name.lower() == "apollo": karma_item.pluses = karma_item.pluses + 1 else: karma_item.minuses = karma_item.minuses + 1 # Give some sass if someone is trying to downvote the bot if (transaction.name.casefold() == "Apollo".casefold() and transaction.net_karma < 0): apollo_response = ":wink:" else: apollo_response = "" # Build the karma item string if transaction.reasons: if len(transaction.reasons) > 1: reasons_plural = "s" reasons_has = "have" else: reasons_plural = "" reasons_has = "has" if transaction.self_karma: item_str += f" • **{truncated_name}** (new score is {karma_change.score}) and your reason{reasons_plural} {reasons_has} been recorded. *Fool!* that's less karma to you. :smiling_imp:\n" else: item_str += f" • **{truncated_name}** (new score is {karma_change.score}) and your reason{reasons_plural} {reasons_has} been recorded. {apollo_response}\n" else: if transaction.self_karma: item_str += f" • **{truncated_name}** (new score is {karma_change.score}). *Fool!* that's less karma to you. :smiling_imp:\n" else: item_str += f" • **{truncated_name}** (new score is {karma_change.score}). {apollo_response}\n" # Get the name, either from discord or irc author_display = get_name_string(message) # Construct the reply string in totality # If you have error(s) and no items processed successfully if not item_str and error_str: reply = f"Sorry {author_display}, I couldn't karma the requested item{transaction_plural} because of the following problem{transaction_plural}:\n\n{error_str}" # If you have items processed successfully but some errors too elif item_str and error_str: reply = f"Thanks {author_display}, I have made changes to the following item(s) karma:\n\n{item_str}\n\nThere were some issues with the following item(s), too:\n\n{error_str}" # If all items were processed successfully else: reply = f"Thanks {author_display}, I have made changes to the following karma item{transaction_plural}:\n\n{item_str}" # Commit any changes (in case of any DB inconsistencies) db_session.commit() return reply.rstrip()
def process_karma(message, db_session, timeout): reply = '' # Parse the message for karma modifications raw_karma = parse_message(message.content) # If no karma'd items, just return if not raw_karma: return reply # Process the raw karma tokens into a number of karma transactions transactions = create_transactions(message.author.name.lower(), raw_karma) if not transactions: return reply # Get karma-ing user user = db_session.query(User).filter( User.user_uid == message.author.id).first() # reply = 'I have changed the karma of the following item{plural} as requested:\n' \ # '{karma_items}{error_str}' # Start preparing the reply string if len(transactions) > 1: transaction_plural = 's' else: transaction_plural = '' item_str = '' error_str = '' # Iterate over the transactions to write them to the database for transaction in transactions: # Catch any self-karma transactions early if transaction.self_karma: error_str += f' - Could not change **{transaction.name}** because you cannot change your own karma, you *fool!*\n' continue # Get the karma item from the database if it exists karma_item = db_session.query(Karma).filter( func.lower(Karma.name) == func.lower( transaction.name)).one_or_none() # Update or create the karma item if not karma_item: karma_item = Karma(name=func.lower(transaction.name), score=0) db_session.add(karma_item) else: # If the item exists then we need to check its modifiable delta = datetime.now() - karma_item.altered if delta.seconds < timeout: mins_since_modified = ceil(delta.seconds / 60) if mins_since_modified == 1: mins_plural = '' else: mins_plural = 's' error_str += f'Could not change **{karma_item.name}** since it is still on cooldown (last altered {mins_since_modified} minute{mins_plural} ago).\n' continue karma_item.score = karma_item.score + transaction.net_karma karma_item.altered = datetime.now() if transaction.net_karma == 0: karma_item.neutrals = karma_item.neutrals + 1 elif transaction.net_karma == 1: karma_item.pluses = karma_item.pluses + 1 elif transaction.net_karma == -1: karma_item.minuses = karma_item.minuses + 1 # Build the karma item string if transaction.reasons: if len(transaction.reasons) > 1: reasons_plural = 's' reasons_has = 'have' else: reasons_plural = '' reasons_has = 'has' item_str += f' - **{transaction.name}** (new score is {karma_item.score}) and your reason{reasons_plural} {reasons_has} been recorded.\n' else: item_str += f' - **{transaction.name}** (new score is {karma_item.score}).\n' # Add any reasons if there are any for reason in transaction.reasons: reason_item = KarmaReason(karma_id=karma_item.id, user_id=user.id, reason=reason, change=transaction.net_karma, score=karma_item.score) db_session.add(reason_item) # Commit the changes to the database db_session.commit() # Construct the reply string in totality # If you have error(s) and no items processed successfully if not item_str and error_str: reply = f'I couldn\'t karma the requested item{transaction_plural} because of the following problem{transaction_plural}:\n{error_str}' # If you have items processed successfully but some errors too elif item_str and error_str: reply = f'I have made changes to the following item(s) karma:\n{item_str}\nThere were some issues with the following item(s), too:\n{error_str}' # If all items were processed successfully else: reply = f'I have made changes the following karma item{transaction_plural}:\n{item_str}' return reply.rstrip()
def karma_change(db_session, client, uid, changes): # get user from db user = db_session.query(User).filter(User.uid == uid).first() changed = [] not_changed = [] for tup in changes: karma_name_raw = tup[0] karma_name = tup[0].lower() if karma_name == 'me': d_user = client.get_user(uid) karma_name_raw = d_user.name karma_name = d_user.name.lower() # ezzy fix elif karma_name == 'ezzy': karma_name = 'esther' change = tup[1] reason = tup[2] # first, check if the karma_name already exists in karma database karma_item = db_session.query(Karma).filter( Karma.name == karma_name).one_or_none() if karma_item == None: # add it to the karma table karma_item = Karma(name=karma_name) db_session.add(karma_item) db_session.commit() # check when last altered last_change = db_session.query(KarmaChange).filter( KarmaChange.karma_id == karma_item.id).order_by( desc(KarmaChange.changed_at)).first() if last_change: time_delta = datetime.utcnow() - last_change.changed_at if time_delta >= timedelta( seconds=CREDS['KARMA_TIMEOUT_S']) or karma_name == 'sara': # enough time has passed or its f****n sara-- karma_change = KarmaChange(karma_id=karma_item.id, user_id=user.id, reason=reason, change=change, score=last_change.score + change, changed_at=datetime.utcnow()) db_session.add(karma_change) db_session.commit() changed.append( (karma_name_raw, last_change.score, karma_change.score)) else: not_changed.append(karma_name_raw) else: karma_change = KarmaChange(karma_id=karma_item.id, user_id=user.id, reason=reason, change=change, score=change, changed_at=datetime.utcnow()) db_session.add(karma_change) db_session.commit() changed.append((karma_name_raw, 'None', karma_change.score)) if change == -1: karma_item.pluses = karma_item.pluses + 1 elif change == 0: karma_item.neutrals = karma_item.neutrals + 1 else: karma_item.minuses = karma_item.minuses + 1 db_session.commit() if len(changed) > 1: ch_item_plural = 's' else: ch_item_plural = '' if len(not_changed) > 1: n_item_plural = 's' else: n_item_plural = '' reply = "" if len(changed) > 0: reply += f"I have made changes to the following item{ch_item_plural}:\n" for c, o, s in changed: reply += f" • **{c}** ({o} -> {s})\n" if len(not_changed) > 0: reply += f"Unfortunately, I couldn't make changes to the following item{n_item_plural} because of the cooldown period:\n" for c in not_changed: reply += f" • **{c}**\n" return reply.rstrip()