diff --git a/monocle/db.py b/monocle/db.py index f1d1eeb2..be57f688 100644 --- a/monocle/db.py +++ b/monocle/db.py @@ -4,7 +4,7 @@ from enum import Enum from time import time, mktime -from sqlalchemy import Column, Integer, String, Float, SmallInteger, BigInteger, ForeignKey, UniqueConstraint, create_engine, cast, func, desc, asc, and_, exists +from sqlalchemy import Column, Integer, String, Float, SmallInteger, BigInteger, Boolean, ForeignKey, UniqueConstraint, create_engine, cast, func, desc, asc, and_, exists from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy.types import TypeDecorator, Numeric, Text from sqlalchemy.ext.declarative import declarative_base @@ -281,6 +281,7 @@ class Fort(Base): id = Column(Integer, primary_key=True) external_id = Column(String(35), unique=True) + name = Column(String(255)) lat = Column(FLOAT_TYPE) lon = Column(FLOAT_TYPE) @@ -289,6 +290,12 @@ class Fort(Base): backref='fort', order_by='FortSighting.last_modified' ) + + members = relationship( + 'FortMember', + backref='fort', + order_by='FortMember.last_modified' + ) class FortSighting(Base): @@ -298,8 +305,10 @@ class FortSighting(Base): fort_id = Column(Integer, ForeignKey('forts.id')) last_modified = Column(Integer, index=True) team = Column(TINY_TYPE) - prestige = Column(MEDIUM_TYPE) + is_in_battle = Column(Boolean, default=False) guard_pokemon_id = Column(TINY_TYPE) + slots_available = Column(TINY_TYPE) + time_ocuppied = Column(Integer) __table_args__ = ( UniqueConstraint( @@ -309,6 +318,30 @@ class FortSighting(Base): ), ) +class FortMember(Base): + __tablename__ = 'fort_members' + + id = Column(Integer, primary_key=True) + fort_id = Column(Integer, ForeignKey('forts.id')) + last_modified = Column(Integer, index=True) + player_name = Column(String(100), index=True) + player_level = Column(TINY_TYPE) + pokemon_id = Column(TINY_TYPE) + pokemon_cp = Column(SmallInteger) + move_1 = Column(SmallInteger) + move_2 = Column(SmallInteger) + individual_attack = Column(TINY_TYPE) + individual_defense = Column(TINY_TYPE) + individual_stamina = Column(TINY_TYPE) + time_deploy = Column(Integer) + __table_args__ = ( + UniqueConstraint( + 'fort_id', + 'player_name', + 'last_modified', + name='fort_last_modif_name_unique' + ), + ) class Pokestop(Base): __tablename__ = 'pokestops' @@ -467,6 +500,7 @@ def add_fort_sighting(session, raw_fort): if not fort: fort = Fort( external_id=raw_fort['external_id'], + name=raw_fort['name'], lat=raw_fort['lat'], lon=raw_fort['lon'], ) @@ -481,14 +515,45 @@ def add_fort_sighting(session, raw_fort): obj = FortSighting( fort=fort, team=raw_fort['team'], - prestige=raw_fort['prestige'], guard_pokemon_id=raw_fort['guard_pokemon_id'], last_modified=raw_fort['last_modified'], + is_in_battle=raw_fort['is_in_battle'], + slots_available=raw_fort['slots_available'], + time_ocuppied=raw_fort['time_ocuppied'] ) session.add(obj) FORT_CACHE.add(raw_fort) +def add_fort_member(session, raw_fort_member): + # Check if raid exists + fort = session.query(Fort) \ + .filter(Fort.external_id == raw_fort_member['external_id']) \ + .first() + if fort and session.query(FortMember) \ + .filter(FortMember.fort_id == fort.id) \ + .filter(FortMember.player_name == raw_fort_member['player_name']) \ + .filter(FortMember.last_modified == raw_fort_member['last_modified']) \ + .first(): + return + else: + obj = FortMember( + fort=fort, + player_name=raw_fort_member['player_name'], + player_level=raw_fort_member['player_level'], + pokemon_id=raw_fort_member['pokemon_id'], + pokemon_cp=raw_fort_member['pokemon_cp'], + move_1=raw_fort_member['move_1'], + move_2=raw_fort_member['move_2'], + individual_attack=raw_fort_member['individual_attack'], + individual_defense=raw_fort_member['individual_defense'], + individual_stamina=raw_fort_member['individual_stamina'], + time_deploy=raw_fort_member['time_deploy'], + last_modified=raw_fort_member['last_modified'] + ) + session.add(obj) + + def add_pokestop(session, raw_pokestop): pokestop_id = raw_pokestop['external_id'] if session.query(exists().where( @@ -553,11 +618,14 @@ def _get_forts_sqlite(session): fs.fort_id, fs.id, fs.team, - fs.prestige, fs.guard_pokemon_id, fs.last_modified, + fs.is_in_battle, + fs.slots_available, + fs.time_ocuppied, f.lat, - f.lon + f.lon, + f.name FROM fort_sightings fs JOIN forts f ON f.id=fs.fort_id WHERE fs.fort_id || '-' || fs.last_modified IN ( @@ -574,11 +642,14 @@ def _get_forts(session): fs.fort_id, fs.id, fs.team, - fs.prestige, fs.guard_pokemon_id, fs.last_modified, + fs.is_in_battle, + fs.slots_available, + fs.time_ocuppied, f.lat, - f.lon + f.lon, + f.name FROM fort_sightings fs JOIN forts f ON f.id=fs.fort_id WHERE (fs.fort_id, fs.last_modified) IN ( diff --git a/monocle/db_proc.py b/monocle/db_proc.py index 772ad7d8..22cfd6e6 100644 --- a/monocle/db_proc.py +++ b/monocle/db_proc.py @@ -47,6 +47,8 @@ def run(self): self.count += 1 elif item_type == 'fort': db.add_fort_sighting(session, item) + elif item_type == 'fort_member': + db.add_fort_member(session, item) elif item_type == 'pokestop': db.add_pokestop(session, item) elif item_type == 'target': diff --git a/monocle/worker.py b/monocle/worker.py index f41d6987..4e535a39 100644 --- a/monocle/worker.py +++ b/monocle/worker.py @@ -831,7 +831,52 @@ async def visit_point(self, point, spawn_id, bootstrap, pokestop = self.normalize_pokestop(fort) db_proc.add(pokestop) elif fort not in FORT_CACHE: - db_proc.add(self.normalize_gym(fort)) + request = self.api.create_request() + request.gym_get_info( + gym_id=fort.id, + player_lat_degrees = self.location[0], + player_lng_degrees = self.location[1], + gym_lat_degrees=fort.latitude, + gym_lng_degrees=fort.longitude + ) + responses = await self.call(request, action=1.2) + try: + if responses['GYM_GET_INFO'].result != 1: + self.log.warning("Failed to get gym_info {}", fort.id) + else: + gym_get_info = responses['GYM_GET_INFO'] + rawFort = {} + rawFort['external_id'] = fort.id + rawFort['name'] = gym_get_info.name + rawFort['lat'] = fort.latitude + rawFort['lon'] = fort.longitude + rawFort['team'] = fort.owned_by_team + rawFort['guard_pokemon_id'] = fort.guard_pokemon_id + rawFort['last_modified'] = fort.last_modified_timestamp_ms // 1000 + rawFort['is_in_battle'] = fort.is_in_battle + rawFort['slots_available'] = fort.gym_display.slots_available + rawFort['time_ocuppied'] = fort.gym_display.occupied_millis // 1000 + db_proc.add(self.normalize_gym(rawFort)) + + gym_members = gym_get_info.gym_status_and_defenders + + for gym_member in gym_members.gym_defender: + raw_member = {} + raw_member['external_id'] = fort.id + raw_member['player_name'] = gym_member.trainer_public_profile.name + raw_member['player_level'] = gym_member.trainer_public_profile.level + raw_member['pokemon_id'] = gym_member.motivated_pokemon.pokemon.pokemon_id + raw_member['pokemon_cp'] = gym_member.motivated_pokemon.pokemon.cp + raw_member['move_1'] = gym_member.motivated_pokemon.pokemon.move_1 + raw_member['move_2'] = gym_member.motivated_pokemon.pokemon.move_2 + raw_member['individual_attack'] = gym_member.motivated_pokemon.pokemon.individual_attack + raw_member['individual_defense'] = gym_member.motivated_pokemon.pokemon.individual_defense + raw_member['individual_stamina'] = gym_member.motivated_pokemon.pokemon.individual_stamina + raw_member['time_deploy'] = gym_member.motivated_pokemon.deploy_ms // 1000 + raw_member['last_modified'] = rawFort['last_modified'] + db_proc.add(self.normalize_gym_member(raw_member)) + except KeyError: + self.log.warning("Failed to get gym_info {}", fort.id) if more_points: try: @@ -897,6 +942,7 @@ def smart_throttle(self, requests=1): except (TypeError, KeyError): return False + async def spin_pokestop(self, pokestop): self.error_code = '$' pokestop_location = pokestop.latitude, pokestop.longitude @@ -1257,13 +1303,34 @@ def normalize_lured(raw, now): def normalize_gym(raw): return { 'type': 'fort', - 'external_id': raw.id, - 'lat': raw.latitude, - 'lon': raw.longitude, - 'team': raw.owned_by_team, - 'prestige': raw.gym_points, - 'guard_pokemon_id': raw.guard_pokemon_id, - 'last_modified': raw.last_modified_timestamp_ms // 1000, + 'external_id': raw['external_id'], + 'name': raw['name'], + 'lat': raw['lat'], + 'lon': raw['lon'], + 'team': raw['team'], + 'guard_pokemon_id': raw['guard_pokemon_id'], + 'last_modified': raw['last_modified'], + 'is_in_battle': raw['is_in_battle'], + 'slots_available': raw['slots_available'], + 'time_ocuppied': raw['time_ocuppied'] + } + + @staticmethod + def normalize_gym_member(raw): + return { + 'type': 'fort_member', + 'external_id' : raw['external_id'], + 'player_name' : raw['player_name'], + 'player_level' : raw['player_level'], + 'pokemon_id' : raw['pokemon_id'], + 'pokemon_cp' : raw['pokemon_cp'], + 'move_1' : raw['move_1'], + 'move_2' : raw['move_2'], + 'individual_attack' : raw['individual_attack'], + 'individual_defense' : raw['individual_defense'], + 'individual_stamina' : raw['individual_stamina'], + 'time_deploy' : raw['time_deploy'], + 'last_modified' : raw['last_modified'] } @staticmethod