Пример #1
0
def getFriendStandings(chat: Chat, contestId, sendIfEmpty=True):
    friends = cf.getListFriends(chat)
    if len(friends) == 0:
        if sendIfEmpty:
            chat.sendMessage((
                "You have no friends :(\n"
                "Please add your API key in the settings or add friends with `/add_friend`."
            ))
            logger.debug("user has no friends -> empty standings")
        return False
    standings = cf.getStandings(contestId, friends)
    if standings == False:
        logger.debug("failed to get standings for " + str(friends))
        return False

    msg = getContestHeader(standings["contest"])
    problemNames = [p["index"] for p in standings["problems"]]
    ratingChanges = getRatingChanges(contestId)
    ranking = Ranking.Ranking(standings["rows"], ratingChanges,
                              len(problemNames))
    tableRows = ranking.getRows(standings["contest"]['phase'] == 'SYSTEM_TEST')

    if not sendIfEmpty and len(tableRows) == 0:
        return False
    table = Table(problemNames, tableRows)
    msg += table.formatTable(chat.width)
    return msg
    def _sendAllSummary(self, contest):
        # cache rating for all users
        chats = [Chat.getChat(c) for c in db.getAllChatPartners()]

        # The getUserInfo command returns False if there is a unknown user in the list
        # the user is then removed by the CF error handling routine. A retry is neccessary though.
        retries = 20
        while retries > 0:
            handles = [c.handle for c in chats if c.handle]
            infos = cf.getUserInfos(handles)
            if infos:
                for info in infos:
                    self.userRatings[info['handle']] = info.get('rating', -1)
                break
            retries -= 1
            time.sleep(5)
        logger.debug(
            f"sending summary for contest {contest['id']}. Cached {len(self.userRatings)} ratings in {20-retries+1} try."
        )

        for chat in chats:
            msg = self._getContestAnalysis(contest, chat)
            if len(msg) > 0:  # only send if analysis is not empty
                msg = contest['name'] + " has finished:\n" + msg
                chat.sendMessage(msg)
            standings.sendContestStandings(chat,
                                           contest['id'],
                                           sendIfEmpty=False)
Пример #3
0
def getRatingChanges(contestId):
    with cfPredictorLock:
        if time.time() > cfPredictorLastRequest[contestId] + 20:
            logger.debug('request rating changes from cf-predictor')
            cfPredictorLastRequest[contestId] = time.time()
            try:
                startT = time.time()
                r = requests.get(cfPredictorUrl + str(contestId), timeout=10)
                perfLogger.info(
                    "cf predictor request {:.3f}s".format(time.time() -
                                                          startT))
            except requests.exceptions.Timeout as errt:
                logger.error("Timeout on CF-predictor.")
                return handleToRatingChanges[contestId]
            except Exception as e:
                logger.critical(
                    'Failed to request cf-predictor: \nexception: %s\n',
                    e,
                    exc_info=True)
                return handleToRatingChanges[contestId]
            if r.status_code != requests.codes.ok:
                logger.error("CF-Predictor request failed with code " +
                             str(r.status_code) + ", " + str(r.reason))
                return handleToRatingChanges[contestId]
            logger.debug('rating changes received')
            r = r.json()
            if r['status'] != 'OK':
                return handleToRatingChanges[contestId]
            r = r['result']
            handleToRatingChanges[contestId] = {}
            for row in r:
                handleToRatingChanges[contestId][row['handle']] = (
                    row['oldRating'], row['newRating'])
            cfPredictorLastRequest[contestId] = time.time()
        return handleToRatingChanges[contestId]
Пример #4
0
def handleCFError(request, r, chat):
    if r['status'] == 'FAILED':
        #delete nonexisting friends
        startS = "handles: User with handle "
        endS = " not found"
        if r['comment'].startswith(startS) and r['comment'].endswith(endS):
            handle = r['comment'][len(startS):-len(endS)]
            db.deleteFriend(handle)
            return
        #remove wrong authentification
        if 'Incorrect API key' in r['comment'] or 'Incorrect signature' in r[
                'comment']:
            chat.apikey = None
            chat.secret = None
            chat.sendMessage(
                "Your API-key did not work 😢. Please add a valid key and secret in the settings."
            )
            return
        if "contestId: Contest with id" in r[
                'comment'] and "has not started" in r['comment']:
            return  # TODO fetch new contest start time
        if "contestId: Contest with id" in r['comment'] and "not found" in r[
                'comment']:
            logger.debug("codeforces error: " + r['comment'])
            return
    logger.critical("codeforces error: " + str(r['comment']) + "\n" +
                    "this request caused the error:\n" + (str(request)[:200]),
                    exc_info=True)
Пример #5
0
 def _analyseRow(self, contestId, row, ranking, firstRead):
     handle = row["party"]["members"][0]["handle"]
     pointsList = self._points[contestId][handle]
     for taski in range(len(row["problemResults"])):
         task = row["problemResults"][taski]
         taskName = ranking["problems"][taski]["index"]
         if task["points"] > 0 and taski not in pointsList:
             if not firstRead:
                 self._notifyTaskSolved(handle, taskName,
                                        task["rejectedAttemptCount"],
                                        task["bestSubmissionTimeSeconds"],
                                        row["rank"] != 0)
                 if ranking["contest"][
                         'phase'] == 'FINISHED':  # if contest is running, standings are updated automatically
                     self._updateStandings(contestId,
                                           db.getWhoseFriendsListed(handle))
             pointsList.append(taski)
             if task['type'] == 'PRELIMINARY' and (
                     taski not in self._notFinal[contestId][handle]):
                 logger.debug('adding non-final task ' + str(taski) +
                              ' for user ' + str(handle))
                 self._notFinal[contestId][handle].append(taski)
         if task['type'] == 'FINAL' and (
                 taski in self._notFinal[contestId][handle]):
             logger.debug('finalizing non-final task ' + str(taski) +
                          ' for user ' + str(handle))
             self._notFinal[contestId][handle].remove(taski)
             self._notifyTaskTested(handle, taskName, task['points'] > 0)
             self._updateStandings(contestId,
                                   db.getWhoseFriendsListed(handle))
             if int(task['points']
                    ) == 0:  #failed on system tests, now not solved
                 pointsList.remove(taski)
