예제 #1
0
파일: backend.py 프로젝트: Supsu/raidaudit
class Backend:
    db = ""
    bnet = ""
    rio = ""
    wcl = ""
    realm = ""
    region = ""

    def __init__(self):
        load_dotenv()
        self.db = Database()
        self.bnet = Bnet()
        self.rio = RIO()
        self.wcl = WCL()
        self.region = os.getenv("WOWREGION")
        self.realm = os.getenv("WOWREALM")

    def getView(self) -> List[Dict[str, str]]:
        """
        Get data for roster table
        """
        def sorter(item) -> Tuple[int, str]:
            roleprio = 0
            if item["Role"] == "Tank":
                roleprio = 1
            elif item["Role"] == "Healer":
                roleprio = 2
            elif item["Role"] == "DPS":
                roleprio = 3
            else:
                roleprio = 4

            return (roleprio, item["name"])

        data = self.db.getIndex()

        listed = sorted(data, key=sorter)

        return listed

    def getBlog(self):
        """
        Get blog posts
        """
        data = self.db.getBlog()
        return data

    def getSingleBlog(self, id: str):
        """
        Get a single blog post with id
        """
        # TODO create a db.py method for getting single blog, this is ugly
        return self.db.db.blog.find_one({"id": id})

    def getLogs(self):
        """
        Get most recent logs for guild from WCL
        """

        data = json.loads(self.wcl.getGuildLogs())

        if "error" in data:
            data = [{"title": "Error!", "start": data["error"], "id": " "}]

        elif len(data) > 10:
            data = data[0:10]

        for row in data:
            row["start"] = time.strftime(
                '%Y-%m-%d', time.localtime(int(row["start"] / 1000)))

        return data

    def updateView(self):
        """
        Update view tables from db
        """
        pass

    def addPlayer(self, player: Dict[str, str]) -> bool:
        """
        Add player to roster manually
        """

        self.db.addPlayer(player["name"], player["Class"], player["Role"])

        return True

    def removePlayer(self, player: Dict[str, str]) -> bool:
        """
        Remove player from roster
        """
        query = {"name": player["name"]}

        collection = ""

        if player["automated"]:
            collection = "autoplayers"

        else:
            collection = "players"

        res = self.db.remove(collection, query)

        return res

    def updateRoster(self):
        """
        Update roster data
        """
        # get raiders from bnet
        roster = self.bnet.getRoster()
        manuals = self.db.getManualPlayers()

        print(roster)
        print(manuals)

        # iterate over players and get full data
        for i in roster:
            tmp = {
                "name": "",
                "Class": "",
                "Role": "",
                "ilv": 0.0,
                "Weekly": 0,
                "rio": 0.0,
                "wcln": 0.0,
                "wclh": 0.0,
                "wclm": 0.0
            }

            name = i["name"]
            cclass = i["class"]

            tmp["name"] = name
            tmp["Class"] = cclass
            tmp["Role"] = self.db.findRole(name)

            print("Getting ilv from battle.net profile for " + name)
            bnetprofile = self.bnet.getCharacterProfile(name)
            tmp["ilv"] = bnetprofile["average_item_level"]

            print("Getting m+ data from raider.io for " + name)
            rioprofile = self.rio.getProfile(name)

            # will return empty list if there are no runs for the week
            if len(rioprofile["mythic_plus_weekly_highest_level_runs"]) == 0:
                tmp["Weekly"] = 0
            else:
                tmp["Weekly"] = int(
                    rioprofile["mythic_plus_weekly_highest_level_runs"][0]
                    ["mythic_level"])

            # in case of no data, should still return 0 as a score
            tmp["rio"] = float(
                rioprofile["mythic_plus_scores_by_season"][0]["scores"]["all"])

            wclperf = self.wcl.getPlayerAvg(name)

            tmp["wcln"] = wclperf["avgN"]
            tmp["wclh"] = wclperf["avgH"]
            tmp["wclm"] = wclperf["avgM"]

            dbquery = {"name": name}
            dbnewdata = {"$set": tmp}

            # push updated automated players to DB
            # TODO create a method for updating in db.py this is ugly
            self.db.db.autoplayers.update_one(dbquery, dbnewdata, upsert=True)

        # TODO refactor this to have only one loop / function call
        # ugly repeating loop

        for i in manuals:
            tmp = {
                "name": "",
                "Class": "",
                "Role": "",
                "ilv": 0.0,
                "Weekly": 0,
                "rio": 0.0,
                "wcln": 0.0,
                "wclh": 0.0,
                "wclm": 0.0
            }

            name = i["name"]
            cclass = i["Class"]

            tmp["name"] = name
            tmp["Class"] = cclass
            tmp["Role"] = self.db.findRole(name)

            print("Getting ilv from battle.net profile for " + name)
            bnetprofile = self.bnet.getCharacterProfile(name)
            tmp["ilv"] = bnetprofile["average_item_level"]

            print("Getting m+ data from raider.io for " + name)
            rioprofile = self.rio.getProfile(name)
            # will return empty list if there are no runs for the week
            if len(rioprofile["mythic_plus_weekly_highest_level_runs"]) == 0:
                tmp["Weekly"] = 0
            else:
                tmp["Weekly"] = int(
                    rioprofile["mythic_plus_weekly_highest_level_runs"][0]
                    ["mythic_level"])

            tmp["rio"] = float(
                rioprofile["mythic_plus_scores_by_season"][0]["scores"]["all"])

            wclperf = self.wcl.getPlayerAvg(name)

            tmp["wcln"] = wclperf["avgN"]
            tmp["wclh"] = wclperf["avgH"]
            tmp["wclm"] = wclperf["avgM"]

            dbquery = {"name": name}
            dbnewdata = {"$set": tmp}

            # push updated automated players to DB
            # TODO create a method for updating in db.py this is ugly
            self.db.db.players.update_one(dbquery, dbnewdata, upsert=True)

        # Update updating time to settings
        # TODO this needs methods, ugly
        print("Setting update timestamp to " + str(int(time.time())))
        response = self.db.db.settings.update_one(
            {}, {"$set": {
                "timestamp": int(time.time())
            }}, upsert=False)
        print("Modified " + str(response.modified_count) + " entries")

        # TODO implement some kind of error handling and return False in
        # case there is an error
        return True

    def login(self, usr: str, pwd: str):
        """
        Check login information
        """

        settings = self.db.getSettings()

        boolusr = False
        boolpwd = False

        # check admin credentials
        if settings["adminname"] == usr:
            boolusr = True
        if settings["adminpwd"] == pwd:
            boolpwd = True

        if boolusr and boolpwd:
            return boolusr, boolpwd
        else:
            # check additional login table for officers etc
            # TODO
            return boolusr, boolpwd

    def post(self, title: str, content: str):
        r = self.db.postBlog(title, content)

        return r

    def getUpdateTimestamp(self):
        return self.db.getSettings()["timestamp"]

    def editPlayerRole(self, playername: str, playerrole: str,
                       automated: bool):
        self.db.updateRole(playername, playerrole, automated)

    def getSideBar(self):
        """
        Gets data for sidebar.

        Initializes a sidebar element list.
        Calls rio.py method getRaidProgress() to get raid progress
        from raider.io

        Returns:
            List of sidebar entities, where [0] is reserved for raid progress
            and [1] for raidaudit version
        """
        sidebar = [{"progress": "NA"}, {"version": "NA"}]

        progress = self.rio.getRaidProgress()
        sidebar[0] = progress
        return sidebar

    def getLinkInfo(self):
        """
        Get realm, region and locale data to generate links to roster table
        """
        info = {"locale": "en-gb", "region": self.region, "realm": self.realm}

        # TODO support all regions? now only eu/us
        if info["region"] == "us":
            info["locale"] = "en-us"

        return info

    def getLootLog(self,
                   loot_file: Union[str, List[str]],
                   time_descending: bool = False) -> List[LootItemData]:
        """
        Fetches RC loot council loot data from .csv file(s) and returns a list of LootItemData objects in time-sorted
        order from latest to oldest.

        Args:
            loot_file (:obj: `str`, :obj: `list` of :obj: `str`): Contains the filename, directory name or
                list of filenames containing the data
            time_descending (bool, optional): Set to true to sort from oldest to newest. Otherwise sorts from
                newest to oldest.

        Returns:
            List: :obj: `LootItemData` objects sorted by time.
        """
        # Pull data from file(s)
        pulled_data = []
        indexes = []
        if isinstance(loot_file, list):
            for filename in loot_file:
                with open(filename) as f:
                    reader = csv.DictReader(f)
                    for row in reader:
                        pulled_data.append(dict(row))
        elif os.path.isdir(loot_file):
            files = [
                os.path.join(loot_file, f) for f in os.listdir(loot_file)
                if os.path.isfile(os.path.join(loot_file, f)) and '.csv' in f
            ]
            for file in files:
                with open(file) as f:
                    reader = csv.DictReader(f)
                    for row in reader:
                        pulled_data.append(dict(row))
        elif os.path.isfile(loot_file):
            with open(loot_file) as f:
                reader = csv.DictReader(f)
                for row in reader:
                    pulled_data.append(dict(row))

        # parse data in file(s)
        loot_list = []
        for loot_data in pulled_data:
            itemstring = loot_data['itemString']
            vals = itemstring.split(':')
            item_id = loot_data['itemID']
            bonuses = vals[14:]
            url = f"https://www.wowhead.com/item={item_id}&bonus={':'.join(bonuses)}"
            date_string = loot_data['date'] + " " + loot_data['time']
            date = datetime.strptime(date_string, '%d/%m/%y %H:%M:%S')
            loot = LootItemData(recipient=loot_data['player'],
                                recipient_class=loot_data['class'],
                                received_time=date,
                                original_owner=loot_data['owner'],
                                response=loot_data['response'],
                                boss_name=loot_data['boss'],
                                instance_name=loot_data['instance'],
                                item_id=loot_data['itemID'],
                                item_name=loot_data['item'],
                                item_url=url,
                                realm_name="Stormscale")
            loot_list.append(loot)

        loot_list.sort(key=operator.attrgetter('received_time'),
                       reverse=not time_descending)

        return loot_list

    def getLoots(self):
        """Gets loot log data from DB

        Gets the loot log data through DB.

        Returns:
            entrylist: List containing database entries
        """

        entrylist = []

        loot = self.db.getLoot()
        for entry in loot:
            entrylist.append(LootItemData(**entry))

        for item in entrylist:
            print(item)
        return entrylist

    def addLoots(self) -> bool:
        """Adds loot data from .cvs files to database

        Returns:
            bool: True if no exceptions were raised
        """
        try:
            lootlist = self.getLootLog("lootdata")
            self.db.addLoot(lootlist)
        except:
            return False

        try:
            rmFiles = glob.glob("./lootdata/*.csv")
            for file in rmFiles:
                os.remove(file)
        except OSError:
            return False

        return True
