示例#1
0
class Article(gj.Document, db.Document):

    url = db.URLField()
    author = db.StringField(default="")
    chuncks = db.ListField(db.StringField(),
                           default=list,
                           exclude_to_json=True)
    content = db.StringField(default="")
    domain = db.StringField(default="")
    title = db.StringField(default="")
    created_at = db.DateTimeField(default=datetime.datetime.utcnow)
    updated_at = db.DateTimeField(default=datetime.datetime.utcnow)
    image = db.URLField(required=False)
    # owner = None
    status = db.IntField(default=0, min_value=0, max_value=3)
    likes = db.ListField(db.ReferenceField("User"),
                         default=list,
                         exclude_to_json=True)

    meta = {
        "collection": "article",
        "indexes": [
            "url",
            "$url",  # text index
            "#url",  # hashed index
        ],
        "strict": False,
    }

    @property
    def likes_count(self) -> int:
        return len(self.likes) if self.likes else 0

    def check_like(self, user) -> bool:
        return user and user in self.likes

    def json(self, user=None):
        data = {
            **json.loads(self.to_json()),
            "likes_count": self.likes_count,
            "content": self.content[:100] if self.content else "",
            "like": 1 if user and self.check_like(user) else 0,
            "audios":
            [f"/media/{self.id}/full.mp3"] if self.status == 1 else [],
            # check if user already added article
            "added": 1 if user and self.check_added(user) else 0,
        }

        return data

    def check_added(self, user) -> bool:
        ua = UserArticle.objects(user=user, article=self)
        return True if ua else False
示例#2
0
class Post(db.Document):
    ''' Class for defining structure of reddit-top-posts collection
    '''
    url = db.URLField(required=True)
    date = db.DateTimeField(required=True)
    date_str = db.StringField(max_length=10, required=True)
    commentsUrl = db.URLField(required=True)
    sub = db.StringField(max_length=20, required=True) # subredit can be 20 chars
    title = db.StringField(max_length=300, required=True) # title can be 300 chars
    score = db.IntField(required=True)

    meta = {
        'collection': 'top_reddit_posts', # collection name
        'ordering': ['-score'], # default ordering
        'auto_create_index': False, # MongoEngine will not create index
        }
示例#3
0
class Task(db.Document):
    """
    任务信息Model
    """
    # 任务名称
    name = db.StringField(unique=True, max_length=64)
    # 任务简述
    desc = db.StringField(max_length=200)
    # 任务类型
    trigger = db.StringField(required=True, choices=TASK_TYPES)
    # 触发时间
    time = db.StringField(required=True)
    # http执行器相关
    # 执行器地址
    url = db.URLField(required=True)
    # 执行器方法
    method = db.StringField(required=True, choices=METHODS)
    # 修改时间
    update_time = db.DateTimeField(default=datetime.utcnow(), required=True)
    # 修改人
    update_user = db.ReferenceField(User)
    # 创建时间
    create_time = db.DateTimeField(default=datetime.utcnow(), required=True)
    # 创建人
    create_user = db.ReferenceField(User)
示例#4
0
class Posts(db.Document):
    city = db.StringField(max_length=200, required=True)
    uf = db.StringField(max_length=3, required=True)
    latitude = db.DecimalField(max_length=60, required=True)
    longitude = db.DecimalField(max_length=60, required=True)
    file = db.URLField(required=True)
    created_at = db.DateTimeField(default=datetime.utcnow(), required=True)
示例#5
0
class StoresDB(db.Document):
    """"""

    store_id = db.StringField(required=True)
    store_name = db.StringField(db_field='sn', max_length=30, required=True, unique=True)
    description = db.StringField(db_field='d', max_length=900, required=True)
    url_prefix = db.URLField(db_field='up', required=True, unique=True)
    tag_name = db.StringField(db_field='tn', required=True)
    query = db.DictField(db_field='q', required=True)
    predefined_store = db.BooleanField(db_field='ps', default=False)
    mall = db.ReferenceField(MallDB, reverse_delete_rule=CASCADE)
    user = db.ReferenceField(UserDB, reverse_delete_rule=CASCADE)
    user_email = db.EmailField(db_field='ue')
    creation_date = db.DateTimeField(db_field='cd', default=time_now())

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        """"""

        document.store_name = document.store_name.title()
        document.url_prefix = document.url_prefix.lower()
        document.tag_name = document.tag_name.lower()

    meta = {
        'indexes': ['store_name', 'url_prefix', 'store_id', 'predefined_store']
    }
