from datetime import datetime

from sqlalchemy import Column
from sqlalchemy_utils.types import phone_number
from werkzeug import generate_password_hash, check_password_hash
from flask.ext.login import UserMixin

from ..extensions import db
from .constants import (USER_ROLE, ADMIN, STAFF,
                        USER_STATUS, ACTIVE,
                        STRING_LEN)


class User(db.Model, UserMixin):
    __tablename__ = 'user_user'

    id = Column(db.Integer, primary_key=True)
    name = Column(db.String(STRING_LEN), nullable=False, unique=True)
    email = Column(db.String(STRING_LEN), nullable=False, unique=True)
    openid = Column(db.String(STRING_LEN), unique=True)
    activation_key = Column(db.String(STRING_LEN))
    created_time = Column(db.DateTime, default=datetime.utcnow)
    last_accessed = Column(db.DateTime)

    phone = Column(phone_number.PhoneNumberType())

    _password = Column('password', db.String(STRING_LEN*3), nullable=False)

    def __unicode__(self):
        return self.name

    def _get_password(self):
        return self._password

    def _set_password(self, password):
        self._password = generate_password_hash(password)
    # Hide password encryption by exposing password field only.
    password = db.synonym('_password',
                          descriptor=property(_get_password,
                                              _set_password))

    def check_password(self, password):
        if self.password is None:
            return False
        return check_password_hash(self.password, password)

    # One-to-many relationship between users and roles.
    role_code = Column(db.SmallInteger, default=STAFF)

    @property
    def role(self):
        return USER_ROLE[self.role_code]

    def is_admin(self):
        return self.role_code == ADMIN

    # One-to-many relationship between users and user_statuses.
    status_code = Column(db.SmallInteger, default=ACTIVE)

    @property
    def status(self):
        return USER_STATUS[self.status_code]

    # ================================================================
    # Class methods

    @classmethod
    def authenticate(cls, login, password):
        user = cls.query.filter(db.or_(User.name == login, User.email == login)).first()

        if user:
            authenticated = user.check_password(password)
        else:
            authenticated = False

        return user, authenticated

    @classmethod
    def search(cls, keywords):
        criteria = []
        for keyword in keywords.split():
            keyword = '%' + keyword + '%'
            criteria.append(db.or_(
                User.name.ilike(keyword),
                User.email.ilike(keyword),
            ))
        q = reduce(db.and_, criteria)
        return cls.query.filter(q)

    @classmethod
    def get_by_id(cls, user_id):
        return cls.query.filter_by(id=user_id).first_or_404()

    def check_name(self, name):
        return User.query.filter(db.and_(User.name == name, User.email != self.id)).count() == 0

@@ -28,38 +28,8 @@
 me%0A%0A
-from sqlalchemy import Column%0A
 from
@@ -407,24 +407,27 @@
 '%0A%0A    id = 
+db.
 Column(db.In
@@ -458,24 +458,27 @@
 %0A    name = 
+db.
 Column(db.St
@@ -536,16 +536,19 @@
 email = 
+db.
 Column(d
@@ -607,24 +607,27 @@
    openid = 
+db.
 Column(db.St
@@ -678,16 +678,19 @@
 n_key = 
+db.
 Column(d
@@ -726,24 +726,27 @@
 ated_time = 
+db.
 Column(db.Da
@@ -794,24 +794,27 @@
 _accessed = 
+db.
 Column(db.Da
@@ -830,24 +830,27 @@
     phone = 
+db.
 Column(phone
@@ -893,16 +893,19 @@
 sword = 
+db.
 Column('
@@ -1618,32 +1618,35 @@
     role_code = 
+db.
 Column(db.SmallI
@@ -1891,16 +1891,19 @@
 _code = 
+db.
 Column(d

use flask.ext.sqlalchemy fields, for discovery by alembic