Example #1
0
    def mp_timer():
        matchID = get_match_id_from_channel(chan)
        userID = userUtils.getID(fro)
        if not can_user_touch_lobby(matchID, userID):
            return False

        if len(message) < 2 or not message[1].isdigit() or int(message[1]) < 1:
            return "Wrong argument"
        secondsWatch = int(message[1])

        match = glob.matches.matches[matchID]
        if match.timerRunned:
            chat.sendMessage(
                glob.BOT_NAME, chan,
                "You can't run another timer, if you had another runned timer.\nEnter !mp aborttimer to stop."
            )
            return False

        def _decreaseTimer(t):
            if match.timerForce:
                chat.sendMessage(glob.BOT_NAME, chan, "Time is up!")
                match.timerForce = False
                match.timerRunned = False
            elif t <= 0:
                chat.sendMessage(glob.BOT_NAME, chan, "Time is up!")
                match.timerRunned = False
            else:
                if t % 10 == 0 or t <= 5:
                    chat.sendMessage(glob.BOT_NAME, chan,
                                     "Timer ends in {} seconds.".format(t))
                threading.Timer(1.00, _decreaseTimer, [t - 1]).start()

        match.timerRunned = True
        threading.Timer(1.00, _decreaseTimer, [secondsWatch - 1]).start()
        return "Timer started!"
Example #2
0
def report(fro, chan, message):
    msg = ""
    try:
        # TODO: Rate limit
        # Get username, report reason and report info
        target, reason, additionalInfo = message[0], message[1], message[2]
        target = chat.fixUsernameForBancho(target)

        # Make sure the target is not foka
        if target == glob.BOT_NAME:
            raise exceptions.invalidUserException()

        # Make sure the user exists
        targetID = userUtils.getID(target)
        if targetID == 0:
            raise exceptions.userNotFoundException()

        # Make sure that the user has specified additional info if report reason is 'Other'
        if reason.lower() == "other" and not additionalInfo:
            raise exceptions.missingReportInfoException()

        # Get the token if possible
        chatlog = ""
        token = glob.tokens.getTokenFromUsername(userUtils.safeUsername(target), safe=True)
        if token is not None:
            chatlog = token.getMessagesBufferString()

        # Everything is fine, submit report
        glob.db.execute(
            "INSERT INTO reports (id, from_uid, to_uid, reason, chatlog, time, assigned) VALUES (NULL, %s, %s, %s, %s, %s, 0)",
            [userUtils.getID(fro), targetID, "{reason} - ingame {info}".format(reason=reason, info="({})".format(
                additionalInfo) if additionalInfo is not None else ""), chatlog, int(time.time())])
        msg = "You've reported {target} for {reason}{info}. A Community Manager will check your report as soon as possible. Every !report message you may see in chat wasn't sent to anyone, so nobody in chat, but admins, know about your report. Thank you for reporting!".format(
            target=target, reason=reason, info="" if additionalInfo is None else " (" + additionalInfo + ")")
        adminMsg = "{user} has reported {target} for {reason} ({info})".format(user=fro, target=target, reason=reason,
                                                                               info=additionalInfo)

        # Log report in #admin and on discord
        chat.sendMessage(glob.BOT_NAME, "#admin", adminMsg)
        log.warning(adminMsg, discord="cm")
    except exceptions.invalidUserException:
        msg = "Hello, {} here! You can't report me. I won't forget what you've tried to do. Watch out.".format(
            glob.BOT_NAME)
    except exceptions.invalidArgumentsException:
        msg = "Invalid report command syntax. To report an user, click on it and select 'Report user'."
    except exceptions.userNotFoundException:
        msg = "The user you've tried to report doesn't exist."
    except exceptions.missingReportInfoException:
        msg = "Please specify the reason of your report."
    except:
        raise
    finally:
        if msg != "":
            token = glob.tokens.getTokenFromUsername(fro)
            if token is not None:
                if token.irc:
                    chat.sendMessage(glob.BOT_NAME, fro, msg)
                else:
                    token.enqueue(serverPackets.notification(msg))
    return False