示例#6
0
class BookMark(db.Document):
    title = db.StringField(required=True, default="")
    url = db.URLField(required=True, max_length=20, primary_key=True)
    content = db.StringField(required=True, default="", null=True)
    remarks = db.StringField(required=True, default="", null=True)
    time = db.DateTimeField(default=datetime.datetime.now())
    status = db.IntField(default=0)
    userid = db.IntField(default=0)
示例#7
0
文件: models.py 项目: zqin/sarjitsu
class Report(db.EmbeddedDocument):
    goal = db.StringField(max_length=140, required=True)
    summary = db.StringField(max_length=500, required=True)
    #db.EmbeddedDocumentField(Summary)
    results = db.StringField(max_length=500, required=True)
    #db.EmbeddedDocumentField(Results)
    datapath = db.URLField()
    analysis = db.EmbeddedDocumentField(Plots)
    created = db.DateTimeField(help_text='date it was created')
    modified = db.DateTimeField(help_text='last modified')
class Api(db.Document):
    # 字段
    api_name = db.StringField()  # 服务名称
    api_description = db.StringField()  # 服务描述
    api_id = db.SequenceField()  # 服务唯一标示
    url = db.URLField()  # 自身已经封装成的可以调用的url地址
    api_url = db.URLField()  # 转接url地址

    img_link = db.URLField()
    json_link = db.URLField()

    api_crawl_rules_link = db.URLField()  # 爬虫规则列表链接

    candidate = db.ListField()  # api参数列表

    main_sec_id = db.IntField()

    api_network = db.ListField()  # 网页可能有效的network请求

    api_result_example = db.ListField()

    form_rules_link = db.URLField()  # check click button的json链接

    api_request_parameters_candidate = db.ListField()  # 调用服务时可以使用的参数

    # {"type":"text",
    #  "query_name":"",
    #  "required":false/true, 是否必须
    #  "level":0/1/2,   0-系统级(__max_page),1-查询级(需要填充到输入框中的),2-返回级(返回参数中的)
    #   "example":
    #   "description"
    # }

    def __str__(self):
        return "service:{} - url:{}".format(self.api_name, self.url)
示例#9
0
class Questions(db.Document):

    _id = db.IntField(primary_key=True)
    url = db.URLField()
    title = db.StringField()
    content = db.StringField()
    is_solved = db.BooleanField(default=0)
    answer_count = db.IntField()
    view_count = db.StringField()
    vote_count = db.StringField()
    tags = db.ListField()
    answers = db.ListField()
    source = db.StringField()
示例#10
0
class ItemDB(db.Document):
    """The fields for the item that would be saved to the database"""
    item_id = db.StringField(required=True)
    store_id = db.StringField(db_field='si', required=True, default='')
    alert_id = db.StringField(db_field='ai')
    url = db.URLField(db_field='u', required=True, unique=True)
    item_name = db.StringField(db_field='in', required=True)
    item_image = db.StringField(db_field='i')
    item_description = db.StringField(db_field='d')
    user_email = db.StringField(db_field='ue', required=True)
    alert_added = db.BooleanField(db_field='aa', default=False)
    store = db.ReferenceField(StoresDB, reverse_delete_rule=CASCADE)
    creation_date = db.DateTimeField(db_field='cd', default=time_now())
    alert_deleted = db.BooleanField(db_field='ad', default=False)

    @classmethod
    def pre_save(cls, sender, document, **kwargs):
        """A pre-save function that is called before any item is saved"""
        document.item_name = document.item_name.lower()
        document.url = document.url.lower()

    meta = {
        'indexes': ['url', 'user_email', 'alert_added', 'store', 'item_id']
    }