예제 #2
0
class Backend:

    db = ""
    bnet = ""
    rio = ""
    wcl = ""
    realm = ""
    region = ""

    def __init__(self):
        load_dotenv()
        self.db = Database()
        self.bnet = Bnet()
        self.rio = RIO()
        self.wcl = WCL()
        self.region = os.getenv("WOWREGION")
        self.realm = os.getenv("WOWREALM")

    def getView(self) -> List[Dict[str, str]]:
        """
		Get data for roster table
		"""
        def sorter(item) -> Tuple[int, str]:
            roleprio = 0
            if item["Role"] == "Tank":
                roleprio = 1
            elif item["Role"] == "Healer":
                roleprio = 2
            elif item["Role"] == "DPS":
                roleprio = 3
            else:
                roleprio = 4

            return (roleprio, item["name"])

        data = self.db.getIndex()

        listed = sorted(data, key=sorter)

        return listed

    def getBlog(self):
        """
		Get blog posts
		"""
        data = self.db.getBlog()
        return data

    def getSingleBlog(self, id: str):
        """
		Get a single blog post with id
		"""
        # TODO create a db.py method for getting single blog, this is ugly
        return self.db.db.blog.find_one({"id": id})

    def getLogs(self):
        """
		Get most recent logs for guild from WCL
		"""

        data = json.loads(self.wcl.getGuildLogs())

        if "error" in data:

            data = [{"title": "Error!", "start": data["error"], "id": " "}]

        elif len(data) > 10:
            data = data[0:10]

        for row in data:
            row["start"] = time.strftime(
                '%Y-%m-%d', time.localtime(int(row["start"] / 1000)))

        return data

    def updateView(self):
        """
		Update view tables from db
		"""
        pass

    def addPlayer(self, player: Dict[str, str]) -> bool:
        """
		Add player to roster manually
		"""

        self.db.addPlayer(player["name"], player["Class"], player["Role"])

        return True

    def removePlayer(self, player):
        """
		Remove player from roster
		"""
        pass

    def updateRoster(self):
        """
		Update roster data
		"""
        # get raiders from bnet
        roster = self.bnet.getRoster()
        manuals = self.db.getManualPlayers()

        print(roster)
        print(manuals)

        # iterate over players and get full data
        for i in roster:
            tmp = {
                "name": "",
                "Class": "",
                "Role": "",
                "ilv": 0.0,
                "Weekly": 0,
                "rio": 0.0,
                "wcln": 0.0,
                "wclh": 0.0,
                "wclm": 0.0
            }

            name = i["name"]
            cclass = i["class"]

            tmp["name"] = name
            tmp["Class"] = cclass
            tmp["Role"] = self.db.findRole(name)

            print("Getting ilv from battle.net profile for " + name)
            bnetprofile = self.bnet.getCharacterProfile(name)
            tmp["ilv"] = bnetprofile["average_item_level"]

            print("Getting m+ data from raider.io for " + name)
            rioprofile = self.rio.getProfile(name)

            # will return empty list if there are no runs for the week
            if len(rioprofile["mythic_plus_weekly_highest_level_runs"]) == 0:
                tmp["Weekly"] = 0
            else:
                tmp["Weekly"] = int(
                    rioprofile["mythic_plus_weekly_highest_level_runs"][0]
                    ["mythic_level"])

            # in case of no data, should still return 0 as a score
            tmp["rio"] = float(
                rioprofile["mythic_plus_scores_by_season"][0]["scores"]["all"])

            wclperf = self.wcl.getPlayerAvg(name)

            tmp["wcln"] = wclperf["avgN"]
            tmp["wclh"] = wclperf["avgH"]
            tmp["wclm"] = wclperf["avgM"]

            dbquery = {"name": name}
            dbnewdata = {"$set": tmp}

            # push updated automated players to DB
            # TODO create a method for updating in db.py this is ugly
            self.db.db.autoplayers.update_one(dbquery, dbnewdata, upsert=True)

        # TODO refactor this to have only one loop / function call
        # ugly repeating loop

        for i in manuals:
            tmp = {
                "name": "",
                "Class": "",
                "Role": "",
                "ilv": 0.0,
                "Weekly": 0,
                "rio": 0.0,
                "wcln": 0.0,
                "wclh": 0.0,
                "wclm": 0.0
            }

            name = i["name"]
            cclass = i["Class"]

            tmp["name"] = name
            tmp["Class"] = cclass
            tmp["Role"] = self.db.findRole(name)

            print("Getting ilv from battle.net profile for " + name)
            bnetprofile = self.bnet.getCharacterProfile(name)
            tmp["ilv"] = bnetprofile["average_item_level"]

            print("Getting m+ data from raider.io for " + name)
            rioprofile = self.rio.getProfile(name)
            # will return empty list if there are no runs for the week
            if len(rioprofile["mythic_plus_weekly_highest_level_runs"]) == 0:
                tmp["Weekly"] = 0
            else:
                tmp["Weekly"] = int(
                    rioprofile["mythic_plus_weekly_highest_level_runs"][0]
                    ["mythic_level"])

            tmp["rio"] = float(
                rioprofile["mythic_plus_scores_by_season"][0]["scores"]["all"])

            wclperf = self.wcl.getPlayerAvg(name)

            tmp["wcln"] = wclperf["avgN"]
            tmp["wclh"] = wclperf["avgH"]
            tmp["wclm"] = wclperf["avgM"]

            dbquery = {"name": name}
            dbnewdata = {"$set": tmp}

            # push updated automated players to DB
            # TODO create a method for updating in db.py this is ugly
            self.db.db.players.update_one(dbquery, dbnewdata, upsert=True)

        #Update updating time to settings
        #TODO this needs methods, ugly
        print("Setting update timestamp to " + str(int(time.time())))
        response = self.db.db.settings.update_one(
            {}, {"$set": {
                "timestamp": int(time.time())
            }}, upsert=False)
        print("Modified " + str(response.modified_count) + " entries")

        # TODO implement some kind of error handling and return False in
        # case there is an error
        return True

    def updateDB(self):
        """
		Update players in database from r.io and wcl
		"""
        pass

    def login(self, usr: str, pwd: str):
        """
		Check login information
		"""

        settings = self.db.getSettings()

        boolusr = False
        boolpwd = False

        # check admin credentials
        if settings["adminname"] == usr:
            boolusr = True
        if settings["adminpwd"] == pwd:
            boolpwd = True

        if boolusr and boolpwd:
            return boolusr, boolpwd
        else:
            #check additional login table for officers etc
            #TODO
            return boolusr, boolpwd

    def post(self, title: str, content: str):
        r = self.db.postBlog(title, content)

        return r

    def getUpdateTimestamp(self):
        return self.db.getSettings()["timestamp"]

    def editPlayerRole(self, playername: str, playerrole: str,
                       automated: bool):
        self.db.updateRole(playername, playerrole, automated)

    def getSideBar(self):
        """
		Gets data for sidebar.

		Initializes a sidebar element list.
		Calls rio.py method getRaidProgress() to get raid progress from raider.io

		Returns:
			List of sidebar entities, where [0] is reserved for raid progress and [1] for raidaudit version
		"""
        sidebar = [{"progress": "NA"}, {"version": "NA"}]

        progress = self.rio.getRaidProgress()
        sidebar[0] = progress
        return sidebar

    def getLinkInfo(self):
        """
		Get realm, region and locale data to generate links to roster table
		"""
        info = {"locale": "en-gb", "region": self.region, "realm": self.realm}

        # TODO support all regions? now only eu/us
        if info["region"] == "us":
            info["locale"] = "en-us"

        return info