class MediaMixin(object): name = db.Column(sqla.String(200)) qiniu_key = db.Column(sqla.String(200), unique=True) # 处理结果 media_process = db.Column(JSON) # 不能用process和meta,因为wtform 有这两个属性 # 媒体资源的元信息 media_meta = db.Column(JSON)
class Favor(CRUDMixin, db.Model): id = sqla.Column(sqla.Integer, primary_key=True) create_time = db.Column(sqla.DateTime, default=datetime.utcnow) user_id = db.Column(sqla.Integer, db.ForeignKey(USER_TABLE_USER_ID)) user = db.relationship('User', backref=db.backref('favors')) # 喜爱对象id obj_id = db.Column(sqla.Integer, db.ForeignKey('book.id')) # 喜爱对象类型 obj_type = db.Column( sqla.Enum('book', 'courseware', 'onlinecourse', name='like_obj_type')) __table_args__ = (UniqueConstraint('user_id', 'obj_id', 'obj_type', name='_user_favor_obj'), ) @property def favor_model(self): from youjiao.teach_material.models import Book, Courseware from youjiao.onlinecourse.models import OnlineCourse if self.obj_type == 'book': return Book if self.obj_type == 'courseware': return OnlineCourse if self.obj_type == 'onlinecourse': return OnlineCourse else: return None @property def real_obj(self): model = self.favor_model return model.query.get(self.obj_id)
class Photo(db.Model, CRUDMixin): id = sqla.Column(sqla.Integer, primary_key=True) create_time = sqla.Column(sqla.DateTime, default=datetime.utcnow) name = db.Column(sqla.String(50)) qiniu_key = db.Column(sqla.String(200)) album_id = db.Column(sqla.Integer, db.ForeignKey('album.id')) def __repr__(self): return u'<Photo: {}>'.format(self.name) @property def url(self): return u'{}/{}'.format(flask_qiniu.PUBLIC_CDN_DOMAIN, self.qiniu_key) @property def thumbnail(self): return u'{}?imageView/2/w/150'.format(self.url) @property def with_watermark(self): return '' @property def with_watermark_thumbnail(self): return ''
class Role(db.Model, RoleMixin, CRUDMixin): id = db.Column(sqla.Integer, primary_key=True) name = db.Column(sqla.String(80), unique=True) description = db.Column(sqla.String(255)) def __repr__(self): return '<Role {}>'.format(self.name)
class LeaveMessage(CRUDMixin, db.Model): id = sqla.Column(sqla.Integer, primary_key=True) create_time = db.Column(sqla.DateTime, default=datetime.utcnow) content = db.Column(sqla.String(length=1000)) user_id = db.Column(sqla.Integer, db.ForeignKey(USER_TABLE_USER_ID)) user = db.relationship('User', backref=db.backref('leave_messages'))
class Comment(CRUDMixin, db.Model): id = sqla.Column(sqla.Integer, primary_key=True) create_time = db.Column(sqla.DateTime, default=datetime.utcnow) user_id = db.Column(sqla.Integer, db.ForeignKey(USER_TABLE_USER_ID)) user = db.relationship('User', backref=db.backref('comments')) # 评论对象id comment_obj_id = db.Column(sqla.Integer) # 评论对象类型 comment_obj_type = db.Column( sqla.Enum('book', 'courseware', name='comment_obj_type')) content = db.Column(sqla.String(140))
class Page(CRUDMixin, CreateUpdateTimeMixin, db.Model): id = db.Column(db.Integer, primary_key=True) # create_time = db.Column(db.DateTime, default=datetime.now) # update_time = db.Column(db.DateTime, onupdate=datetime.now) title = db.Column(db.String(255)) html = db.Column(db.Text) status = db.Column(db.String(2), default='1') user_id = db.Column(db.Integer, db.ForeignKey(USER_TABLE_USER_ID)) @property def edit_link(self): redirect_url = url_for('activity_content.pages', page_title=self.title) return '/admin/page/edit?url={}&id={}'.format(redirect_url, self.id)
class Activity(CRUDMixin, CreateUpdateTimeMixin, db.Model): id = db.Column(sqla.Integer, primary_key=True) # create_time = db.Column(sqla.DateTime, default=datetime.utcnow) # update_time = db.Column(sqla.DateTime, onupdate=datetime.utcnow) title = db.Column(db.String(255)) origin = db.Column(db.String(255), default='') html = db.Column(db.Text) # status = db.Column(sqla.Boolean, default=False) publish = db.Column(sqla.Boolean, default=False) category = db.Column(sqla.Enum('policy', 'news', 'events', 'research', 'activity', 'achievement', name='category'), default='policy') user_id = db.Column(db.Integer, db.ForeignKey(USER_TABLE_USER_ID)) user = db.relationship('User') @classmethod def weekly_popular_top10(cls): return cls.query.limit(10).all() @property def link(self): return url_for('activity_content.activity_view', id=self.id) @property def edit_link(self): redirect_url = url_for('activity_content.activity_view', id=self.id) return '/admin/activity/edit?url={}&id={}'.format( redirect_url, self.id)
class OnlineCourse(CRUDMixin, CreateUpdateTimeMixin, db.Model): id = db.Column(db.Integer, primary_key=True) publish = db.Column(sqla.Boolean, default=False) name = db.Column(sqla.String(200)) url = db.Column(sqla.String(200)) category = db.Column( sqla.Enum(u'优秀课堂', u'优秀讲座', u'其他视频', u'产品使用培训', u'师资培训视频', name='online_course_category')) content = db.Column(JSON) @classmethod def get_category(cls, category): return cls.query.filter_by(category=category, publish=True) @property def link(self): return url_for('online_course.video_detail', video_id=self.id) @property def cover(self): if self.content.get('full_video'): video_cover = self.content['full_video'] + '?vframe/jpg/offset/7/w/480/h/360' return get_private_url(video_cover) return 'http://7xn3in.com2.z0.glb.qiniucdn.com/logo-big.jpg' def add_user_visit_recent(self, user): key = user.onlinecourse_visit_recent_key redis_cli.lpush(key, self.id) redis_cli.ltrim(key, 0, 8) @classmethod def top10(cls): return cls.query.filter(cls.publish==True).limit(10)
class User(db.Model, UserMixin, CRUDMixin): __tablename__ = USER_TABLE_NAME id = sqla.Column(sqla.Integer, primary_key=True) name = db.Column(sqla.String(50), unique=True) email = db.Column(sqla.String(50), unique=True) password = db.Column(sqla.String(200)) phone_number = db.Column(sqla.String(16), unique=True) active = db.Column(sqla.Boolean, default=True) # is_admin = db.Column(db.Boolean, default=False) # TODO: use a base model to add create_time and update_time create_time = db.Column(sqla.DateTime, default=datetime.utcnow) last_login = db.Column(sqla.DateTime) # TODO: add login log field, and add field update in login view roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) # profile = db.relationship('UserProfile', backref='user', uselist=False) # from youjiao.user_util.models import Comment, Favor # comments = db.relationship('Comment', backref='user') # favors = db.relationship('Favor', backref='user') def __repr__(self): return '<User {}>'.format(self.name) @classmethod def create_user(cls, name, email, password): password = encrypt_password(password) user = User() user.name = name user.email = email user.password = password user.save() return user @classmethod def verify(cls, email_or_name, password): user = cls.query.filter((User.email==email_or_name)|(User.name==email_or_name)).first() if not user: return None if not user.verify_and_update_password(password): return None return user def set_password(self, new_password): self.password = encrypt_password(new_password) self.save() def verify_password(self, password): return verify_password(password, self.password) def verify_and_update_password(self, password): """used in login user""" signed = get_hmac(password).decode('ascii') verified, new_password = password_context.verify_and_update(signed, self.password) if verified and new_password: self.password = new_password self.save() return verified @property def roles_name(self): return [role.name for role in self.roles] def favor(self, obj_type): from youjiao.user_util.models import Favor pass @property def book_visit_recent_key(self): return 'user_{}_book_visit_list'.format(self.id) @property def courseware_visit_recent_key(self): return 'user_{}_courseware_visit_list'.format(self.id) @property def onlinecourse_visit_recent_key(self): return 'user_{}_onlinecourse_visit_list'.format(self.id) @property def book_visit_recent(self): from youjiao.teach_material.models import Book book_id_list = redis_cli.lrange(self.book_visit_recent_key, 0, 8) return Book.query.filter(Book.id.in_(book_id_list)) @property def courseware_visit_recent(self): from youjiao.teach_material.models import Courseware courseware = redis_cli.lrange(self.courseware_visit_recent_key, 0, 8) return Courseware.query.filter(Courseware.id.in_(courseware)) @property def onlinecourse_visit_recent(self): from youjiao.onlinecourse.models import OnlineCourse onlinecourse_id_list = redis_cli.lrange(self.onlinecourse_visit_recent_key, 0, 8) return OnlineCourse.query.filter(OnlineCourse.id.in_(onlinecourse_id_list)) @property def can_view_vip_content(self): return vip_permission.can()
class VIP(db.Model, CRUDMixin): id = db.Column(sqla.Integer, primary_key=True) user_id = db.Column(sqla.Integer, db.ForeignKey(USER_TABLE_USER_ID)) user = db.relationship('User', backref=db.backref('vips')) begin = db.Column(sqla.Date) end = db.Column(sqla.Date)
class UserProfile(db.Model, CRUDMixin): id = db.Column(sqla.Integer, primary_key=True) user_id = db.Column(sqla.Integer, db.ForeignKey(USER_TABLE_USER_ID)) user = db.relationship('User', backref=db.backref('profile', uselist=False)) # TODO: add column describe/description nickname = db.Column(sqla.String(16), unique=True) work_place_name = db.Column(sqla.String(255)) avatar_qiniu_key = db.Column(sqla.String(200), default='default_avatar.png') birthday = db.Column(sqla.Date) gender = db.Column(sqla.Enum('male', 'female', name='gender')) career = db.Column(sqla.String(16)) province = db.Column(sqla.String(16)) city = db.Column(sqla.String(16)) district = db.Column(sqla.String(16)) street = db.Column(sqla.String(16)) @property def location(self): return '{} {} {} {}'.format(self.province, self.city, self.district, self.street)
# -*- coding: utf-8 -*- from __future__ import absolute_import from datetime import datetime from flask_security import RoleMixin from flask_login import UserMixin from youjiao.extensions import db, redis_cli, USER_TABLE_NAME, USER_TABLE_USER_ID from youjiao.utils.database import CRUDMixin import sqlalchemy as sqla from .permissions import vip_permission from .utils import generate_random_number_4, generate_random_string_4, encrypt_password, \ verify_password, get_hmac, password_context roles_users = db.Table( 'roles_users', db.Column('user_id', sqla.Integer(), db.ForeignKey('youjiao_user.id')), db.Column('role_id', sqla.Integer(), db.ForeignKey('role.id')), sqla.UniqueConstraint('user_id', 'role_id') ) class User(db.Model, UserMixin, CRUDMixin): __tablename__ = USER_TABLE_NAME id = sqla.Column(sqla.Integer, primary_key=True) name = db.Column(sqla.String(50), unique=True) email = db.Column(sqla.String(50), unique=True) password = db.Column(sqla.String(200)) phone_number = db.Column(sqla.String(16), unique=True) active = db.Column(sqla.Boolean, default=True) # is_admin = db.Column(db.Boolean, default=False) # TODO: use a base model to add create_time and update_time
class Slider(CRUDMixin, db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(sqla.String(200)) image_list = db.Column(JSON) POSITION_HOME = u'主页' POSITION_COURSEWARE_HOME = u'课件' POSITION_BOOK_HOME = u'教材' POSITION_ONLINECOURSE_HOME = u'网课主页' @classmethod def home_slider(cls): slider = cls.query.filter_by(name=cls.POSITION_HOME).first() if slider: return slider.image_list else: return [ { 'image': "http://7xj2zj.com2.z0.glb.qiniucdn.com/11.jpg", 'link': '/book/1' }, { 'image': "http://7xj2zj.com2.z0.glb.qiniucdn.com/12.jpg", 'link': '/book/2' }, { 'image': "http://7xj2zj.com2.z0.glb.qiniucdn.com/13.jpg", 'link': '/book/3' }, { 'image': "http://7xj2zj.com2.z0.glb.qiniucdn.com/14.jpg", 'link': '/book/4' }, { 'image': "http://7xj2zj.com2.z0.glb.qiniucdn.com/15.jpg", 'link': '/book/5' }, ] @classmethod def book_slider(cls): slider = cls.query.filter_by(name=cls.POSITION_BOOK_HOME).first() if slider: return slider.image_list else: return [ { 'image': "http://7xn3in.com2.z0.glb.qiniucdn.com/banner1.jpg", 'link': '/book/1' }, { 'image': "http://7xn3in.com2.z0.glb.qiniucdn.com/banner2.jpg", 'link': '/book/1' }, { 'image': "http://7xn3in.com2.z0.glb.qiniucdn.com/banner3.jpg", 'link': '/book/1' }, { 'image': "http://7xn3in.com2.z0.glb.qiniucdn.com/banner4.jpg", 'link': '/book/1' }, { 'image': "http://7xn3in.com2.z0.glb.qiniucdn.com/banner5.jpg", 'link': '/book/1' }, ] @classmethod def courseware_slider(cls): slider = cls.query.filter_by(name=cls.POSITION_COURSEWARE_HOME).first() if slider: return slider.image_list else: return [{ "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/e7a9887b-2a77-4e52-85c9-0e914880f795/anner1.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/f3603d5f-dbab-407c-baa0-6702fd4d708f/anner2.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/e9fb3150-4b19-48e4-adcb-35eea39bd818/banner3.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/2ba3c115-9203-4f1e-8885-15093041a53d/banner4.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/52bc0da0-6bcc-49f8-a6ee-cb978376e7e3/banner5.jpg", "link": "#" }] @classmethod def onlinecourse_slider(cls): slider = cls.query.filter_by( name=cls.POSITION_ONLINECOURSE_HOME).first() if slider: return slider.image_list else: return [{ "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/lesson%20banner1.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/lesson%20banner2.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/lesson%20banner3.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/lesson%20banner4.jpg", "link": "#" }, { "image": "http://7xn3in.com2.z0.glb.qiniucdn.com/lesson%20banner5.jpg", "link": "#" }]
class ContentList(CRUDMixin, CreateUpdateTimeMixin, db.Model): ''' 页面出现一些对象, 要求有name这个字段, 保存成一个array(list)放在json中''' id = db.Column(sqla.Integer, primary_key=True) position = db.Column(sqla.String(200)) content = db.Column(JSON) BOOK = u'幼教教材' COURSEWARE = u'幼教课件' ONLINECOURSE = u'幼教网课' # position enum HOME_BOOK = u'首页 教材推荐' HOME_COURSEWARE = u'首页 课件推荐' HOME_RECOMMEND = u'首页推荐' from youjiao.teach_material.models import Book, Courseware from youjiao.onlinecourse.models import OnlineCourse name_model = { BOOK: Book, COURSEWARE: Courseware, ONLINECOURSE: OnlineCourse } model_name = {v: k for k, v in name_model.items()} @staticmethod def obj_to_dict(obj): obj_dict_list = [{ 'id': obj.id, 'name': obj.__repr__(), 'model_name': name } for name, model in ContentList.name_model.items() if isinstance(obj, model)] if len(obj_dict_list) == 0: raise Exception('can not handle obj: {}'.format(obj)) else: return obj_dict_list[0] @staticmethod def dict_to_obj(dct): obj_model = ContentList.name_model[dct['model_name']] obj_id = dct['id'] return obj_model.query.get(obj_id) @classmethod def add_obj_to_position(cls, obj_list, position_name): if position_name not in [ cls.HOME_BOOK, cls.HOME_COURSEWARE, cls.HOME_RECOMMEND ]: raise Exception('{} is invalid'.format(position_name)) contentlist = cls.query.filter(cls.position == position_name).first() if not contentlist: contentlist = cls(position=position_name, content=[]) contentlist.save() if not isinstance(obj_list, collections.Iterable): obj_list = [ obj_list, ] added_content = [cls.obj_to_dict(obj) for obj in obj_list] contentlist.content = contentlist.content + added_content contentlist.save() return contentlist @property def ids(self): return [i.get('id') for i in self.content] @property def obj_list(self): return [self.dict_to_obj(i) for i in self.content]
class CreateUpdateTimeMixin(object): create_time = db.Column(sqla.DateTime, default=datetime.utcnow) update_time = db.Column(sqla.DateTime, onupdate=datetime.utcnow)