def index():
def view_mail_daily_products(receiver):
def user_subscribe_event(msg):
def user_event_day_top_voted(msg):
def user_event_week_top_voted(msg):
def user_event_month_top_voted(msg):
def user_event_search(msg):
def user_event_mail(msg):
def user_event_help(msg):
def user_event_feedback(msg):
def push_welcome_info(msg):
def push_help_info(msg):
def push_thanks_info(msg):
def push_products(msg, products):
def mail_products(msg, products, receiver):
def push_day_top_voted_products(msg):
def push_week_top_voted_products(msg):
def push_month_top_voted_products(msg):
def push_search_result_products(msg):
def mail_day_top_voted_products(msg):
def weixin_access_verify():
def weixin_msg():
def verification(req):
def parse_msg(rawmsgstr):
def response_text_msg(msg, content):
def response_products_msg(msg, products):
EVENT_PROCS = [
    (user_subscribe_event, push_welcome_info),
    (user_event_day_top_voted, push_day_top_voted_products),
    (user_event_week_top_voted, push_week_top_voted_products),
    (user_event_month_top_voted, push_month_top_voted_products),
    (user_event_search, push_search_result_products),
    (user_event_mail, mail_day_top_voted_products),
    (user_event_help, push_help_info),
    (user_event_feedback, push_thanks_info),
] def _tag_names(post):
def _render_tags(post):
def _render_contributors(contributers, postid, locked_by, field):
def _post_aquire_translate(request):
def translate():
def index():
def posts():
def post_intro(postid):
def pull():
def lock():
def tags():
def tags_name(tagname):
def dailybriefing(day):
def get_qiniu_token(): def profile(username):
def login():
def reauth():
def logout():
def register():
def forgot_password():
def reset_password(token):
def collections():
def translations():
def settings():
def settings_email():
def settings_password():
def weibo_auth():
def weibo_auth_callback(): class Guest(AnonymousUserMixin):
    @property
    def permissions(self):
        return self.get_permissions()

    def get_permissions(self, exclude=None):
        """Returns a dictionary with all permissions the user has"""
        exclude = exclude or []
        exclude.extend(['id', 'name', 'description'])

        perms = {}
        # Get the Guest group
        group = Group.query.filter_by(guest=True).first()
        for c in group.__table__.columns:
            if c.name in exclude:
                continue
            perms[c.name] = getattr(group, c.name)
        return perms class User(db.Model, UserMixin):
    __tablename__ = "users"
    __searchable__ = ['username', 'email']

    # field map between User and Weibo API users/show json data
    FIELD_MAP = {
        "wbuid": "id",
        "username": "screen_name",
        "gender": "gender",
        "website": "url",
        "notes": "description",
        "nickname": "name",
        "avatar": "avatar_large",
    }

    id = db.Column(db.Integer, primary_key=True)
    wbuid = db.Column(db.String(16))
    username = db.Column(db.String(200), unique=True, nullable=False)
    email = db.Column(db.String(200), unique=True, nullable=False)
    _password = db.Column('password', db.String(120), nullable=False)
    date_joined = db.Column(db.DateTime, default=datetime.utcnow())
    lastseen = db.Column(db.DateTime, default=datetime.utcnow())
    birthday = db.Column(db.DateTime)
    gender = db.Column(db.String(10))
    website = db.Column(db.String(512))
    location = db.Column(db.String(100))
    nickname = db.Column(db.String(100))
    avatar = db.Column(db.String(512))
    notes = db.Column(db.Text)

    theme = db.Column(db.String(15))

    primary_group_id = db.Column(db.Integer, db.ForeignKey('groups.id'),
                                 nullable=False)

    primary_group = db.relationship('Group', lazy="joined",
                                    backref="user_group", uselist=False,
                                    foreign_keys=[primary_group_id])

    secondary_groups = \
        db.relationship('Group',
                        secondary=groups_users,
                        primaryjoin=(groups_users.c.user_id == id),
                        backref=db.backref('users', lazy='dynamic'),
                        lazy='dynamic')

    ctagline_products = \
        db.relationship('Product',
                        secondary=users_translated,
                        primaryjoin=(users_translated.c.user_id == id),
                        backref=db.backref('ctagline_editors', lazy='dynamic'),
                        lazy='dynamic')

    cintro_products = \
        db.relationship('Product',
                        secondary=users_introduced,
                        primaryjoin=(users_introduced.c.user_id == id),
                        backref=db.backref('cintro_editors', lazy='dynamic'),
                        lazy='dynamic')

    @property
    def url(self):
        """Returns the url for the user"""
        return url_for("user.profile", username=self.username)

    @property
    def permissions(self):
        """Returns the permissions for the user"""
        return self.get_permissions()

    @property
    def days_registered(self):
        """Returns the amount of days the user is registered."""
        days_registered = (datetime.utcnow() - self.date_joined).days
        if not days_registered:
            return 1
        return days_registered

    # Methods
    def __repr__(self):
        """Set to a unique key specific to the object in the database.
        Required for cache.memoize() to work across requests.
        """
        return "<{} {}>".format(self.__class__.__name__, self.username)

    def _get_password(self):
        """Returns the hashed password"""
        return self._password

    def _set_password(self, password):
        """Generates a password hash for the provided 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):
        """Check passwords. If passwords match it returns true, else false"""

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

    @classmethod
    def authenticate(cls, login, password):
        """A classmethod for authenticating users
        It returns true if the user exists and has entered a correct password

        :param login: This can be either a username or a email address.
        :param password: The password that is connected to username and email.
        """

        user = cls.query.filter(db.or_(User.username == login,
                                       User.email == login)).first()

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

    def _make_token(self, data, timeout):
        s = Serializer(current_app.config['SECRET_KEY'], timeout)
        return s.dumps(data)

    def _verify_token(self, token):
        s = Serializer(current_app.config['SECRET_KEY'])
        data = None
        expired, invalid = False, False
        try:
            data = s.loads(token)
        except SignatureExpired:
            expired = True
        except Exception:
            invalid = True
        return expired, invalid, data

    def make_reset_token(self, expiration=3600):
        """Creates a reset token. The duration can be configured through the
        expiration parameter.

        :param expiration: The time in seconds how long the token is valid.
        """
        return self._make_token({'id': self.id, 'op': 'reset'}, expiration)

    def verify_reset_token(self, token):
        """Verifies a reset token. It returns three boolean values based on
        the state of the token (expired, invalid, data)

        :param token: The reset token that should be checked.
        """

        expired, invalid, data = self._verify_token(token)
        if data and data.get('id') == self.id and data.get('op') == 'reset':
            data = True
        else:
            data = False
        return expired, invalid, data

    def add_to_group(self, group):
        """Adds the user to the `group` if he isn't in it.

        :param group: The group which should be added to the user.
        """

        if not self.in_group(group):
            self.secondary_groups.append(group)
            db.session.commit()
            self.invalidate_cache()
            return self

    def remove_from_group(self, group):
        """Removes the user from the `group` if he is in it.

        :param group: The group which should be removed from the user.
        """

        if self.in_group(group):
            self.secondary_groups.remove(group)
            db.session.commit()
            self.invalidate_cache()
            return self

    def in_group(self, group):
        """Returns True if the user is in the specified group

        :param group: The group which should be checked.
        """

        return self.secondary_groups.filter(
            groups_users.c.group_id == group.id).count() > 0

    @cache.memoize(timeout=max_integer)
    def get_permissions(self, exclude=None):
        """Returns a dictionary with all the permissions the user has.

        :param exclude: a list with excluded permissions. default is None.
        """

        exclude = exclude or []
        exclude.extend(['id', 'name', 'description'])

        perms = {}
        groups = self.secondary_groups.all()
        groups.append(self.primary_group)
        for group in groups:
            for c in group.__table__.columns:
                # try if the permission already exists in the dictionary
                # and if the permission is true, set it to True
                try:
                    if not perms[c.name] and getattr(group, c.name):
                        perms[c.name] = True

                # if the permission doesn't exist in the dictionary
                # add it to the dictionary
                except KeyError:
                    # if the permission is in the exclude list,
                    # skip to the next permission
                    if c.name in exclude:
                        continue
                    perms[c.name] = getattr(group, c.name)
        return perms

    def invalidate_cache(self):
        """Invalidates this objects cached metadata."""

        cache.delete_memoized(self.get_permissions, self)

    def in_ctagline_list(self, product):
        """check does product in users translated list"""

        return self.ctagline_products.filter(
            users_translated.c.product_postid == product.postid).count() > 0

    def add_ctagline_product(self, product):
        """add a product to users translate list"""
        if not self.in_ctagline_list(product):
            self.ctagline_products.append(product)
            db.session.commit()
            return self

    def in_cintro_list(self, product):
        """check does product in users translated list"""

        return self.cintro_products.filter(
            users_introduced.c.product_postid == product.postid).count() > 0

    def add_cintro_product(self, product):
        """add a product to users translate list"""
        if not self.in_cintro_list(product):
            self.cintro_products.append(product)
            db.session.commit()
            return self

    @classmethod
    def from_json(cls, json):
        """
        Create User from weibo json data
        """
        u = User()
        for k, v in User.FIELD_MAP.items():
            if k == 'gender':
                if json[v] == 'm':
                    u.gender = 'Male'
                elif json[v] == 'f':
                    u.gender = 'Female'
            else:
                setattr(u, k, json[v])

        # special field
        u.email = u.username + '@example.org'
        u.password = ''.join(random.sample( \
            '1234567890zyxwvutsrqponmlkjihgfedcba',8))
        member_group = Group.query.filter_by(member=True).first()
        u.primary_group_id = member_group.id
        return u

    def save(self):
        """Saves a user"""

        db.session.add(self)
        db.session.commit()
        return self

    def delete(self):
        """Deletes the User."""

        db.session.delete(self)
        db.session.commit()

        return self def render_markup(text):
    """Renders the given text as markdown

    :param text: The text to be rendered
    """
    if text is None:
        text = ""
    return render_markdown(text, extras=['tables']) def root_url_prefix(app, prefix_key):
    """ return the url prefix """
    return app.config["ROOT_URL_PREFIX"] + app.config[prefix_key] def is_online(user):
    """A simple check to see if the user was online within a specified
    time range

    :param user: The user who needs to be checked
    """
    return user.lastseen >= time_diff() def can_translate(user):
    """Checks if a user translate a product"""

    return user.permissions['perm_translate'] def can_comment(user):
    """Checks if a user can post comments to product"""

    return user.permissions['perm_comment'] def can_review(user):
    """Checks if a user can review a translate"""

    return user.permissions['perm_review'] def can_report(user):
    """Checks if a user can generate a daily report"""

    return user.permissions['perm_report'] def can_topic(user):
    """Checks if a user can generate a topic"""

    return user.permissions['perm_topic'] def can_setgroup(user):
    """Checks if a user can change other user's secondary group"""

    return user.permissions['perm_setgroup'] def format_date(d):
    """ format a datetime.date object to string """
    return '%04d-%02d-%02d' % (d.year, d.month, d.day) def is_moderator(user):
    """Returns ``True`` if the user is in a moderator group.

    :param user: The user who should be checked.
    """
    return user.permissions['mod'] or user.permissions['admin'] def is_admin(user):
    """Returns ``True`` if the user is a administrator.

    :param user:  The user who should be checked.
    """
    return user.permissions['admin'] class DefaultConfig(object):

    ## Instance path is used to store database and config file
    INSTANCE_PATH = '/tmp'

    DEBUG = False
    TESTING = False

    # Logs
    # If SEND_LOGS is set to True, the admins (see the mail configuration) will
    # recieve the error logs per email.
    SEND_LOGS = False

    # The filename for the info and error logs. The logfiles are stored at
    # weixin_producthunt/logs
    INFO_LOG = "info.log"
    ERROR_LOG = "error.log"

    # Default Database
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + INSTANCE_PATH + '/' + \
                              'productporter.sqlite'

    # This will print all SQL statements
    SQLALCHEMY_ECHO = False

    # Security
    # This is the secret key that is used for session signing.
    # You can generate a secure key with os.urandom(24)
    SECRET_KEY = 'secret key'

    # Protection against form post fraud
    WTF_CSRF_ENABLED = True
    WTF_CSRF_SECRET_KEY = "reallyhardtoguess"

    # Auth
    LOGIN_VIEW = "user.login"
    REAUTH_VIEW = "user.reauth"
    LOGIN_MESSAGE_CATEGORY = "error"

    # URL Prefixes. If you deply application on example.com/app1/app2
    # then, the value here should be app1/app2
    ROOT_URL_PREFIX = ""
    # Blueprints URL Prefixs.
    PRODUCT_URL_PREFIX = ""
    WEIXIN_URL_PREFIX = "/weixin"
    USER_URL_PREFIX = "/user"

    ## Mail
    MAIL_SERVER = "localhost"
    MAIL_USERNAME = "noreply@example.org"
    MAIL_PASSWORD = ""
    MAIL_SENDER = "noreply@example.org"
    # The user who should recieve the error logs
    ADMINS = ["your_admin_user@gmail.com"]

    ## ProductHuntAPI key and secret
    PH_API_KEY = "your_producthunt_api_key"
    PH_API_SECRET = "your_producthunt_api_secret"
    ## if you do not have ProductHuntAPI key and secret plesae use local data
    ## to run unit test
    PH_API_USE_SAMPLE_DATA = False

    ## weixin token
    WEIXIN_UNITTEST = False
    WEIXIN_TOKEN = "your_weixin_token"

    # Caching
    CACHE_TYPE = "simple"
    CACHE_DEFAULT_TIMEOUT = 60

    ## theme
    DEFAULT_THEME = ""

    WEIBO_APP_KEY = '' # your weibo app key
    WEIBO_APP_SECRET = '' # your weibo app secret

    # qiniu key
    # if you change bucket ,you should also change js qiniu config
    QINIU_ACCESS_KEY = ""
    QINIU_SECRET_KEY = ""
    QINIU_BUCKET = ""