Example #3
0
    def invite(self, sender, target, force=True):
        """
		Fro invites to in this match.

		:param sender: sender userID
		:param target: receiver userID
		:return:
		"""
        # Get tokens
        sendToken = glob.tokens.getTokenFromUserID(sender)
        recvToken = glob.tokens.getTokenFromUserID(target)
        if sendToken is None or recvToken is None:
            return

        # BOT IS BUSY!!!
        if target == 1:
            chat.sendMessage(
                glob.BOT_NAME, sendToken.username,
                "I would love to join your match, but I can't let my guard down from watching this place. Sorry!"
            )

        # Send message
        recvToken.enqueue(
            serverPackets.matchInvite(sendToken.username,
                                      recvToken.username,
                                      self.matchID,
                                      force=force))
Example #4
0
		def _decreaseTimer(t):
			if t <= 0:
				_start()
			else:
				if t % 10 == 0 or t <= 5:
					chat.sendMessage("FokaBot", chan, "Match starts in {} seconds.".format(t))
				threading.Timer(1.00, _decreaseTimer, [t - 1]).start()
    def asyncGet(self):
        statusCode = 400
        data = {"message": "unknown error"}
        try:
            # Check arguments
            if not requestsManager.checkArguments(self.request.arguments,
                                                  ["k", "to", "msg"]):
                raise exceptions.invalidArgumentsException()

            # Check ci key
            key = self.get_argument("k")
            if key is None or key != glob.conf.config["server"]["cikey"]:
                raise exceptions.invalidArgumentsException()

            chatHelper.sendMessage(
                glob.BOT_NAME,
                self.get_argument("to").encode().decode("ASCII", "ignore"),
                self.get_argument("msg").encode().decode('utf-8'))

            # Status code and message
            statusCode = 200
            data["message"] = "ok"
        except exceptions.invalidArgumentsException:
            statusCode = 400
            data["message"] = "invalid parameters"
        finally:
            # Add status code to data
            data["status"] = statusCode

            # Send response
            self.write(json.dumps(data))
            self.set_status(statusCode)
Example #6
0
    def invite(self, fro, to):
        """
		Fro invites to in this match.

		:param fro: sender userID
		:param to: receiver userID
		:return:
		"""
        # Get tokens
        froToken = glob.tokens.getTokenFromUserID(fro)
        toToken = glob.tokens.getTokenFromUserID(to)
        if froToken is None or toToken is None:
            return

        # FokaBot is too busy
        if to == 999:
            chat.sendMessage(
                glob.BOT_NAME, froToken.username,
                "I would love to join your match, but I'm busy keeping Mansion up and running. Sorry. Beep Boop."
            )

        # Send message
        message = "Come join my multiplayer match: \"[osump://{}/{} {}]\"".format(
            self.matchID, self.matchPassword.replace(" ", "_"), self.matchName)
        chat.sendMessage(token=froToken, to=toToken.username, message=message)
Example #7
0
	def sendReadyStatus(self):
		chanName = "#multi_{}".format(self.matchID)

		# Make sure match exists before attempting to do anything else
		if chanName not in glob.channels.channels:
			return

		totalUsers = 0
		readyUsers = 0

		for slot in self.slots:
			# Make sure there is a user in this slot
			if slot.user is None:
				continue

			# In this slot there is a user, so we increase the amount of total users
			# in this multi room.
			totalUsers += 1

			if slot.status == slotStatuses.READY:
				readyUsers += 1

		message = "{} users ready out of {}.".format(readyUsers, totalUsers)

		if totalUsers == readyUsers:
			message += " All users ready!"

		# Check whether there is anyone left in this match.
		if totalUsers == 0:
			message = "The match is now empty."

		chat.sendMessage(glob.BOT_NAME, chanName, message)
Example #8
0
	def setRestricted(self):
		"""
		Set this token as restricted, send FokaBot message to user
		and send offline packet to everyone

		:return:
		"""
		chat.sendMessage(glob.BOT_NAME, self.username, "Your account has been restricted! Please contact the RealistikOsu staff through our Discord server for more info!")