示例#11
0
class User(db.Document):
    """A user model.

    The :class:`User` object is only created once the user logs in for the
    first time and confirms the details of their account.

    :ivar date_created: :class:`mongoengine.fields.DateTimeField` - The date
        that this user was created.
    :ivar date_modified: :class:`mongoengine.fields.DateTimeField` - The date
        the this user was last modified.
    :ivar gplus_id: :class:`mongoengine.fields.StringField` - The Google+ ID
        for this user.  It's what we use in the Google+ authentication.
    :ivar name: :class:`mongoengine.fields.StringField` - The user's name.
    :ivar slug: :class:`mongoengine.fields.StringField` - A URL slug  their
        internal profile page.
    :ivar email: :class:`mongoengine.fields.EmailField` - The user's email
        address.
    :ivar roles: :class:`mongoengine.fields.ListField` of
        :class:`mongoengine.fields.StringField` - A list of roles that the user
        has.
    :ivar privileges: :class:`mongoengine.fields.DictField` - A dictionary of
        privileges that the user has.  Often determined soley by their
        ``user_type``.
    :ivar image_url: :class:`mongoengine.fields.URLField` - The URL of the
        profile picture for the user's profile picture.
    :ivar image: :class:`mongoengine.fields.ReferenceField` - The local image
        for the user's profile picture.
    :ivar user_type: :class:`mongoengine.fields.StringField` - The type of the
        user. Can either be ``"fake_user"``, ``"editor"``, ``"publisher"``, or
        ``"admin"``.  The selection of user type determines their
        ``privileges``.
    :ivar last_logon: :class:`mongoengine.fields.DateTimeField` - The date of
        this user's last logon.
    """

    date_created = db.DateTimeField(required=True, default=now)
    date_modified = db.DateTimeField(required=True, default=now)
    gplus_id = db.StringField(required=True, unique=True)
    name = db.StringField(required=True, max_length=510)
    slug = db.StringField(required=True,
                          max_length=510,
                          unique=True,
                          regex=SLUG_REGEX)
    email = db.EmailField(required=True, unique=True)
    roles = db.ListField(db.StringField(db_field="role"), default=list)
    privileges = db.DictField(required=True, default={})
    image_url = db.URLField()
    image = db.ReferenceField('Image')
    user_type = db.StringField(default='editor', regex=USER_TYPE_REGEX)
    last_logon = db.DateTimeField()

    # MongoEngine ORM metadata
    meta = {'allow_inheritance': True, 'indexes': ['email', 'gplus_id']}

    def can(self, privilege):
        """Returns True if the user has ``privilege``.

        :returns: True if the user has ``privilege``
        :rtype: bool
        """
        return self.privileges.get(privilege)

    def get_profile_picture(self, size=50):
        """Returns the url to the profile picture for the user.

        TODO: This method needs major fixing.  What's going on with that URL?

        :param int size: The size of the image to pass, if the size can be
            changed.

        :returns: The URL of the image.
        :rtype: str
        """
        if self.image:
            return self.image.url()
        if not self.image_url:
            # Import app in the function body to avoid importing `None` when
            # the module is first loaded.
            from app import app
            return url_for('static',
                           filename=app.config['DEFAULT_PROFILE_PICTURE'])
        if "googleusercontent.com" in self.image_url:
            return self.image_url + str(size)
        return self.image_url

    def register_login(self):
        """Update the model as having logged in."""
        self.last_logon = now()

    def clean(self):
        """Called by Mongoengine on every ``.save()`` to the object.

        Update date_modified and apply privileges shorthand notation.

        :raises: :class:`wtforms.validators.ValidationError`
        """
        self.date_modified = now()

        # Update self.privileges with one of the USER_TYPES dictionaries
        self.privileges.update(USER_TYPES[self.user_type])

        # Update the slug for the user (used in URLs)
        new_slug = self.name.lower().replace(' ', '-')
        new_slug = re.sub(r"\'|\.|\_|", "", new_slug)
        if User.objects(slug=new_slug).count() > 0:
            i = 2
            new_slug = new_slug + "-{}".format(i)
            while User.objects(slug=new_slug).count() > 0:
                i += 1
                new_slug = re.sub(r"-([0-9])*$", "-{}".format(i), new_slug)
        self.slug = new_slug

        if self.image_url and "googleusercontent.com" in self.image_url:
            self.image_url = re.sub(r"sz=([0-9]*)$", "sz=", self.image_url)

    def id_str(self):
        """The id of this object, as a string.

        :returns: The id
        :rtype: str
        """
        return str(self.id)

    def role(self):
        """Returns the role of the user, in plain English.  It is either
        ``"Admin"``, ``"Publisher"``, ``"Editor"``, or ``"Fake User"``.

        :returns: The role.
        :rtype: str
        """
        if self.can('admin'):
            return "Admin"
        if self.can('publish'):
            return "Publisher"
        if self.can('edit'):
            return "Editor"
        return "Fake User"

    def __repr__(self):
        """The representation of this user.

        :returns: The user's details.
        :rtype: str
        """
        return ('User(id=%r, name=%r, email=%r, roles=%r, privileges=%r, '
                'gplus_id=%r, date_created=%r)' %
                (self.id, self.name, self.email, self.roles, self.privileges,
                 self.gplus_id, self.date_created))

    def __unicode__(self):
        """This user, as a unicode string.

        :returns: The user encoded as a string.
        :rtype: str
        """
        if self.can('admin'):
            return '%r <%r> (Admin)' % (self.name, self.email)
        if self.can('publish'):
            return '%r <%r> (Publisher)' % (self.name, self.email)
        if self.can('edit'):
            return '%r <%r> (Editor)' % (self.name, self.email)
        else:
            return '%r <%r> (Fake User)' % (self.name, self.email)
