class Thread(GameEvent): forum_id = db.Column(db.Integer, db.ForeignKey('forum.id'), nullable=False) posts = db.relationship('Post', backref='thread') title = db.Column(db.String(32)) author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) author = db.relationship("User") def __init__(self, forum_id, title, author_id): self.forum_id = forum_id self.title = title self.author_id = author_id def get_post_count(self): return len(self.posts) def get_most_recent_post(self): return Post.query.filter_by(thread_id=self.id).order_by( desc('time_created')).first() def get_author(self): return self.author.username def get_votes(self): """Return sum of all votes on all posts.""" return sum([ Upvote.query.filter_by(post_id=post.id, vote=1).count() for post in self.posts ]) def get_views(self): """Return sum of all views on all posts.""" raise NotImplementedError("We currently don't have this feature.")
def clan_addon(user_cls, clan_cls, kingdom_cls): """Modify User so as to add a relationship to the clan class. Note: user.clan might be None even though clan.user would be a user. This occurs when clan status is anything other than "Member". """ user_cls.clan = db.relationship( "Clan", primaryjoin=( "and_(" "User.id==Clan.user_id, " "Clan.status=='Member'" ")" ), uselist=False) clan_cls.user = db.relationship("User") def get_user_by_status(self, option): """Return a list of users based on membership status. This should be a join query of some kind. """ return ( user_cls .query .join(clan_cls) .filter(clan_cls.kingdom_id==self.kingdom_id, clan_cls.status==option) .all() ) clan_cls.get_user_by_status = get_user_by_status clan_cls.kingdom = db.relationship("Kingdom")
class Post(GameEvent): thread_id = db.Column(db.Integer, db.ForeignKey('thread.id'), nullable=False) parent_post_id = db.Column(db.Integer) # 0 if this is the parent title = db.Column(db.String(32)) content = db.Column(db.String(5000)) author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) votes = db.Column(db.Integer) author = db.relationship("User") def __init__(self, thread_id, author_id, title, content, parent_post_id): self.thread_id = thread_id self.author_id = author_id self.title = title self.content = content self.parent_post_id = parent_post_id self.votes = 0 def get_reply_count(self): replies = Post.query.filter_by(parent_post_id=self.id).all() return len(replies) def get_replies(self): return Post.query.filter_by(parent_post_id=self.id).all() def get_most_recent_reply(self): post = Post.query.filter_by(parent_post_id=self.id).order_by( desc('time_created')).first() if post is None: return self return post def get_author(self): return self.author.username def get_votes(self): return Upvote.query.filter_by(post_id=self.id, vote=1).count() def get_vote_status(self, user_id): """Return 1 for voted and 0 for not voted. If no vote exists then vote is 0. This uses integers rather than booleans because it makes math easier. """ vote = Upvote.query.filter_by(post_id=self.id, user_id=user_id).first() try: return vote.vote except AttributeError: return 0
def casting_addon(cls): """Modify County so as to add a relationship to the casting class. Casting.query.filter_by(target_id=current_user.county.id).filter((Casting.duration > 0) | (Casting.active==True)).all() elif target_county.kingdom in current_user.county.kingdom.enemies: targets = 'hostile' """ cls.active_enemy_spells = db.relationship( 'Casting', primaryjoin=("and_(" "County.id==casting.c.target_id, " f"{active_condition}, " "casting.c.target_relation=='hostile'" ")"))
class Forum(GameEvent): threads = db.relationship('Thread', backref='forum') def __init__(self): pass
class World(GameState): kingdoms = db.relationship('Kingdom', backref='world') age = db.Column(db.Integer) # How many 'reset events' day = db.Column(db.Integer) # How many in-game days have passed this age season = db.Column(db.String(16)) # The current season def __init__(self): self.age = 1 self.day = 0 self.season = seasons[0] def advance_day(self): if self.day >= 0: for county in County.query.all(): if county.user.is_bot: county.temporary_bot_tweaks() else: county.advance_day() for kingdom in Kingdom.query.all(): kingdom.advance_day() self.day += 1 if self.day % 36 == 0: # Every 36 game days we advance the game season season_index = seasons.index(self.season) + 1 if season_index == len(seasons): season_index = 0 self.season = seasons[season_index] def advance_analytics(self): if self.day < 0: return users = User.query.filter_by(is_bot=False).filter( User.county != None).all() for user in users: # First check and set their retention user_age = (datetime.utcnow() - user.time_created).days if user.get_last_logout() and user.get_last_logout().date( ) == datetime.today().date(): retention = 1 else: retention = 0 user.day1_retention = 1 if user_age == 1: user.day1_retention = retention elif user_age == 3: user.day3_retention = retention elif user_age == 7: user.day7_retention = retention # If they are playing this age, create a DAU for them if user.county: dau_event = DAU(user.id) dau_event.save() self.export_data_to_csv() def advance_age(self): kingdoms = Kingdom.query.all() counties = County.query.all() users = User.query.all() for user in users: if user.county: user.ages_completed += 1 for kingdom in kingdoms: kingdom.leader = 0 kingdom.wars_total_ta = 0 kingdom.wars_won_ta = 0 kingdom.approval_rating = Kingdom.BASE_APPROVAL_RATING kingdom.save() winning_kingdoms = [ sorted(kingdoms, key=lambda x: x.wars_won_ta, reverse=True)[0], sorted(kingdoms, key=lambda x: x.total_land_of_top_three_counties, reverse=True)[0] ] winning_county = sorted(counties, key=lambda x: x.land, reverse=True)[0] for kingdom in winning_kingdoms: for county in kingdom.counties: county.user.gems += 1 winning_county.user.gems += 1 tables = [ 'DAU', 'army', 'building', 'casting', 'chatroom', 'diplomacy', 'economy', 'espionage', 'expedition', 'infiltration', 'infrastructure', 'magic', 'message', 'military', 'notification', 'preferences', 'scientist', 'session', 'technology_to_technology', 'technology', 'trade', 'transaction', 'wizardry', 'county' ] table_mixers.drop_then_rebuild_tables(db, tables) self.age += 1 self.day = -24 def export_data_to_csv(self): all_tables = [] table_name_reference = [] tables = db.metadata.tables table_names = db.engine.table_names() for name in table_names: # Each table is a list inside the list new_table = [] table_name_reference.append(name) if name not in {}: # Each row will be a list inside the table list, inside the all_tables list table = tables[name] header_row = [] for column in table.columns: header_row.append(column.name) new_table.append(header_row) for row in db.session.query(table).all(): normal_row = [] for value in row: normal_row.append(value) new_table.append(normal_row) all_tables.append(new_table) # We have a list of smaller lists. Each smaller list should be a csv file (each one is a separate sql table) current_path = f"export/age-{self.age}" if not os.path.exists(current_path): os.makedirs(current_path) for index, table in enumerate(all_tables): if len(table) < 2: continue headers = table.pop(0) name = table_name_reference[index] filename = f"{current_path}/{name}_table.csv" df = DataFrame(table) df.to_csv(filename, header=headers) def __repr__(self): return '<World %r (%r)>' % ('id:', self.id)