Example #9
0
	def resetRestricted(self):
		"""
		Send FokaBot message to alert the user that he has been unrestricted
		and he has to log in again.

		:return:
		"""
		chat.sendMessage(glob.BOT_NAME, self.username, "Your account has been unrestricted! Please re-log to refresh your status.")
Example #10
0
    def handle(self, data):
        handler_data = super().parseData(data)
        if handler_data is None: return

        chatHelper.sendMessage(
            fro=glob.BOT_NAME,
            to=handler_data["to"].encode("latin-1").decode("utf-8"),
            message=handler_data["message"].encode("latin-1").decode("utf-8"))
Example #11
0
 def onTick(tick):
     fmt = ""
     if tick >= 60:
         fmt = f"{tick // 60} minute{'s' if (tick // 60) > 1 else ''}"
     else:
         fmt = f"{tick} second{'s' if (tick) > 1 else ''}"
     chat.sendMessage(glob.BOT_NAME, channel,
                      f"Countdown ends in {fmt}")
Example #12
0
		def _start():
			matchID = getMatchIDFromChannel(chan)
			success = glob.matches.matches[matchID].start()
			if not success:
				chat.sendMessage("FokaBot", chan, "Couldn't start match. Make sure there are enough players and "
												  "teams are valid. The match has been unlocked.")
			else:
				chat.sendMessage("FokaBot", chan, "Have fun!")
Example #13
0
	def resetRestricted(self):
		"""
		Send Aika message to alert the user that he has been unrestricted
		and he has to log in again.

		:return:
		"""
		chat.sendMessage(glob.BOT_NAME, self.username, "Your account has been unrestricted! Please log in again.")
Example #14
0
	def setRestricted(self):
		"""
		Set this token as restricted, send Aika message to user
		and send offline packet to everyone

		:return:
		"""
		self.restricted = True
		chat.sendMessage(glob.BOT_NAME, self.username, "Your account is currently in restricted mode. Please visit Akatsuki's website for more information.")
Example #15
0
    def allPlayersCompleted(self):
        """
		Cleanup match stuff and send match end packet to everyone

		:return:
		"""
        # Collect some info about the match that just ended to send to the api
        infoToSend = {
            "id": self.matchID,
            "name": self.matchName,
            "beatmap_id": self.beatmapID,
            "mods": self.mods,
            "game_mode": self.gameMode,
            "scores": {}
        }

        # Add score info for each player
        for i in range(0, 16):
            if self.slots[i].user is not None and self.slots[
                    i].status == slotStatuses.PLAYING:
                infoToSend["scores"][glob.tokens.tokens[
                    self.slots[i].user].userID] = {
                        "score": self.slots[i].score,
                        "mods": self.slots[i].mods,
                        "failed": self.slots[i].failed,
                        "pass": self.slots[i].passed,
                        "team": self.slots[i].team
                    }

        # Send the info to the api
        glob.redis.publish("api:mp_complete_match", json.dumps(infoToSend))

        # Reset inProgress
        self.inProgress = False

        # Reset slots
        self.resetSlots()

        # Send match update
        self.sendUpdates()

        # Send match complete
        glob.streams.broadcast(self.streamName, serverPackets.matchComplete())

        # Destroy playing stream
        glob.streams.dispose(self.playingStreamName)
        glob.streams.remove(self.playingStreamName)

        # Console output
        log.info("MPROOM{}: Match completed".format(self.matchID))

        # If this is a tournament match, then we send a notification in the chat
        # saying that the match has completed.
        chanName = "#multi_{}".format(self.matchID)
        if self.isTourney and (chanName in glob.channels.channels):
            chat.sendMessage(glob.BOT_NAME, chanName,
                             "Match has just finished.")
Example #16
0
 def triggerStart():
     success = match.start(force=True)
     if not success:
         chat.sendMessage(
             glob.BOT_NAME, channel,
             "Couldn't start match. Make sure there are enough players and "
             "teams are valid. The match has been unlocked.")
     else:
         chat.sendMessage(glob.BOT_NAME, channel, "Match have started.")