示例#12
0
class User(UserMixin, db.Document):
    username = db.StringField(max_length=255, required=True)
    email = db.EmailField(max_length=255)
    password_hash = db.StringField(required=True)
    create_time = db.DateTimeField(default=datetime.datetime.now,
                                   required=True)
    last_login_time = db.DateTimeField(default=datetime.datetime.now,
                                       required=True)
    confirmed = db.BooleanField(default=False)
    role = db.StringField(max_length=32, default='reader', choices=ROLES)
    is_superuser = db.BooleanField(default=False)
    about_me = db.StringField()
    social_networks = db.DictField(default=SOCIAL_NETWORKS)
    homepage_url = db.URLField()
    confirm_send_time = db.DateTimeField()

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    def generate_confirmation_token(self, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'confirm': self.username})

    def confirm_email(self, token, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except Exception:
            return False
        if data.get('confirm') != self.username:
            return False
        self.confirmed = True
        self.save()
        return True

    def generate_reset_token(self, expiration=3600):
        s = Serializer(current_app.config['SECRET_KEY'], expiration)
        return s.dumps({'reset': self.username})

    @staticmethod
    def reset_password(token, new_password):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)

        except Exception:
            return False

        try:
            user = User.objects.get(username=data.get('reset'))

        except Exception:
            return False

        user.password = new_password
        user.save()

        return True

    def get_id(self):
        try:
            return self.username
        except AttributeError:
            raise NotImplementedError(
                'No `username` attribute - override `get_id`')

    def user_to_dict(self):
        dict_user = {}

        dict_user['username'] = self.username
        dict_user['email'] = self.email
        dict_user['confirmed'] = self.confirmed
        dict_user['role'] = self.role
        dict_user['is_superuser'] = self.is_superuser
        dict_user['about_me'] = self.about_me
        dict_user['social_networks'] = self.social_networks
        dict_user['about_me'] = self.about_me
        dict_user['last_login_time'] = self.last_login_time.strftime(
            '%Y-%m-%d %H:%M')
        dict_user['create_time'] = self.create_time.strftime('%Y-%m-%d %H:%M')
        dict_user['confirm_send_time'] = self.confirm_send_time.strftime(
            '%Y-%m-%d %H:%M')

        return dict_user

    def __unicode__(self):
        return self.username