import os
import logging
import datetime
from flask import Flask
from productporter.weixin.views import weixin
from productporter.product.views import product
from productporter.user.views import user
from productporter.user.models import Guest, User
from productporter.utils.helper import render_markup, root_url_prefix, \
        is_online, can_translate, can_comment, can_review, can_report, \
        can_topic, can_setgroup, format_date, is_moderator, is_admin
from productporter.extensions import db, cache, themes, login_manager, migrate
from productporter.configs.default import DefaultConfig
from flask.ext.login import current_user
    from logging.handlers import SMTPHandler
# -*- coding: utf-8 -*-
"""
    productporter.app
    ~~~~~~~~~~~~~~~~~

    manages the app creation and configuration process

    :copyright: (c) 2014 by the ProductPorter Team.
    :license: BSD, see LICENSE for more details.
"""


# extensions
# default config

def create_app(config=None):
    """
    Creates the app.
    """
    static_url_path = ''
    instance_path = None
    if config is None:
        static_url_path = DefaultConfig.ROOT_URL_PREFIX + '/static'
        instance_path = DefaultConfig.INSTANCE_PATH
    else:
        static_url_path = config.ROOT_URL_PREFIX + '/static'
        instance_path = config.INSTANCE_PATH
    # Initialize the app
    app = Flask("productporter",
        static_url_path=static_url_path,
        instance_path=instance_path)

    # Use the default config and override it afterwards
    app.config.from_object('productporter.configs.default.DefaultConfig')
    # Update the config
    app.config.from_object(config)

    configure_blueprints(app)
    configure_extensions(app)
    configure_template_filters(app)
    configure_context_processors(app)
    configure_before_handlers(app)
    configure_errorhandlers(app)
    configure_logging(app)

    return app

def configure_blueprints(app):
    """
    Configures the blueprints
    """
    app.register_blueprint(weixin, url_prefix=root_url_prefix(app, 'WEIXIN_URL_PREFIX'))
    app.register_blueprint(product, url_prefix=root_url_prefix(app, 'PRODUCT_URL_PREFIX'))
    app.register_blueprint(user, url_prefix=root_url_prefix(app, 'USER_URL_PREFIX'))

def configure_extensions(app):
    """
    Configures the extensions
    """

    # Flask-SQLAlchemy
    db.init_app(app)

    # Flask-Migrate
    migrate.init_app(app, db)

    # Flask-Cache
    cache.init_app(app)

    # Flask-Themes
    themes.init_themes(app, app_identifier="productporter")

    # Flask-Login
    login_manager.login_view = app.config["LOGIN_VIEW"]

    login_manager.refresh_view = app.config["REAUTH_VIEW"]