Example #17
0
    def resetRestricted(self):
        """
		Send FokaBot message to alert the user that he has been unrestricted
		and he has to log in again.

		:return:
		"""
        chat.sendMessage(
            "FokaBot", self.username,
            "Your account has been unrestricted! Please log in again.")
Example #18
0
    def setRestricted(self):
        """
		Set this token as restricted, send FokaBot message to user
		and send offline packet to everyone

		:return:
		"""
        self.restricted = True
        chat.sendMessage(
            glob.botName, self.username,
            "Your account is currently in restricted mode. Please visit Yozora's website for more information."
        )
Example #19
0
    def setRestricted(self):
        """
		Set this token as restricted, send FokaBot message to user
		and send offline packet to everyone

		:return:
		"""
        self.restricted = True
        chat.sendMessage(
            glob.BOT_NAME, self.username,
            "Your account is currently in restricted mode. Please visit (Datenshi)[https://osu.troke.id] website or (Discord)[https://link.troke.id/datenshi] for more information."
        )
Example #20
0
 def onTick(tick):
     fmt = ""
     if tick >= 60:
         fmt = f"{tick // 60} minute{'s' if (tick // 60) > 1 else ''}"
     elif tick >= 3:
         fmt = f"{tick} second{'s' if (tick) > 1 else ''}"
     elif tick == 2:
         chat.sendMessage(glob.BOT_NAME, channel, "glhf!")
         return
     else:
         return
     chat.sendMessage(glob.BOT_NAME, channel, f"Match starts in {fmt}")
Example #21
0
	def spamProtection(self, increaseSpamRate = True):
		"""
		Silences the user if is spamming.

		:param increaseSpamRate: set to True if the user has sent a new message. Default: True
		:return:
		"""
		# Increase the spam rate if needed
		if increaseSpamRate:
			self.spamRate += 1

		# Silence the user if needed
		if self.spamRate > 10:
			self.silence(600, "Spamming (auto spam protection)")
			chat.sendMessage(
				glob.BOT_NAME,
				self.username.encode().decode("ASCII", "ignore"),
				"You have silenced, reason {}".format("Spamming (auto spam protection)")
			)
Example #22
0
 def help(response, token, sender, channel, message):
     userID = userUtils.getID(sender)
     for command, command_data in commands.items():
         chat.sendMessage(
             glob.BOT_NAME, sender,
             f"mp {command} {command_data.syntax} {('(requires %s or higher)' % (command_data.perm,) if command_data.perm != 'basic' else '') if command_data.mpOnly else '*can be used outside mp room*'}"
             .strip())
     chat.sendMessage(
         glob.BOT_NAME, sender,
         "This command still underwent heavy rewriting, those ugly terms and such will go soon(TM)."
     )
     chat.sendMessage(
         glob.BOT_NAME, sender,
         "Let (us) me know about the bancho mimicking that I need to do, I'll do my best!"
     )
     gloryID = 3  # oi.
     if userID == gloryID:
         chat.sendMessage(glob.BOT_NAME, sender,
                          "-- a note that you left behind.")
     else:
         gloryName = userUtils.getUsername(gloryID)
         chat.sendMessage(glob.BOT_NAME, sender, f"-- {gloryName}.")
     pass