示例#13
0
class User(db.Document):
    """"""

    date_created = db.DateTimeField(required=True, default=now)
    date_modified = db.DateTimeField(required=True, default=now)
    gplus_id = db.StringField(required=True, unique=True)
    name = db.StringField(required=True, max_length=510)
    slug = db.StringField(required=True,
                          max_length=510,
                          unique=True,
                          regex='([a-z]|[A-Z]|[1-9]|-)*')
    email = db.EmailField(required=True, unique=True)
    roles = db.ListField(db.StringField(db_field="role"), default=list)
    privileges = db.DictField(required=True, default={})
    image_url = db.URLField()
    image = db.ReferenceField('Image')
    user_type = db.StringField(default='editor',
                               regex="(fake_user|editor|publisher|admin)")
    last_logon = db.DateTimeField()

    # MongoEngine ORM metadata
    meta = {'allow_inheritance': True, 'indexes': ['email', 'gplus_id']}

    def can(self, privilege):
        """Returns whether or not the user has a privilege"""
        return self.privileges.get(privilege)

    def get_profile_picture(self, size=50):
        if self.image:
            return self.image.url()
        if not self.image_url:
            return 'https://lh6.googleusercontent.com/-K9HZ5Z5vOU8/AAAAAAAAAAI/AAAAAAAAAAA/yRoMtBSXoxQ/s48-c/photo.jpg'
        if "googleusercontent.com" in self.image_url:
            return self.image_url + str(size)
        return self.image_url

    def register_login(self):
        """Update the model as having logged in"""
        self.last_logon = now()

    def clean(self):
        """Update date_modified and apply privileges shorthand notation."""
        self.date_modified = now()

        # If undefined, update self.privileges with one of the USER_TYPES
        # dictionaries
        if self.privileges == {}:
            self.privileges.update(USER_TYPES[self.user_type])

        # Update the slug for the user (used in URLs)
        new_slug = self.name.lower().replace(' ', '-')
        new_slug = re.sub(r"\'|\.|\_|", "", new_slug)
        if User.objects(slug=new_slug).count() > 0:
            i = 2
            new_slug = new_slug + "-%s" % i
            while User.objects(slug=new_slug).count() > 0:
                i += 1
                new_slug = re.sub(r"-([0-9])*$", "-%s" % i, new_slug)
        self.slug = new_slug

        if self.image_url and "googleusercontent.com" in self.image_url:
            self.image_url = re.sub(r"sz=([0-9]*)$", "sz=", self.image_url)

    def id_str(self):
        return str(self.id)

    def role(self):
        if self.can('admin'):
            return "Admin"
        if self.can('publish'):
            return "Publisher"
        if self.can('edit'):
            return "Editor"
        return "Fake User"

    def __repr__(self):
        return 'User(id=%r, name=%r, email=%r, roles=%r, privileges=%r, gplus_id=%r, date_created=%r)' % \
            (self.id, self.name, self.email, self.roles,
             self.privileges, self.gplus_id, self.date_created)

    def __unicode__(self):
        if self.can('admin'):
            return '%r <%r> (Admin)' % (self.name, self.email)
        if self.can('publish'):
            return '%r <%r> (Publisher)' % (self.name, self.email)
        if self.can('edit'):
            return '%r <%r> (Editor)' % (self.name, self.email)
        else:
            return '%r <%r> (Fake User)' % (self.name, self.email)
