class User(UserMixin, db.Model): id = db.Column(db.Integer(), primary_key=True) email = db.Column(db.String(64), unique=True, index=True) location = db.Column(db.String(64)) about_me = db.Column(db.Text()) member_since = db.Column(db.DateTime(), default=datetime.utcnow) last_seen = db.Column(db.DateTime(), default=datetime.utcnow) name = db.Column(db.String(64), unique=True) username = db.Column(db.String(255)) password = db.Column(db.String(255)) birthday = db.Column(db.Date()) posts = db.relationship('Post', backref='user', lazy='dynamic') headimg = db.Column(db.String(128), default=None) comments = db.relationship('Comment', backref='user', lazy='dynamic') messagesboard = db.relationship('Messageboard', backref='user', lazy='dynamic') myphotos = db.relationship('Photos', backref='user', lazy='dynamic') def __repr__(self): return "<User '{}'>".format(self.username) def set_password(self, password): self.password = bcrypt.generate_password_hash(password) def check_password(self, password): return bcrypt.check_password_hash(self.password, password) def ping(self): self.last_seen = datetime.utcnow() db.session.add(self) db.session.commit()
class Course(db.Model): __tablename__ = 'course' code = db.Column(db.String(7), primary_key=True) title = db.Column(db.String(80), nullable=False) credits = db.Column(db.Integer, nullable=False) # many -to many with Users users = db.relationship('User', secondary=course_list, lazy='subquery', backref=db.backref('courses', lazy=True)) sessions = db.relationship('Session', back_populates='course') def __repr__(self): return f'Course<code={self.code}, title={self.title}, credits={self.credits}>' def save(self): db.session.add(self) db.session.commit() @classmethod def get_courses(cls): res = cls.query.all() return res @classmethod def find_by_id(cls, code): course = cls.query.filter(cls.code == code).first() return course
class QuestItem(db.Model, DroppedByMixin): __tablename__ = "quest_item" _mapper_utils = { "files": { "server": ["s_QuestItem.bin"], "client": ["c_QuestItemRes.bin"], "string": ["QuestItemStr.dat"], }, } index = db.Column(db.Integer, nullable=False) code = CustomColumn(db.String(32), primary_key=True, nullable=False, mapper_key="코드") name = CustomColumn(db.String(256), nullable=False, mapper_key="_name") icon = CustomColumn(db.String(32), nullable=False, mapper_key="_icon") stack_size = CustomColumn(db.Integer, nullable=False, mapper_key="중복가능수") quest_missions = db.relationship( "QuestMission", primaryjoin="foreign(QuestMission.quest_item_code) == QuestItem.code", ) quest_give_items = db.relationship( "QuestGiveItem", primaryjoin="foreign(QuestGiveItem.item_code) == QuestItem.code", ) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = { "code": self.code, "name": self.name, "icon": self.icon, } if minimal: return minimal_dict quest_objectives = self.quest_missions + self.quest_give_items return { **minimal_dict, "stack_size": self.stack_size, "quests": [ quest_objective.quest.to_dict(minimal=True) for quest_objective in quest_objectives ], **DroppedByMixin.to_dict(self), }
class MapPoint(db.Model): __tablename__ = "map_point" index = db.Column(db.Integer, primary_key=True, autoincrement=True) map_code = db.Column(db.String(32), db.ForeignKey("map.code"), nullable=False) map = db.relationship("Map", foreign_keys=[map_code]) monster_code = db.Column(db.String(32), db.ForeignKey("monster.code"), nullable=False) monster = db.relationship("Monster", foreign_keys=[monster_code]) x = db.Column(db.Integer, nullable=False) y = db.Column(db.Integer, nullable=False) z = db.Column(db.Integer, nullable=False) def to_dict( self, monster_dict: bool = False, map_dict: bool = False, ) -> dict: if monster_dict: return { "monster": self.monster.to_dict(minimal=True), "pos": { "x": self.x, "y": self.y, "z": self.z, }, } elif map_dict: return { "map": self.map.to_dict(minimal=True), "pos": { "x": self.x, "y": self.y, "z": self.z, }, } return { "map": self.map.to_dict(minimal=True), "monster": self.monster.to_dict(minimal=True), "pos": { "x": self.x, "y": self.y, "z": self.z, }, }
class Post(db.Model): id = db.Column(db.Integer(),primary_key=True) title = db.Column(db.String(255)) text = db.Column(db.Text()) publish_date = db.Column(db.DateTime()) user_id = db.Column(db.Integer(),db.ForeignKey('user.id')) comments = db.relationship('Comment',backref = 'post',lazy = 'dynamic') tags=db.relationship( 'Tag',secondary =tags,backref = db.backref('posts',lazy='dynamic') ) def __init__(self,title): self.title = title def __repr__(self): return "<Post '{}'>".format(self.title)
class Blog(db.Model): __tablename__ = 'blogs' __searchable__ = ['title', 'content'] __analyzer__ = ChineseAnalyzer() id = db.Column(db.Integer, primary_key=True) time = db.Column(db.BigInteger) author = db.Column(db.String(255)) title = db.Column(db.String(255), unique=True) content = db.Column(LONGTEXT) comments = db.relationship('Comment', backref='blogs', lazy='dynamic') tags = db.relationship('Tag', secondary=tags, backref=db.backref('blogs', lazy='dynamic')) def __init__(self, author, title, content): self.author = author self.title = title self.content = content def __repr__(self): return "<Blog '{}'>".format(self.title) def save(self): db.session.add(self) db.session.commit() def delete(self): db.session.delete(self) db.session.commit() def to_dict(self): """Transforms a model into a dictionary which can be dumped to JSON.""" # first we get the names of all the columns on your model columns = [c.key for c in class_mapper(self.__class__).columns] # then we return their values in a dict return dict((c, getattr(self, c)) for c in columns) # 返回除了 content, comments 之外的值 @staticmethod def query_title(): sql_str = ''' SELECT blogs.id, blogs.time, blogs.author, blogs.title, group_concat(tags.title) tag FROM blogs LEFT JOIN blog_tags ON blogs.id=blog_tags.blog_id left join tags ON tags.id=blog_tags.tag_id group by blogs.id; ''' ret = db.engine.execute(sql_str).fetchall() return [dict(r) for r in ret]
class PetSkillStone( db.Model, BaseMixin, DroppedByMixin, RandomBoxMixin, ): __tablename__ = "pet_skill_stone" _mapper_utils = { "files": { "server": ["s_PetSkillStoneItem.bin"], "client": ["c_PetSkillStoneItemRes.bin"], "string": ["PetSkillStoneItemStr.dat"], } } skill_code = CustomColumn(db.String(32), db.ForeignKey("pet_skill.code"), nullable=False, mapper_key="대상코드") skill_data = db.relationship("PetSkill", foreign_keys=[skill_code]) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = BaseMixin.to_dict(self, minimal) if minimal: return minimal_dict return { **minimal_dict, "skill": self.skill_data.to_dict(), **DroppedByMixin.to_dict(self), **RandomBoxMixin.to_dict(self), }
class Article(db.Model): __tablename__ = 'article' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(80), nullable=False) author = db.Column(db.String(80)) full_text = db.Column(TEXT, nullable=False) link = db.Column(db.String(250), nullable=False) sessions = db.relationship('Session', secondary=session_articles, lazy='subquery', backref=db.backref('articles', lazy=True)) # many to many def __repr__(self): return f'Article<id={self.id}, title={self.title}, author={self.author}>' def save(self): db.session.add(self) db.session.commit() @classmethod def find_by_id(cls, article_id): return cls.query.filter(cls.id == article_id).first() @classmethod def get_articles(cls): return cls.query.all()
class ProductBook(db.Model, BaseMixin, SoldByMixin): __tablename__ = "product_book" _mapper_utils = { "files": { "server": ["s_ProductBook.bin"], "client": ["c_ProductRes.bin"], "string": ["ProductStr.dat"], }, } production_code = CustomColumn(db.String(32), db.ForeignKey("production.code"), nullable=False, mapper_key="대상코드") production = db.relationship("Production", foreign_keys=[production_code], uselist=False) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = BaseMixin.to_dict(self, minimal) if minimal: return minimal_dict return { **minimal_dict, "production": self.production.to_dict(minimal=True), **SoldByMixin.to_dict(self), }
class Map(db.Model): __tablename__ = "map" _mapper_utils = { "files": { "string": ["AreaStr.dat"], }, } code = db.Column(db.String(32), primary_key=True, nullable=False) name = db.Column(db.String(128), nullable=False) left = CustomColumn(db.Float) top = CustomColumn(db.Float) width = CustomColumn(db.Float) height = CustomColumn(db.Float) map_points = db.relationship( "MapPoint", primaryjoin="foreign(MapPoint.map_code) == Map.code") def _parse_row(row: dict) -> "Map": code = row["Code"] lwth = MAP_CODE_TO_LTWH.get(code, None) if lwth is None: # Not a "real" map but rather island or an area # which only have a name and code return {"code": code, "name": row[LANGUAGE]} l, t, w, h = [float(num) for num in lwth.split(",")] return { "code": code, "name": row[LANGUAGE], "left": l, "top": t, "width": w, "height": h, } def to_dict(self, minimal: bool = False) -> dict: minimal_dict = { "code": self.code, "name": self.name, "left": self.left, "top": self.top, "width": self.width, "height": self.height, } if minimal: return minimal_dict return { **minimal_dict, "points": [point.to_dict(monster_dict=True) for point in self.map_points] }
class Post(db.Model): id = db.Column(db.Integer(), primary_key=True) title = db.Column(db.String(255)) subtitle = db.Column(db.String(255)) text = db.Column(db.Text()) publish_date = db.Column(db.DateTime()) private = db.Column(db.Boolean()) user_id = db.Column(db.Integer(), db.ForeignKey('user.id')) comments = db.relationship('Comment', backref='post', lazy='dynamic') body_html = db.Column(db.Text()) tags = db.relationship('Tag', secondary=tags, backref=db.backref('posts', lazy='dynamic')) ''' @staticmethod def on_changed_body(target,value,oldvalue,intitiator): allowed_tag = ['a','abbr','acronym','b','blockquote','code','div','em','i','li','ol','pre','strong','table','thead','tbody','tr','th','ul','h1','h2','h3','h4','h5','h6','p',] target.body_html = bleach.linkify(bleach.clean(markdown(value,output_html = 'html'),tags=allowed_tag,strip=True)) ''' #处理body字段变化的函数 @staticmethod def on_changed_post(target, value, oldvalue, initiaor): allow_tags = [ 'a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 'h1', 'h2', 'h3', 'p', 'img' ] #转换markdown为html,并清洗html标签 target.body_html = bleach.linkify( bleach.clean( markdown(value, output_form='html', extensions=['extra', 'codehilite']), tags=allow_tags, strip=True, attributes={ '*': ['class'], 'a': ['href', 'rel'], 'img': ['src', 'alt'], #支持<img src …>标签和属性 })) def __repr__(self): return "<Post '{}'>".format(self.title)
class Session(db.Model): __tablename__ = 'session' id = db.Column(db.Integer, primary_key=True) start_time = db.Column(db.DateTime, server_default=func.now(), nullable=False) duration_s = db.Column(db.Integer, nullable=False) #? 1 course - Many sessions course_code = db.Column(db.String(7), db.ForeignKey('course.code')) course = db.relationship('Course', back_populates='sessions') #? 1 user - Many study blocks user_id = db.Column(db.Integer, db.ForeignKey('user.id')) user = db.relationship('User', back_populates='sessions') db.UniqueConstraint(start_time, user_id) def __repr__(self): return f"Session<id={self.id}, start={self.start_time}, duration={self.duration_s}, course_code={self.course_code}, user={self.user_id}>" def save(self): db.session.add(self) db.session.commit() def add_article(self, article): self.articles.append(article) self.save() def remove_article(self, article_id): article = Article.find_by_id(article_id) self.articles.remove(article) self.save() @classmethod def find_by_id(cls, session_id): return cls.query.filter(cls.id == session_id).first() @classmethod def find_course_sessions(cls, user_id, course_code): return cls.query.filter(cls.user_id == user_id).filter( cls.course_code == course_code).all()
class QuestMission(db.Model): __tablename__ = "quest_mission" index = db.Column(db.Integer, primary_key=True, autoincrement=True) work_type = db.Column(db.Enum(QuestWorkType), nullable=False) work_value = db.Column(db.String(32)) quest_code = db.Column(db.String(32), db.ForeignKey("quest.code"), nullable=False) quest = db.relationship("Quest", foreign_keys=[quest_code]) map_code = db.Column(db.String(32), db.ForeignKey("map.code")) map = db.relationship("Map", foreign_keys=[map_code], uselist=False) x = db.Column(db.Float) y = db.Column(db.Float) count = db.Column(db.Integer, nullable=False) npc_code = db.Column(db.String(32), db.ForeignKey("npc.code")) npc = db.relationship("Npc", foreign_keys=[npc_code], uselist=False) item_code = db.Column(db.String(32), db.ForeignKey("item_list.code")) item = db.relationship("ItemList", foreign_keys=[item_code], uselist=False) monster_code = db.Column(db.String(32), db.ForeignKey("monster.code")) monster = db.relationship("Monster", foreign_keys=[monster_code], uselist=False) quest_item_code = db.Column(db.String(32), db.ForeignKey("quest_item.code")) quest_item = db.relationship("QuestItem", foreign_keys=[quest_item_code], uselist=False) def to_dict(self) -> dict: return { "work_type": self.work_type.to_dict(), "work_value": self.work_value, "map": (self.map.to_dict(minimal=True) if self.map else None), "pos": { "x": self.x, "y": self.y, }, "count": self.count, "npc": self.npc.to_dict(minimal=True) if self.npc else None, "item": self.item.to_dict() if self.item else None, "monster": (self.monster.to_dict(minimal=True) if self.monster else None), "quest_item": (self.quest_item.to_dict( minimal=True) if self.quest_item else None) }
class QuestSelectableItem(db.Model): __tablename__ = "quest_selectable_item" index = db.Column(db.Integer, primary_key=True, autoincrement=True) quest_code = db.Column(db.String(32), db.ForeignKey("quest.code"), nullable=False) quest = db.relationship("Quest", foreign_keys=[quest_code]) item_code = db.Column(db.String(32), db.ForeignKey("item_list.code"), nullable=False) item = db.relationship("ItemList", foreign_keys=[item_code], uselist=False) amount = db.Column(db.Integer, nullable=False) def to_dict(self) -> dict: return { "item": self.item.to_dict(), "amount": self.amount, }
class Drop(db.Model): __tablename__ = "drop" index = db.Column(db.Integer, primary_key=True, autoincrement=True) quantity = db.Column(db.Integer, nullable=False, default=1) monster_code = db.Column(db.String(32), db.ForeignKey("monster.code"), nullable=False) monster = db.relationship("Monster", foreign_keys=[monster_code]) item_code = db.Column(db.String(32), db.ForeignKey("item_list.code"), nullable=False) item = db.relationship("ItemList", foreign_keys=[item_code]) def to_dict( self, item_dict: bool = False, monster_dict: bool = False ) -> dict: if item_dict: return { "item": self.item.to_dict(with_item_data=True), "quantity": self.quantity, } elif monster_dict: return { "monster": self.monster.to_dict(minimal=True), "quantity": self.quantity, }
class User(UserMixin,db.Model): id =db.Column(db.Integer(),primary_key = True) email = db.Column(db.String(64),unique = True,index = True) username = db.Column(db.String(255)) password = db.Column(db.String(255)) posts = db.relationship('Post',backref = 'user',lazy = 'dynamic') def __repr__(self): return "<User '{}'>".format(self.username) def set_password (self,password): self.password = bcrypt.generate_password_hash(password) def check_password(self,password): return bcrypt.check_password_hash(self.password,password)
class ArticleRatings(db.Model): __tablename__ = 'article_ratings' user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) user = db.relationship('User', back_populates='article_ratings') article_id = db.Column(db.Integer, db.ForeignKey('article.id'), primary_key=True) rating = db.Column(db.Integer, nullable=False) def __repr__(self): return f'Rating<user_id: {self.user_id}, article_id: {self.article_id}, rating: {self.rating}>' def remove(self): db.session.delete(self) db.session.commit() @classmethod def find_by_id(cls, user_id, article_id): return cls.query.filter(cls.user_id == user_id).filter( cls.article_id == article_id).first()
class SkillBook( db.Model, BaseMixin, SoldByMixin ): __tablename__ = "skill_book" _mapper_utils = { "files": { "server": [ "s_SkillBookItem.bin" ], "client": [ "c_SkillBookItemRes.bin" ], "string": [ "SkillBookItemStr.dat" ], }, } skill_code = CustomColumn( db.String(32), db.ForeignKey("player_skill.code"), nullable=False, mapper_key="대상코드") skill = db.relationship("PlayerSkill", foreign_keys=[skill_code], uselist=False) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = BaseMixin.to_dict(self, minimal) if minimal: return minimal_dict return { **minimal_dict, "skill": self.skill.to_dict() if self.skill else None, **SoldByMixin.to_dict(self), }
class QuestScroll( db.Model, BaseMixin, DroppedByMixin, SoldByMixin, ): __tablename__ = "quest_scroll" _mapper_utils = { "files": { "server": ["s_QuestScrollItem.bin"], "client": ["c_QuestScrollItemRes.bin"], "string": ["QuestScrollItemStr.dat"], }, } quest_code = CustomColumn(db.String(32), db.ForeignKey("quest.code"), nullable=False, mapper_key="대상코드") quest = db.relationship("Quest", foreign_keys=[quest_code], uselist=False) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = BaseMixin.to_dict(self, minimal) if minimal: return minimal_dict return { **minimal_dict, "quest": self.quest.to_dict(minimal=True) if self.quest else None, **SoldByMixin.to_dict(self), **DroppedByMixin.to_dict(self), }
class User(db.Model): __tablename__ = 'user' # Define attributes id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(150), nullable=False) firstname = db.Column(db.String(150), nullable=False) lastname = db.Column(db.String(150), nullable=False) password = db.Column(db.String(30), nullable=False) bio = db.Column(db.String(250), server_default='') # TODO: Add a table for year in school # year_in_school # course_of_study = db.Column(db.Integer, db.ForeignKey('course_of_study.id')) # course_of_study_id = db.Column(db.Integer, db.ForeignKey('Course_Of_Study.id')) # course_of_study = db.relationship('Course_Of_Study', back_populates='user') sessions = db.relationship('Session', back_populates='user', order_by='Session.start_time.desc()') article_ratings = db.relationship('ArticleRatings', back_populates='user') def __repr__(self): return f"User<id={self.id}, email={self.email}, firstname={self.firstname}, lastname={self.lastname}>" def save(self): # Save a user to a db db.session.add(self) db.session.commit() db.session.refresh(self) def verify_password(self, other_password): # TODO: Hash the passwords return self.password == other_password def get_courses(self): return self.courses def add_course(self, code): course = Course.find_by_id(code) self.courses.append(course) self.save() def remove_course(self, code): course = Course.find_by_id(code) self.courses.remove(course) self.save() def get_sessions(self, course_code=None): if not course_code: return self.sessions return Session.find_course_sessions(self.id, course_code) def get_articles(self): return self.article_ratings def add_rating(self, article_id, rating): article_rating = ArticleRatings(user_id=self.id, article_id=article_id, rating=rating) self.article_ratings.append(article_rating) self.save() def remove_rating(self, article_id): article_rating = ArticleRatings.find_by_id(self.id, article_id) print(article_rating) article_rating.remove() # self.article_ratings.remove(article_rating) # self.save() @classmethod def find_by_email(cls, email): if not email: return None res = User.query.filter(cls.email == email).first() return res @classmethod def find_by_id(cls, id): if not id: return None try: res = User.query.filter(cls.id == id).first() except: return None return res @classmethod def get_users(cls, limit=15): res = cls.query.limit(limit).all() return res @classmethod def remove_by_id(cls, user_id): cls.query.filter(cls.id == user_id).delete() db.session.commit()
class JournalEntry(db.Model): """Model for journal entries.""" id = db.Column(db.Integer, primary_key=True) create_date = db.Column(db.Date, default=func.now(), index=True) updated_at = db.Column(db.DateTime, default=func.now(), onupdate=func.now(), nullable=False, server_default=func.now()) contents = db.Column(db.String) owner_id = db.Column(db.Integer, db.ForeignKey(User.id, ondelete="cascade"), index=True) owner = db.relationship( User, backref=backref('entries', cascade="all,delete"), ) __table_args__ = (db.UniqueConstraint('owner_id', 'create_date', name='_id_date'), ) def __str__(self): return repr(self.id) def __repr__(self): return f'< JournaEntry id={self.id} create_date={self.create_date}' @property def html(self) -> str: """Return HTML rendering of markdown contents.""" return markdown.markdown(self.contents) @property def date_string(self) -> str: """Date as YYYY-MM-DD.""" return self.create_date.strftime('%Y-%m-%d') @property def date_human(self) -> str: """A pretty and human readable date.""" return self.create_date.strftime('%B %d, %Y, a %A') @property def next(self): found = JournalEntry.query.filter( JournalEntry.owner_id == self.owner_id).order_by( JournalEntry.create_date).filter( JournalEntry.create_date > self.create_date).first() if found: if found.id != self.id: return found return None @property def previous(self): found = JournalEntry.query.filter( JournalEntry.owner_id == self.owner_id).filter( JournalEntry.create_date < self.create_date).order_by( JournalEntry.create_date.desc()).first() if found: if found.id != self.id: return found return None
class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(100), unique=True, index=True) password = db.Column(db.String(200)) email = db.Column(db.String(200), unique=True, index=True) registered_on = db.Column(db.DateTime, default=datetime.datetime.utcnow) first_name = db.Column(db.String(200)) last_name = db.Column(db.String(200)) active = db.Column(db.Boolean()) confirmed_at = db.Column(db.DateTime()) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) # ========== flask-login methods ========== @property def is_authenticated(self): return True @property def is_active(self): return True @property def is_anonymous(self): return False def get_id(self): return self.id def get_latest_entry(self, ) -> "JournalEntry": """Return the chronologically latest JournalEntry.""" sess = db.session.object_session(self) if sess is None: try: db.session.add(self) except sqlalchemy.exc.InvalidRequestError: pass return db.session.query(JournalEntry).filter( JournalEntry.owner_id == self.id).order_by( JournalEntry.create_date.desc()).first() def query_all_entries(self): return JournalEntry.query.filter(JournalEntry.owner_id == self.id) def get_all_years(self, ) -> 'iterable[datetime.datetime]': """Return a list of dates corresponding to the range of years encompassed by all journal entries.""" # define earliest and latest years of entries start_year = self.query_all_entries().order_by( JournalEntry.create_date).first() end_year = self.query_all_entries().order_by( JournalEntry.create_date.desc()).first() if start_year and end_year: for y in range(start_year.create_date.year, end_year.create_date.year + 1): # find any entry within this year but before next year found = self.query_all_entries().filter( JournalEntry.create_date >= datetime.datetime( y, 1, 1, 0, 0)).filter( JournalEntry.create_date < datetime.datetime( y + 1, 1, 1, 0, 0)).first() # only yield this year if has an entry if found: yield datetime.datetime(y, 1, 1, 0, 0) def next_entry(self, e: "JournalEntry") -> "JournalEntry": """Return the first JournalEntry that falls chronologically after the given entry.""" return self.query_all_entries().filter( JournalEntry.create_date > e.create_date).first() def previous_entry(self, e: "JournalEntry") -> "JournalEntry": """Return the first JournalEntry that falls chronologically before the given entry.""" return self.query_all_entries().filter( JournalEntry.create_date < e.create_date).order_by( JournalEntry.create_date.desc()).first()
class Npc(db.Model): __tablename__ = "npc" _mapper_utils = { "files": { "server": [ "s_MerchantChar.bin", "s_GuardChar.bin", "s_CitizenChar.bin" ], "client": [ "c_MerchantCharRes.bin", "c_GuardCharRes.bin", "c_CitizenCharRes.bin" ], "string": [ "MerchantCharStr.dat", "GuardCharStr.dat", "CitizenCharStr.dat" ], }, "options": { "image_key": "모델명" } } index = db.Column(db.Integer, nullable=False) code = CustomColumn(db.String(32), primary_key=True, nullable=False, mapper_key="코드") name = CustomColumn(db.String(128), nullable=False, mapper_key="_name") icon = CustomColumn(db.String(128), nullable=False, mapper_key="_icon") level = CustomColumn(db.Integer, nullable=False, mapper_key="기준레벨") shop_items = db.relationship( "NpcShopItem", primaryjoin="foreign(NpcShopItem.npc_code) == Npc.code" ) quests = db.relationship( "Quest", primaryjoin="foreign(Quest.start_npc_code) == Npc.code" ) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = { "code": self.code, "name": self.name, "icon": self.icon, "level": self.level, } if minimal: return minimal_dict return { **minimal_dict, "shop_items": [shop_item.to_dict(item_dict=True) for shop_item in self.shop_items # Some NPCs sell items that do no longer exist # or are not included in the database (like # commerce goods), so those will be filtered # out for now to prevent errors. if shop_item.item], "quests": [quest.to_dict(minimal=True) for quest in self.quests], }
class Monster(db.Model): __tablename__ = "monster" _mapper_utils = { "files": { "server": ["s_MonsterChar.bin"], "client": ["c_MonsterCharRes.bin"], "string": ["MonsterCharStr.dat"], }, "options": { "image_key": "모델명" }, } index = db.Column(db.Integer, nullable=False) code = CustomColumn(db.String(32), primary_key=True, mapper_key="코드") name = CustomColumn(db.String(256), nullable=False, mapper_key="_name") icon = CustomColumn(db.String(32), nullable=False, mapper_key="_icon") rating_type = CustomColumn(db.Enum(RatingType), nullable=False, mapper_key="몬스터등급타입", transform=lambda val: RatingType(val)) level = CustomColumn(db.Integer, nullable=False, mapper_key="기준레벨") hp = CustomColumn(db.Integer, nullable=False, mapper_key="기준최대HP") range = CustomColumn(db.Enum(MonsterRange), nullable=False, mapper_key="공격거리타입", transform=lambda val: MonsterRange(val)) area = CustomColumn(db.Enum(Area), nullable=False, mapper_key="필드구분", transform=lambda val: Area(val)) experience = CustomColumn(db.Integer, nullable=False, mapper_key="보상경험치") minimal_damage = CustomColumn(db.Integer, nullable=False, mapper_key="최소물공력") maximal_damage = CustomColumn(db.Integer, nullable=False, mapper_key="최대물공력") physical_defense = CustomColumn(db.Integer, nullable=False, mapper_key="물방력") magic_defense = CustomColumn(db.Integer, nullable=False, mapper_key="마항력") attack_range = CustomColumn(db.Float, nullable=False, mapper_key="기본사정거리", transform=florensia_meter_transform) tameable = CustomColumn(db.Boolean, mapper_key="테이밍", nullable=False) drops = db.relationship( "Drop", primaryjoin="foreign(Drop.monster_code) == Monster.code") map_points = db.relationship( "MapPoint", primaryjoin="foreign(MapPoint.monster_code) == Monster.code") quest_missions = db.relationship( "QuestMission", primaryjoin="foreign(QuestMission.monster_code) == Monster.code") vision_range = CustomColumn(db.Float, nullable=False, mapper_key="선공시야", transform=florensia_meter_transform) # If you perform an action close to the range # attack vision range of the monster, you will # also get aggro attack_vision_range = CustomColumn(db.Float, nullable=False, mapper_key="요청시야", transform=florensia_meter_transform) messages_code = CustomColumn(db.String(32), mapper_key="오브젝트채팅", transform=lambda v: v if v != "#" else None) monster_message = db.relationship("MonsterMessage", uselist=False) # Skill 1 skill_1_code = CustomColumn(db.String(32), db.ForeignKey("monster_skill.code"), mapper_key="부가Action1코드", transform=lambda v: v if v != "#" else None) skill_1_chance = CustomColumn(db.Float, mapper_key="부가Action1선택율", transform=florensia_probability_transform) skill_1 = db.relationship("MonsterSkill", foreign_keys=[skill_1_code]) # Skill 2 skill_2_code = CustomColumn(db.String(32), db.ForeignKey("monster_skill.code"), mapper_key="부가Action2코드", transform=lambda v: v if v != "#" else None) skill_2_chance = CustomColumn(db.Float, mapper_key="부가Action2선택율", transform=florensia_probability_transform) skill_2 = db.relationship("MonsterSkill", foreign_keys=[skill_2_code]) def to_dict(self, minimal: bool = False) -> dict: minimal_dict = { "code": self.code, "name": self.name, "icon": self.icon, "rating": self.rating_type.to_dict(), "level": self.level, "area": self.area.to_dict(), } if minimal: return minimal_dict # Get monster skills as a list skills = [] for i in range(1, 3): skill = getattr(self, f"skill_{i}") if skill: skill_dict = skill.to_dict() skill_dict["chance"] = getattr(self, f"skill_{i}_chance") skills.append(skill_dict) return { **minimal_dict, "hp": self.hp, "range": self.range.to_dict(), "experience": self.experience, "minimal_damage": self.minimal_damage, "maximal_damage": self.maximal_damage, "physical_defense": self.physical_defense, "magic_defense": self.magic_defense, "attack_range": self.attack_range, "tamable": self.tameable, "vision_range": self.vision_range, "attack_vision_range": self.attack_vision_range, "messages": (self.monster_message.to_dict() if self.monster_message else None), "skills": skills, "map_points": [point.to_dict(map_dict=True) for point in self.map_points], "drops": [drop.to_dict(item_dict=True) for drop in self.drops], "quests": [ mission.quest.to_dict(minimal=True) for mission in self.quest_missions ] }
# Link seal option to table. Used to reference the table later. # This is done in the update_database.py loop. seal_option_type = CustomColumn(db.Enum(SealOptionType), nullable=False, mapper_key="_seal_option_type") # Add columns with data dynamically for i in range(0, 63): # Option code setattr( SealOption, f"option_{i}_code", CustomColumn(db.String(32), db.ForeignKey("seal_option_data.code"), mapper_key=f"옵션코드{i}")) # Option probability setattr( SealOption, f"option_{i}_chance", CustomColumn(db.Float, mapper_key=f"확률{i}", transform=(lambda v: florensia_probability_transform(v) if v != 0 else None))) # Option relationship setattr( SealOption, f"option_{i}", db.relationship("SealOptionData", foreign_keys=[getattr(SealOption, f"option_{i}_code")]))
class User(db.Model, UserMixin): id = db.Column(db.Integer(), primary_key=True) username = db.Column(db.String(20), unique=True) bio = db.Column(db.String(100)) gender = db.Column(db.SmallInteger(), default=0) # 1 男 2 女 0 未填写 email = db.Column(db.String(50), unique=True, index=True) password = db.Column(db.String(255)) reg_date = db.Column(db.TIMESTAMP(), server_default=func.now()) last_login_date = db.Column(db.DateTime()) wb_uid = db.Column(db.String(20)) avatar = db.Column(db.String(500)) tasks = db.relationship('Task', backref='user', lazy='dynamic') comments = db.relationship('Comment', backref='user', lazy='dynamic') following = db.relationship('User', secondary=follows, primaryjoin=(follows.c.user_id == id), secondaryjoin=(follows.c.follow_id == id), backref=db.backref('follower', lazy='dynamic'), lazy='dynamic') liked = db.relationship('Likes', backref='user', lazy='dynamic') def __init__(self, username): self.username = username def __repr__(self): return '<User: {}>'.format(self.username) # 检查是否关注 def check_following(self, user_id): if User.query.get(user_id) in self.following.all(): return True # 互相关注的好友 def friends(self): return list(set(self.following.all()) & set(self.follower.all())) # 添加关注 def add_following(self, user_id): self.following.append(User.query.get(user_id)) db.session.add(self) db.session.commit() # 取消关注 def cancel_following(self, user_id): self.following.remove(User.query.get(user_id)) db.session.add(self) db.session.commit() def set_password(self, password): self.password = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password, password) def count_task(self): return '创建了{}个任务,完成了{}个'.format( len(self.tasks.all()), len(self.tasks.filter_by(status=1).all())) def unfinish_task(self): return len(self.tasks.all()) - len( self.tasks.filter_by(status=1).all()) # 从微博注册用户 def wb_reg(self, wb_uid): if not User.query.filter_by(wb_uid=wb_uid).first(): self.wb_uid = wb_uid # 查询当前登录用户关注的人中是否有人关注了页面显示的用户 def relation(self): if current_user.username != self.username: return list( set(current_user.following.all()) & set(self.follower.all())) def gender_text(self): return '他' if self.gender else '她' # 取用户头像,为空则取默认头像 def get_avatar(self): if self.avatar: return '/static/images/' + self.avatar else: if self.gender == 0: return '/static/images/0.png' else: return '/static/images/1.png' # 圈子内容 def circle_task(self): query_1 = and_( Task.user_id.in_([user.id for user in self.following.all()]), Task.public_level == '3') if self.following.all() else None # 关注的 query_2 = and_(Task.user_id.in_([ user.id for user in self.friends() ]), Task.public_level == '2') if self.friends() else None # 互相关注的 return Task.query.filter(or_(Task.user_id == self.id, query_1, query_2)).order_by( Task.create_time.desc()).all()
class Task(db.Model): id = db.Column(db.Integer(), primary_key=True) user_id = db.Column(db.Integer(), db.ForeignKey('user.id'), nullable=False, index=True) title = db.Column(db.String(100)) text = db.Column(db.Text()) create_time = db.Column(db.TIMESTAMP(), server_default=func.now()) update_time = db.Column(db.DateTime(), onupdate=func.now()) done_time = db.Column(db.DateTime()) deadline = db.Column(db.DateTime(), nullable=False) status = db.Column(db.SmallInteger(), default=0) # 0:进行中 1:已完成 2:暂停 9:删除 public_level = db.Column(db.SmallInteger(), default=3, index=True) # 1:仅自己可见 2:我关注的人可见 3:所有人可见 overtime = db.Column(db.Boolean, default=0) # 任务结束后: 0:未超时 1:超时 comment_allowed = db.Column(db.Boolean, default=1) # 0:禁止评论并隐藏所有评论内容 1:允许评论 comments = db.relationship('Comment', backref='task', lazy='dynamic') liked = db.relationship('Likes', backref='task', lazy='dynamic') def __init__(self, title): self.title = title def __repr__(self): return '<Task: {}|User:{}>'.format(self.title, self.user_id) # 判断任务是否超时 def is_overtime(self): if self.status == 0 and self.deadline > datetime.now(): return False elif self.status == 1 and self.overtime == 0: return False else: return True # 超时时间 def over_time(self): if self.status == 0 and self.deadline < datetime.now(): over_time = datetime.now() - self.deadline if over_time.total_seconds() < 3600: return ''.join( ['已超时', str(int(over_time.total_seconds() / 60)), '分钟']) elif 3600 <= over_time.total_seconds() < 86400: return ''.join( ['已超时', str(int(over_time.total_seconds() / 3600)), '小时']) else: return ''.join( ['已超时', str(int(over_time.total_seconds() / 86400)), '天']) elif self.status == 1: over_time = self.done_time - self.deadline if over_time.total_seconds() < 3600: return ''.join( ['超时', str(int(over_time.total_seconds() / 60)), '分钟完成']) elif 3600 <= over_time.total_seconds() < 86400: return ''.join( ['超时', str(int(over_time.total_seconds() / 3600)), '小时完成']) else: return ''.join( ['超时', str(int(over_time.total_seconds() / 86400)), '天完成']) else: pass # 给任务点赞的所有user_id def liked_user(self): return list(u.user_id for u in self.liked.all()) # 判断是否已点赞 def check_liked(self): if current_user.id in self.liked_user(): return True # 距离超时一小时 def one_hour_deadline(self): the_time = self.deadline - datetime.now() if 0 < the_time.total_seconds() < 3600: return True # 判断当前用户是否有权限查看当前task def task_auth(self): task_user = User.query.get(self.user_id) if current_user.id == self.user_id or self.public_level == 3 or ( current_user in task_user.follower.all() and self.public_level == 2): return True else: return False
class ItemSet(db.Model): __tablename__ = "item_set" _mapper_utils = { "files": { "server": ["s_SetItemData.bin"], "string": ["SetNameStr.dat"], }, } code = CustomColumn(db.String(32), primary_key=True, nullable=False, mapper_key="코드") name = CustomColumn(db.String(256), nullable=False, mapper_key="_name") weapon_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="무기", transform=lambda v: v if v != "#" else None) weapon = db.relationship("ItemList", foreign_keys=[weapon_code], uselist=False, lazy="joined") coat_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="상의", transform=lambda v: v if v != "#" else None) coat = db.relationship("ItemList", foreign_keys=[coat_code], uselist=False, lazy="joined") pants_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="하의", transform=lambda v: v if v != "#" else None) pants = db.relationship("ItemList", foreign_keys=[pants_code], uselist=False, lazy="joined") shoes_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="신발", transform=lambda v: v if v != "#" else None) shoes = db.relationship("ItemList", foreign_keys=[shoes_code], uselist=False, lazy="joined") gauntlet_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="장갑", transform=lambda v: v if v != "#" else None) gauntlet = db.relationship("ItemList", foreign_keys=[gauntlet_code], uselist=False, lazy="joined") shield_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="방패", transform=lambda v: v if v != "#" else None) shield = db.relationship("ItemList", foreign_keys=[shield_code], uselist=False, lazy="joined") necklace_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="목걸이", transform=lambda v: v if v != "#" else None) necklace = db.relationship("ItemList", foreign_keys=[necklace_code], uselist=False, lazy="joined") earring_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="귀걸이", transform=lambda v: v if v != "#" else None) earring = db.relationship("ItemList", foreign_keys=[earring_code], uselist=False, lazy="joined") ring_1_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="반지1", transform=lambda v: v if v != "#" else None) ring_1 = db.relationship("ItemList", foreign_keys=[ring_1_code], uselist=False, lazy="joined") ring_2_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="반지2", transform=lambda v: v if v != "#" else None) ring_2 = db.relationship("ItemList", foreign_keys=[ring_2_code], uselist=False, lazy="joined") dress_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="옷", transform=lambda v: v if v != "#" else None) dress = db.relationship("ItemList", foreign_keys=[dress_code], uselist=False, lazy="joined") hat_code = CustomColumn(db.String(32), db.ForeignKey("item_list.code"), mapper_key="모자", transform=lambda v: v if v != "#" else None) hat = db.relationship("ItemList", foreign_keys=[hat_code], uselist=False, lazy="joined") def to_dict(self) -> dict: item_columns = [ self.weapon, self.coat, self.pants, self.shoes, self.gauntlet, self.shield, self.necklace, self.earring, self.ring_1, self.ring_2, self.dress, self.hat ] effects = [] for i in range(1, 13): effect_code = getattr(self, f"effect_{i}_code") if effect_code: effects.append({ "code": effect_code.to_dict(), "operator": getattr(self, f"effect_{i}_operator"), "value": getattr(self, f"effect_{i}_value"), }) return { "items": [ item.to_dict(with_item_data=True) for item in item_columns if item ], "effects": effects, }
# 0 - 60 = 61 items per box for i in range(0, 62): # Code setattr(RandomBox, f"item_{i}_code", CustomColumn( db.String(32), db.ForeignKey("item_list.code"), mapper_key=f"보상{i}", transform=lambda v: v if v != "#" else None)) # Quantity setattr(RandomBox, f"item_{i}_quantity", CustomColumn( db.Integer, mapper_key=f"보상수량{i}", transform=lambda v: v if v != 0 else None )) # Chance setattr(RandomBox, f"item_{i}_chance", CustomColumn( db.Float, mapper_key="보상확률0", transform=( lambda v: florensia_probability_transform(v) if v != 0 else None))) # Relationship setattr(RandomBox, f"item_{i}", db.relationship( "ItemList", foreign_keys=[getattr(RandomBox, f"item_{i}_code")]))
class User(db.Model, UserMixin): __tablename__ = 'users' __searchable__ = ['username'] __analyzer__ = ChineseAnalyzer() id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(255), unique=True) password = db.Column(db.String(255)) email = db.Column(db.String(255)) create_time = db.Column(db.String(255)) online = db.Column(db.Boolean, default=False) last_seen_at = db.Column(db.Integer, default=time.time()) updated_at = db.Column(db.Integer, default=time.time(), onupdate=time.time()) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) messages = db.relationship('Message', backref='users', lazy='dynamic') def __init__(self, **kwargs): self.username = kwargs['username'] self.password = kwargs['password'] def __repr__(self): return "<User '{}'>".format(self.username) def check_username_password(self, username, password): user = User.query.filter_by(username=username).first() if user is None: return False elif user.password != password: return False else: return True def save(self): db.session.add(self) db.session.commit() def delete(self): db.session.delete(self) db.session.commit() @staticmethod def roll_back(): db.session.rollback() def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return unicode(self.id) def can(self, permissions): if self.roles is None: return False all_perms = reduce(or_, map(lambda x: x.permissions, self.roles)) return all_perms & permissions == permissions def ping(self): """Marks the user as recently seen and online.""" self.last_seen_at = time.time() last_online = self.online self.online = True return last_online != self.online @staticmethod def get_username_by_reg(reg): sql = ''' select username from users where username REGEXP '{}' LIMIT 5 '''.format(reg) ret = db.engine.execute(sql).fetchall() return [dict(r)['username'] for r in ret] @staticmethod def get_username_limit5(): sql = ''' select username from users LIMIT 5 ''' ret = db.engine.execute(sql).fetchall() return [dict(r)['username'] for r in ret]