Example #23
0
    def noticePrivmsgHandler(self, command, arguments):
        """NOTICE and PRIVMSG commands handler (same syntax)"""
        # Syntax check
        if len(arguments) == 0:
            self.replyCode(411, "No recipient given ({})".format(command))
            return
        if len(arguments) == 1:
            self.replyCode(412, "No text to send")
            return
        recipientIRC = arguments[0]
        message = arguments[1]

        # Send the message to bancho and reply
        if not recipientIRC.startswith("#"):
            recipientBancho = chat.fixUsernameForBancho(recipientIRC)
        else:
            recipientBancho = recipientIRC
        response = chat.sendMessage(self.banchoUsername,
                                    recipientBancho,
                                    message,
                                    toIRC=False)
        if response == 404:
            self.replyCode(404, "Cannot send to channel", channel=recipientIRC)
            return
        elif response == 403:
            self.replyCode(403, "No such channel", channel=recipientIRC)
            return
        elif response == 401:
            self.replyCode(401, "No such nick/channel", channel=recipientIRC)
            return

        # Send the message to IRC and bancho
        if recipientIRC.startswith("#"):
            # Public message (IRC)
            if recipientIRC not in glob.channels.channels:
                self.replyCode(401,
                               "No such nick/channel",
                               channel=recipientIRC)
                return
            for _, value in self.server.clients.items():
                if recipientIRC in value.joinedChannels and value != self:
                    value.message(":{} PRIVMSG {} :{}".format(
                        self.IRCUsername, recipientIRC, message))
        else:
            # Private message (IRC)
            for _, value in self.server.clients.items():
                if value.IRCUsername == recipientIRC:
                    value.message(":{} PRIVMSG {} :{}".format(
                        self.IRCUsername, recipientIRC, message))
Example #24
0
 def _decreaseTimer(t):
     if match.timerForce:
         chat.sendMessage(glob.BOT_NAME, chan, "Time is up!")
         match.timerForce = False
         match.timerRunned = False
     elif t <= 0:
         chat.sendMessage(glob.BOT_NAME, chan, "Time is up!")
         match.timerRunned = False
     else:
         if t % 10 == 0 or t <= 5:
             chat.sendMessage(glob.BOT_NAME, chan,
                              "Timer ends in {} seconds.".format(t))
         threading.Timer(1.00, _decreaseTimer, [t - 1]).start()
Example #25
0
def handle(userToken, packetData):
    # Send private message packet
    packetData = clientPackets.sendPrivateMessage(packetData)
    chat.sendMessage(token=userToken,
                     to=packetData["to"],
                     message=packetData["message"])
Example #26
0
def handle(userToken, packetData):
    # Send public message packet
    packetData = clientPackets.sendPublicMessage(packetData)
    chat.sendMessage(token=userToken,
                     target=packetData["to"],
                     message=packetData["message"])