示例#14
0
class Product(db.Document):
    product_id = db.IntField(required=True)

    product_name = db.StringField(required=True)
    # FIXME: type of 'product_stars' should be float
    product_stars = db.IntField(min_value=0, max_value=5, default=0)
    description = db.EmbeddedDocumentField(Description, required=True)
    quantity = db.IntField(min_value=0, required=True)
    ordered = db.IntField(min_value=0, default=0)

    base_price = db.FloatField(min_value=0, required=True)
    discount = db.FloatField(min_value=0, default=0)
    discounted_price = db.FloatField(min_value=0, required=True)

    seller_id = db.IntField(required=True)
    # category_id = db.IntField(required=True)    # very last sub-category
    category = db.ReferenceField(SecondaryCategory,
                                 reverse_delete_rule=mongoengine.CASCADE,
                                 required=True)  # very last sub-category

    img_base_url = db.URLField(required=True)
    img_aux_urls = db.ListField(db.URLField(), max_length=3, default=[])

    colors = db.ListField(db.StringField(), required=True)
    sizes = db.ListField(db.StringField(), required=True)
    features = db.ListField(db.StringField(), required=True)

    date = db.EmbeddedDocumentField(Date)
    # reviews = db.ListField(db.EmbeddedDocumentField(Review))
    tags = db.ListField(db.StringField(), max_length=5)
    extra = db.DictField(default={})

    meta = {'collection': 'products', 'indexes': ['product_id']}

    def __repr__(self):
        return f'Product(id={self.product_id}, name={self.name})'

    @classmethod
    def add_document(cls, **kwargs):
        next_id = Counter.get_next_sequence_value('products')
        product = cls(
            product_id=next_id,
            product_name=kwargs.get('product_name'),
            quantity=kwargs.get('quantity'),
            base_price=kwargs.get('base_price'),
            discount=kwargs.get('discount', 0),
            seller_id=kwargs.get('seller_id'),
            #   category_id=kwargs.get('category_id'),
            features=kwargs.get('features', []),
            colors=kwargs.get('colors', []),
            sizes=kwargs.get('sizes', []),
            img_base_url=kwargs.get('img_base_url'))
        product.description = Description(
            short_description=kwargs.get('short_description'),
            long_description=kwargs.get('long_description'))
        product.date = Date()
        product.category = (SecondaryCategory.objects(
            category_id=kwargs.get('category_id')).first())
        product.discounted_price = product.base_price * (
            1 - product.discount / 100)
        product.img_aux_urls = kwargs.get('img_aux_urls', [])

        return product