Пример #6
0
 def _doTask(self):
     logger.debug('loading current contests')
     allContests = sendRequest('contest.list', {'gym': 'false'})
     if allContests is False:
         logger.error('failed to load current contest - maybe cf is not up')
     else:
         with contestListLock:
             selectImportantContests(allContests)
     logger.debug('loding contests finished')
Пример #7
0
def deleteFriend(handle):
    logger.debug("deleting friends with handle " + handle)
    query = "DELETE FROM friends WHERE friend = %s"
    insertDB(query, (handle, ))

    query = "SELECT chatId FROM tokens WHERE handle = %s"
    chatIds = [r[0] for r in queryDB(query, (handle, ))]
    logger.debug(f"deleting chat handle {handle} for chats {chatIds}")
    for chatId in chatIds:
        Chat.getChat(chatId).handle = None  # write through to DB
Пример #8
0
def handleAddSecret(chat, secret):
    if not secret.isalnum():
        chat.sendMessage(
            "Your API-secret is incorrect, it may only contain alphanumerical letters. Please try again:"
        )
        return
    chat.secret = secret
    bot.setOpenCommandFunc(chat.chatId, None)
    logger.debug('new secret added for user ' + str(chat.chatId))
    chat.sendMessage("Key added. Now fetching your codeforces friends...")
    cf.updateFriends(chat)
    bot.sendSetupFinished(chat)
Пример #9
0
 def _doTask(self, firstRead=False):
     logger.debug('started analysing standings')
     friends = db.getAllFriends()
     threads = []
     for contestId in cf.getCurrentContestsId():
         t = util.createThread(target=self._analyseContest,
                               args=(contestId, friends, firstRead),
                               name="analyseContest" + str(contestId))
         t.start()
         threads.append(t)
     for t in threads:
         t.join()
     logger.debug('finished analysing standings')
Пример #10
0
def getUserInfos(userNameArr):
    batchSize = 200
    split = [
        userNameArr[batchSize * i:batchSize * (i + 1)]
        for i in range((len(userNameArr) + batchSize - 1) // batchSize)
    ]
    res = []
    for part in split:
        usrList = ';'.join(part)
        logger.debug('requesting info of ' + str(len(part)) + ' users ')
        r = sendRequest('user.info', {'handles': usrList})
        if r is False:
            return False
        res.extend(r)
    return res
Пример #11
0
def updateStandingsForChat(contest, chat: Chat):
    with standingsSentLock:
        if contest not in standingsSent[
                chat.chatId]:  # only used as speed-up, checked again later
            return
    msg = getFriendStandings(chat, contest)
    if msg is False:
        return
    logger.debug('update standings for ' + str(chat.chatId) + '!')
    with standingsSentLock:
        if contest not in standingsSent[chat.chatId]:
            return
        msgId, oldMsg = standingsSent[chat.chatId][contest]
        if tg.shortenMessage(oldMsg) != tg.shortenMessage(msg):
            updateStandingsSent(chat.chatId, contest, msgId, msg)
            chat.editMessageTextLater(
                msgId, contest,
                lambda chat, contest: getFriendStandings(chat, contest))
Пример #12
0
def updateStandings(contestId):
    global aktuelleContests
    logger.debug('updating standings for contest ' + str(contestId) +
                 ' for all users')
    stNew = sendRequest('contest.standings', {
        'contestId': contestId,
        'showUnofficial': True
    })
    if stNew and "contest" in stNew:
        with standingsLock[contestId]:
            globalStandings[contestId] = {
                "time": time.time(),
                "standings": stNew
            }
        with contestListLock:
            aktuelleContests = [
                stNew["contest"] if stNew["contest"]["id"] == c["id"] else c
                for c in aktuelleContests
            ]
        logger.debug('standings received')
    else:
        logger.error('standings not updated')
Пример #13
0
def updateFriends(chat):
    p = {'onlyOnline': 'false'}
    logger.debug('request friends of chat with chat_id ' + str(chat.chatId))
    f = sendRequest("user.friends", p, True, chat)
    logger.debug('requesting friends finished')
    if f != False:
        db.addFriends(chat.chatId, f, chat.notifyLevel)
        logger.debug('friends updated for chat ' + str(chat.chatId))
Пример #14
0
def deleteUser(chatId):
    logger.debug("deleting all data of user with chatId " + str(chatId))
    query = "DELETE FROM friends WHERE chatId = %s"
    logger.debug("deleting all friend entries: " + query)
    insertDB(query, (chatId, ))
    query = "DELETE FROM tokens WHERE chatId = %s"
    logger.debug("deleting all token entries: " + query)
    insertDB(query, (chatId, ))
Пример #15
0
 def _doTask(self):
     logger.debug('starting to update all friends')
     for chatId in db.getAllChatPartners():
         updateFriends(Chat.getChat(chatId))
     logger.debug('updating all friends finished')
Пример #16
0
def deleteFriendOfUser(handle, chatId):
    logger.debug("deleting friend with handle " + handle + " from user " +
                 str(chatId))
    query = "DELETE FROM friends WHERE friend = %s AND chatId = %s"
    insertDB(query, (handle, chatId))