Example #27
0
    def allPlayersCompleted(self):
        """
		Cleanup match stuff and send match end packet to everyone

		:return:
		"""
        # Collect some info about the match that just ended to send to the api
        infoToSend = {
            "id": self.matchID,
            "name": self.matchName,
            "beatmap_id": self.beatmapID,
            "mods": self.mods,
            "game_mode": self.gameMode,
            "host_id": self.hostUserID,
            "host_user_name": userUtils.getUsername(self.hostUserID),
            "game_type": self.matchTeamType,
            "game_score_condition": self.matchScoringType,
            "game_mod_mode": self.matchModMode,
            "scores": {}
        }

        # Add score info for each player
        for i in range(0, 16):
            if self.slots[i].user is not None and self.slots[
                    i].status == slotStatuses.PLAYING:
                infoToSend["scores"][glob.tokens.tokens[
                    self.slots[i].user].userID] = {
                        "score":
                        self.slots[i].score,
                        "mods":
                        self.slots[i].mods,
                        "failed":
                        self.slots[i].failed,
                        "pass":
                        self.slots[i].passed,
                        "team":
                        self.slots[i].team,
                        "username":
                        userUtils.getUsername(glob.tokens.tokens[
                            self.slots[i].user].userID)  # vinse shit ;3
                    }

        # Send the info to the api
        glob.redis.publish("api:mp_complete_match", json.dumps(infoToSend))
        self.games.append(json.dumps(infoToSend))

        # Reset inProgress
        self.inProgress = False

        # Reset slots
        self.resetSlots()

        # Send match update
        self.sendUpdates()

        # Send match complete
        glob.streams.broadcast(self.streamName, serverPackets.matchComplete())

        # Destroy playing stream
        glob.streams.dispose(self.playingStreamName)
        glob.streams.remove(self.playingStreamName)

        # Console output
        log.info("MPROOM{}: Match completed".format(self.matchID))

        chanName = "#multi_{}".format(self.matchID)
        if self.vinseID is None:
            self.vinseID = (int(time.time()) // (60 * 15)) << 32 | self.matchID
            chat.sendMessage(
                glob.BOT_NAME, chanName,
                "Match history available [{} here]".format(
                    "https://kurikku.pw/matches/{}".format(self.vinseID)))

        # If this is a tournament match, then we send a notification in the chat
        # saying that the match has completed.
        if self.isTourney and (chanName in glob.channels.channels):
            chat.sendMessage(glob.BOT_NAME, chanName,
                             "Match has just finished.")
Example #28
0
	def allPlayersCompleted(self):
		"""
		Cleanup match stuff and send match end packet to everyone

		:return:
		"""
		# Collect some info about the match that just ended to send to the api
		infoToSend = {
			"id": self.matchID,
			"name": self.matchName,
			"beatmap_id": self.beatmapID,
			"mods": self.mods,
			"game_mode": self.gameMode,
			"scores": {}
		}

		# Add score info for each player
		for i in range(0,16):
			if self.slots[i].user is not None and self.slots[i].status == slotStatuses.PLAYING:
				infoToSend["scores"][glob.tokens.tokens[self.slots[i].user].userID] = {
					"score": self.slots[i].score,
					"mods": self.slots[i].mods,
					"failed": self.slots[i].failed,
					"pass": self.slots[i].passed,
					"team": self.slots[i].team
				}

		# Send the info to the api
		glob.redis.publish("api:mp_complete_match", json.dumps(infoToSend))

		# Reset inProgress
		self.inProgress = False

		# Reset slots
		self.resetSlots()

		# Send match update
		self.sendUpdates()

		# Send match complete
		glob.streams.broadcast(self.streamName, serverPackets.matchComplete())

		# Destroy playing stream
		glob.streams.dispose(self.playingStreamName)
		glob.streams.remove(self.playingStreamName)

		# Console output
		log.info("MPROOM{}: Match completed".format(self.matchID))

		# Set vinse id if needed
		chanName = "#multi_{}".format(self.matchID)
		if self.vinseID is None:
			self.vinseID = (int(time.time()) // (60 * 15)) << 32 | self.matchID
			chat.sendMessage("FokaBot", chanName, "Match history available [{} here]".format(
				"https://vinse.ripple.moe/match/{}".format(self.vinseID)
			))
		if not self.bloodcatAlert:
			chat.sendMessage(
				"FokaBot",
				chanName,
				"Oh by the way, in case you're playing unranked or broken maps "
				"that are now available through ripple's osu!direct, you can "
				"type '!bloodcat' in the chat to get a download link for the "
				"currently selected map from Bloodcat!"
			)
			self.bloodcatAlert = True

		# If this is a tournament match, then we send a notification in the chat
		# saying that the match has completed.
		if self.isTourney and (chanName in glob.channels.channels):
			chat.sendMessage(glob.BOT_NAME, chanName, "Match has just finished.")
Example #29
0
    def allPlayersCompleted(self):
        """
		Cleanup match stuff and send match end packet to everyone

		:return:
		"""
        # Collect some info about the match that just ended to send to the api
        infoToSend = {
            "id": self.matchID,
            "name": self.matchName,
            "beatmap_id": self.beatmapID,
            "mods": self.mods,
            "game_mode": self.gameMode,
            "scores": {}
        }

        # Add score info for each player
        for i in range(0, 16):
            if self.slots[i].user is not None and self.slots[
                    i].status == slotStatuses.PLAYING:
                infoToSend["scores"][glob.tokens.tokens[
                    self.slots[i].user].userID] = {
                        "score": self.slots[i].score,
                        "mods": self.slots[i].mods,
                        "failed": self.slots[i].failed,
                        "pass": self.slots[i].passed,
                        "team": self.slots[i].team
                    }

        # Send the info to the api
        glob.redis.publish("api:mp_complete_match", json.dumps(infoToSend))

        # Reset inProgress
        self.inProgress = False

        # Reset slots
        self.resetSlots()

        # Send match update
        self.sendUpdates()

        # Send match complete
        glob.streams.broadcast(self.streamName, serverPackets.matchComplete())

        # Destroy playing stream
        glob.streams.dispose(self.playingStreamName)
        glob.streams.remove(self.playingStreamName)

        # Console output
        log.info("MPROOM{}: Match completed".format(self.matchID))

        # Set vinse id if needed
        chanName = "#multi_{}".format(self.matchID)
        if self.vinseID is None:
            self.vinseID = (int(time.time()) // (60 * 15)) << 32 | self.matchID
            chat.sendMessage(
                glob.BOT_NAME, chanName,
                "Match history available [{} here]".format(
                    "https://multi.troke.id/match/{}".format(self.vinseID)))
        #ganti ke if not kalau error
        if not self.bloodcatAlert:
            chat.sendMessage(
                glob.BOT_NAME, chanName,
                "You can use !bloodcat for another beatmap mirror, in case if you have a problem with osudirect"
            )
            self.bloodcatAlert = True

        # If this is a tournament match, then we send a notification in the chat
        # saying that the match has completed.
        if self.isTourney and (chanName in glob.channels.channels):
            chat.sendMessage(glob.BOT_NAME, chanName,
                             "Match has just finished.")
Example #30
0
def edit_map(fro, chan, message): # Edit maps ranking status ingame. // Added by cmyui :) // cmyui why u dont like PEP8?
    messages = [m.lower() for m in message]
    rank_type = message[0]
    map_type = message[1]
    map_id = message[2]

    # Get persons username & ID
    user_id = userUtils.getID(fro)
    name = userUtils.getUsername(user_id)

    typeBM = None

    # Figure out what to do
    if rank_type == 'rank':
        rank_typed_str = 'ranke'
        rank_type_id = 2
        freeze_status = 1
    elif rank_type == 'love':
        rank_typed_str = 'love'
        rank_type_id = 5
        freeze_status = 1
    elif rank_type == 'unrank':
        rank_typed_str = 'unranke'
        rank_type_id = 0
        freeze_status = 0

    # Grab beatmap_data from db
    beatmap_data = glob.db.fetch("SELECT * FROM beatmaps WHERE beatmap_id = {} LIMIT 1".format(map_id))

    if map_type == 'set':
        glob.db.execute(
            "UPDATE beatmaps SET ranked = {}, ranked_status_freezed = {} WHERE beatmapset_id = {} LIMIT 100".format(
                rank_type_id, freeze_status, beatmap_data["beatmapset_id"]))
        if freeze_status == 1:
            glob.db.execute("""UPDATE scores s JOIN (SELECT userid, MAX(score) maxscore FROM scores JOIN beatmaps ON scores.beatmap_md5 = beatmaps.beatmap_md5 WHERE beatmaps.beatmap_md5 = (SELECT beatmap_md5 FROM beatmaps
					WHERE beatmapset_id = {} LIMIT 1) GROUP BY userid) s2 ON s.score = s2.maxscore AND s.userid = s2.userid SET completed = 3""".format(
                beatmap_data["beatmapset_id"]))
        typeBM = 'set'
    elif map_type == 'map':
        glob.db.execute(
            "UPDATE beatmaps SET ranked = {}, ranked_status_freezed = {} WHERE beatmap_id = {} LIMIT 1".format(
                rank_type_id, freeze_status, map_id))
        if freeze_status == 1:
            glob.db.execute("""UPDATE scores s JOIN (SELECT userid, MAX(score) maxscore FROM scores JOIN beatmaps ON scores.beatmap_md5 = beatmaps.beatmap_md5 WHERE beatmaps.beatmap_md5 = (SELECT beatmap_md5 FROM beatmaps
					WHERE beatmap_id = {} LIMIT 1) GROUP BY userid) s2 ON s.score = s2.maxscore AND s.userid = s2.userid SET completed = 3""".format(
                beatmap_data["beatmap_id"]))
        typeBM = 'beatmap'
    else:
        return "Please specify whether it is a set/map. eg: '!map unrank/rank/love set/map 123456'"

    # Announce / Log to AP logs when ranked status is changed
    if rank_type == "love":
        log.rap(user_id,
                "has {}d beatmap ({}): {} ({}).".format(rank_type, map_type, beatmap_data["song_name"], map_id),
                True)
        if map_type == 'set':
            msg = "{} has loved beatmap set: [https://osu.ppy.sh/s/{} {}]".format(name, beatmap_data["beatmapset_id"],
                                                                                  beatmap_data["song_name"])
        else:
            msg = "{} has loved beatmap: [https://osu.ppy.sh/s/{} {}]".format(name, map_id, beatmap_data["song_name"])

        glob.db.execute(
            "UPDATE scores s JOIN (SELECT userid, MAX(score) maxscore FROM scores JOIN beatmaps ON scores.beatmap_md5 = beatmaps.beatmap_md5 WHERE beatmaps.beatmap_md5 = (SELECT beatmap_md5 FROM beatmaps WHERE beatmap_id = {} LIMIT 1) GROUP BY userid) s2 ON s.score = s2.maxscore AND s.userid = s2.userid SET completed = 2".format(
                beatmap_data["beatmap_id"]))
    elif rank_type == "rank":
        log.rap(user_id,
                "has {}ed beatmap ({}): {} ({}).".format(rank_type, map_type, beatmap_data["song_name"], map_id),
                True)
        if map_type == 'set':
            msg = "{} has {}ed beatmap set: [https://osu.ppy.sh/s/{} {}]".format(name, rank_type,
                                                                                 beatmap_data["beatmapset_id"],
                                                                                 beatmap_data["song_name"])
        else:
            msg = "{} has {}ed beatmap: [https://osu.ppy.sh/s/{} {}]".format(name, rank_type, map_id,
                                                                             beatmap_data["song_name"])
        glob.db.execute(
            "UPDATE scores s JOIN (SELECT userid, MAX(score) maxscore FROM scores JOIN beatmaps ON scores.beatmap_md5 = beatmaps.beatmap_md5 WHERE beatmaps.beatmap_md5 = (SELECT beatmap_md5 FROM beatmaps WHERE beatmap_id = {} LIMIT 1) GROUP BY userid) s2 ON s.score = s2.maxscore AND s.userid = s2.userid SET completed = 2".format(
                beatmap_data["beatmap_id"]))
    else:
        log.rap(user_id,
                "has {}ed beatmap ({}): {} ({}).".format(rank_type, map_type, beatmap_data["song_name"], map_id),
                True)
        if map_type == 'set':
            msg = "{} has {}ed beatmap set: [https://osu.ppy.sh/s/{} {}]".format(name, rank_type,
                                                                                 beatmap_data["beatmapset_id"],
                                                                                 beatmap_data["song_name"])
        else:
            msg = "{} has {}ed beatmap: [https://osu.ppy.sh/s/{} {}]".format(name, rank_type, map_id,
                                                                             beatmap_data["song_name"])

            glob.db.execute(
                "UPDATE scores s JOIN (SELECT userid, MAX(score) maxscore FROM scores JOIN beatmaps ON scores.beatmap_md5 = beatmaps.beatmap_md5 WHERE beatmaps.beatmap_md5 = (SELECT beatmap_md5 FROM beatmaps WHERE beatmap_id = {} LIMIT 1) GROUP BY userid) s2 ON s.score = s2.maxscore AND s.userid = s2.userid SET completed = 2".format(
                    beatmap_data["beatmap_id"]))

    need_params = {
        'token': glob.conf.config["discord"]["krbotToken"],
        'poster': fro,
        'type': rank_typed_str
    }
    if typeBM == 'set':
        need_params['sid'] = beatmap_data["beatmapset_id"]
    else:
        need_params['bid'] = beatmap_data["beatmap_id"]
    requests.get(glob.conf.config["discord"]["krbot"] + "api/v1/submitMap", params=need_params)

    chat.sendMessage(glob.BOT_NAME, "#nowranked", msg)
    return msg