示例#15
0
class User(db.Document, UserMixin, FavorAction):
    """"""
    meta = {
        'indexes': [
            'name', 'account.created_at', 'roles', 'level', 'account.email',
            'account.is_email_verified', 'is_deleted'
        ],
        'ordering': ['-account.created_at']
    }
    name = db.StringField(required=True)
    account = db.EmbeddedDocumentField('UserAccount')
    information = db.EmbeddedDocumentField('UserInformation')
    avatar_url = db.URLField(default='http://assets.maybe.cn/logo/panda.jpg')
    # level
    # 0: normal user
    # 1: normal member
    # 2: advance member
    # 3: premium member
    # 4: VIP member
    level = db.IntField(default=0)
    roles = db.ListField(db.StringField())
    address = db.ListField(db.ReferenceField('Address'))
    default_address = db.ReferenceField('Address')
    # followers
    num_followers = db.IntField(default=0, min_value=0)
    num_followings = db.IntField(default=0, min_value=0)
    followers = db.ListField(db.ReferenceField('User'))
    followings = db.ListField(db.ReferenceField('User'))

    subscribed_mp = db.BooleanField(default=False)

    # favor related (item_ids)
    num_favors = db.IntField(default=0, min_value=0)
    favor_items = db.ListField(db.IntFidld())

    # favor related (post_ids)
    num_post_likes = db.IntField(default=0, min_value=0)
    like_posts = db.ListField(db.IntField())

    # shopping cart
    cart = db.ReferenceField('Cart')

    # wallet
    wallet = db.ReferenceField('CouponWallet')

    is_deleted = db.BooleanField(default=False)
    deleted_date = db.DateTimeField()

    def __unicode__(self):
        # return '%s' % str(self.id)
        return '{}'.format(self.name)

    @property
    def coin_wallet(self):
        return CoinWallet.get_or_create(user=self)

    @property
    def lucky_money(self):
        return LuckymoneyWallet.by_user(user=self)

    @property
    def orders(self):
        return Order.objects(customer_id=self.id, is_paid=True)

    @property
    def avatar_thumb(self):
        return self.avatar_url[:23] + 'avarat_thumbs/80x80/' + self.avatar_url[
            23:]

    def used_coupon(self, code):
        return bool(
            Order.objects(customer_id=self.id,
                          is_paid=True,
                          coupon_codes__contains=code))

    @db.queryset_manager
    def active(doc_cls, queryset):
        return queryset.filter(is_deleted=False)

    @property
    def is_admin(self):
        return USER_ROLE.ADMIN in self.roles

    def follow(self, other):
        if self not in other.followers:
            other.followers.append(self)
            other.num_followers += 1

        if other not in self.followings:
            self.followings.append(other)
            self.num_followings += 1

        self.save()
        other.save()

        signals.site_message.send(self,
                                  dest=other.id,
                                  source=self,
                                  imgs=[self.avatar_url],
                                  noti_type=NOTIFICATION_TYPE.FOLLOW,
                                  title='')

    def unfollow(self, other):
        if self in other.followers:
            other.followers.remove(self)
            other.num_followers -= 1

        if other in self.followings:
            self.followings.remove(other)
            self.num_followings -= 1

        self.save()
        other.save()

    def is_following(self, other):
        return other in self.followings

    def to_json(self):
        data = dict(
            name=self.name,
            avatar_url=self.avatar_url,
            avatar_thumb=self.avatar_thumb,
            num_followers=self.num_followers,
            num_followings=self.num_followings,
            created_at=str(self.account.created_at),
            id=str(self.id),
        )
        return data

    @classmethod
    def authenticate(cls, email=None, password=None):
        if email:
            user = cls.active(account__email=email.lower()).first()
        else:
            user = None
        if user:
            authenticated = user.account.check_password(password)
        else:
            authenticated = False

        return user, authenticated

    def generate_auth_token(self, expires_in=604800):
        serializer = TimedJSONWebSignatureSerializer(
            current_app.config['SECRET_KEY'], expires_in=expires_in)
        return serializer.dumps({'id': str(self.id)}).decode('utf-8')

    @staticmethod
    def verify_auth_token(token):
        serializer = TimedJSONWebSignatureSerializer(
            current_app.config['SECRET_KEY'])
        try:
            data = serializer.loads(token)
        except:
            return None

        return User.objects(id=data['id']).first()

    @classmethod
    def create(cls, email, password, name, mobile_number=None):
        # init user account
        cart = Cart()
        cart.save()

        wallet = CouponWallet()
        wallet.save()

        # account
        account = UserAccount(email=email.lower(),
                              mobile_number=mobile_number,
                              is_email_verified=True)
        account.password = password

        user = User(name=name,
                    roles=[USER_ROLE.MEMBER],
                    information=UserInformation(),
                    cart=cart,
                    wallet=wallet,
                    account=account)
        user.save()
        signals.user_signup.send('system', user=user)
        return user

    def mark_deleted(self):
        if self.is_deleted:
            return
        SocialOAuth.objects(user=self).delete()
        self.is_deleted = True
        self.deleted_date = datetime.datetime.utcnow()
        self.save()
class User(db.Document):
    """
    User Document Schema
    """

    _id = db.StringField(primary_key=True)
    loginType = db.StringField()
    imageUrl = db.URLField()
    email_id = db.StringField(db_field="email", required=True, unique=True)
    password = db.StringField(required=True, db_field="password")
    name = db.StringField(db_field="name")
    stats = db.DictField()
    workspaces = db.ListField(db.StringField(), default=[])             #A workspace is an organization, an email ID can be a part of one workspace only
    isActive = db.BooleanField(default=False)                           #Set to True after registering
    registeredOn = db.DateTimeField(default=None, null=True)            #When did the person actually register on the console after invite
    isRemoved = db.BooleanField(default=False)                          #Has admin removed this account or person deletes own account
    removedOn = db.DateTimeField(default=None, null=True)               #When was the account removed
    isEmailVerified = db.BooleanField(default=False)                    #If email has been verified
    tokens = db.ListField(db.DictField(), default=[], required=True)   #AccessTokens for console, fb messenger, etc

    meta = {'collection': 'users', 'strict': False}

    def __init__(self, *args, **kwargs):
        super(User, self).__init__(*args, **kwargs)
        if not self._id:
            self._id = f"usr{util.get_short_unique_id()}"
    
    
    def sign_up(self, userObj=None, *args, **kwargs):
        self.loginType = 'email'
        self.isActive = True
        self.registeredOn = util.get_current_time()
        self.save()

    @staticmethod
    def encode_password(password):
        return base64.b64encode(password.encode("utf-8")).decode('utf-8')

    def save(self, *args, **kwargs):
        super(User, self).save(*args, **kwargs)
        return self
        # return self.encode_auth_token(self.loginId)

    def generate_third_party_tokens(self):
        expiry = datetime.datetime.utcnow() + datetime.timedelta(seconds=app.config.get('AUTH_TOKEN_EXPIRY_SECONDS'))
        ks = util.get_kaltura_session(self.email_id)
        self.tokens = Tokens(arena={'token':ks, 'expiry':expiry})
        self.save()

    def generate_access_tokens(self):
        payload = {
            'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=app.config.get('AUTH_TOKEN_EXPIRY_SECONDS')),
            'iat': datetime.datetime.utcnow(),
            'sub': self.email_id
        }
        token = jwt.encode(
            payload,
            app.config['SECRET_KEY'],
            algorithm='HS256'
        ).decode('utf-8')

        print("Token generated", token)
        return token

    def get_auth_token(self):
        """
        Generates new auth token, sets auth token, returns auth token
        :param user_id: User's Id
        :return:
        """
        try:
            return self.generate_access_tokens()
        except Exception as e:
            print (e)
            app.logger.error('LOGIN', exc_info=True)
            return e

    @staticmethod
    def decode_auth_token(token):
        """
        Decoding the token to get the payload and then return the user Id in 'sub'
        :param token: Auth Token
        :return:
        """
        try:
            payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms='HS256', verify=False)
            is_token_blacklisted = BlackListToken.check_blacklist(token)
            if is_token_blacklisted:
                raise ValueError('Token was Blacklisted, Please login In')
            return payload['sub']
        except jwt.ExpiredSignatureError:
            raise ValueError('Signature expired, Please sign in again')
        except jwt.InvalidTokenError:
            raise ValueError('Invalid token. Please sign in again')


    @staticmethod
    def decode_verify_token(token):
        """
        Decoding the token to get the payload and then return the user Id in 'sub'
        :param token: Auth Token
        :return:
        """
        try:
            payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms='HS256', verify=False)
            is_token_blacklisted = BlackListToken.check_blacklist(token)
            if is_token_blacklisted:
                raise ValueError('Token was Blacklisted, Please Sign Up Again')
            return payload['sub']
        except jwt.ExpiredSignatureError:
            raise ValueError('Signature expired, Please sign in again')
        except jwt.InvalidTokenError:
            raise ValueError('Invalid token. Please sign in again')

    @staticmethod
    def get_by_id(user_id):
        """
        Filter a user by Id.
        :param user_id:
        :return: User or None
        """
        return User.objects(_id=user_id).first()

    @staticmethod
    def get_by_email(email):
        """
        Check a user by their email address
        :param email:
        :return:
        """
        # user_list =  User.objects(email_id=email).as_pymongo()
        # if user_list:
        #     return user_list[0]
        # else:
        #     return []

        return User.objects(email_id=email).first()

    def remove(self):
        """
        Soft deletes the user
        """
        self.isRemoved = True
        self.removedOn = util.get_current_time()