コード例 #1
0
class TagArticle(JSONModel):
    KEY = 'TagArticle:%s'

    tag = StringProperty()
    article_id = IntegerProperty()
    time = IntegerProperty()

    def _get_watching_keys(self, inserting=False):
        return [self.KEY % self.tag]

    def _save_self(self, redis_client, inserting=False):
        key = self.KEY % self.tag
        if self.time:
            redis_client.zadd(key, self.time, self.article_id)
        else:
            redis_client.zrem(key, self.article_id)

    @classmethod
    def get_article_ids(cls, tag_name, cursor=None, limit=CONFIG.ARTICLES_PER_PAGE):
        redis_client = cls.redis_client
        key = cls.KEY % tag_name
        if cursor is None:
            return redis_client.zrevrange(key, 0, limit - 1, withscores=True, score_cast_func=int)
        else:
            return redis_client.zrevrangebyscore(key, '(%d' % cursor, 0, 0, limit, withscores=True, score_cast_func=int)

    @classmethod
    def get_articles(cls, category_name, cursor=None, limit=CONFIG.ARTICLES_PER_PAGE):
        article_ids_with_time = cls.get_article_ids(category_name, cursor)
        if article_ids_with_time:
            from .article import Article
            return Article.get_articles_and_next_cursor(article_ids_with_time, limit=limit)
        return [], None
コード例 #2
0
class Model4(Model1):
    a = StringProperty()
    b = IntegerProperty()
    c = BooleanProperty()
    d = FloatProperty()
    e = DateTimeProperty()
    f = DateTimeProperty(auto_now=True)
コード例 #3
0
class JSONTestModel(JSONModel):
    a = IntegerProperty()
    b = StringProperty()
    c = BooleanProperty()
    d = ListProperty()
    e = Property()

    def _save_self(self, redis_client, inserting=False):
        redis_client.hset(self.KEY, 'self', '1')

    def _save_relative(self, redis_client, inserting=False):
        redis_client.hset(self.KEY, 'relative', '1')
コード例 #4
0
class User(IDModel):
    email = StringProperty()
    name = StringProperty()
    site = StringProperty()

    def _save_relative(self, redis_client, inserting=False):
        if inserting:
            user_email = UserEmail(email=self.email, id=self.id)
            user_email.save(redis_client, inserting=True)

    def _get_relative_keys(self, inserting=False):
        if inserting:
            return [UserEmail.KEY]
        return []

    @classmethod
    def get_by_email(cls, email):
        user_id = UserEmail.get_user_id_by_email(email)
        if user_id:
            return cls.get_by_id(user_id)

    @classmethod
    def get_by_emails(cls, emails):
        user_ids = UserEmail.get_user_ids_by_emails(emails)
        user_ids = [
            int(user_id) for user_id in user_ids if user_id is not None
        ]
        if user_ids:
            users = cls.get_by_ids(user_ids)
            if users:
                return {user.id: user for user in users}
        return {}

    def get_avatar(self):
        return '//gravatar.com/avatar/' + md5(self.email).hexdigest()

    def is_admin(self):
        return self.id == CONFIG.ADMIN_USER_ID
コード例 #5
0
ファイル: keyword.py プロジェクト: zhangj47/Doodle
class KeywordArticle(JSONModel):
    keywords = StringProperty()
    article_id = IntegerProperty()

    def _get_watching_keys(self, inserting=False):
        return [self.KEY]

    def _save_self(self, redis_client, inserting=False):
        member = '%s:%d' % (self.keywords, self.article_id)
        redis_client.sadd(self.KEY, member)

    def delete(self, redis_client):
        member = '%s:%d' % (self.keywords, self.article_id)
        redis_client.srem(self.KEY, member)

    @classmethod
    def query_by_keyword(cls,
                         keyword,
                         result_limit=CONFIG.SEARCH_PAGE_SIZE,
                         search_limit=CONFIG.MAX_SEARCH_COUNT):
        cache_key = 'KeywordArticles:' + keyword
        cached_result = redis_cache_client.get(cache_key)
        if cached_result is not None:
            if not cached_result:
                return []
            try:
                article_ids = cached_result.split(',')
                return [int(article_id) for article_id in article_ids]
            except ValueError:
                logging.warning('Key "%s" contains wrong value: %s', cache_key,
                                cached_result)
                redis_cache_client.delete(cache_key)

        pattern = '*%s*:*' % keyword.lower()
        cursor, members = cls.redis_client.sscan(cls.KEY,
                                                 match=pattern,
                                                 count=search_limit)
        if members:
            article_ids = [
                member.rsplit(':', 1)[-1] for member in members[:result_limit]
            ]
            result = [int(article_id) for article_id in article_ids]
        else:
            article_ids = result = []

        redis_cache_client.set(cache_key,
                               ','.join(article_ids),
                               ex=CONFIG.DEFAULT_CACHE_TIME)

        return result
コード例 #6
0
ファイル: category.py プロジェクト: lau-jay/Doodle
class CategoryArticle(JSONModel):
    KEY = 'CategoryArticle:%s'

    category = StringProperty()
    article_id = IntegerProperty()
    time = IntegerProperty()

    def _get_watching_keys(self, inserting=False):
        return [self.KEY % self.category]

    def _save_self(self, redis_client, inserting=False):
        key = self.KEY % self.category
        if self.time:
            redis_client.zadd(key, self.time, self.article_id)
        else:
            redis_client.zrem(key, self.article_id)
コード例 #7
0
class UserEmail(JSONModel):
    email = StringProperty()
    id = IntegerProperty()

    @classmethod
    def get_user_id_by_email(cls, email):
        user_id = cls.redis_client.hget(cls.KEY, email)
        if user_id:
            return int(user_id)

    @classmethod
    def get_user_ids_by_emails(cls, emails):
        return cls.redis_client.hmget(cls.KEY, emails)

    def _save_self(self, redis_client, inserting=False):
        if self.id:
            redis_client.hset(self.KEY, self.email, self.id)
        else:
            redis_client.hdel(self.KEY, self.email)
コード例 #8
0
class ArticleURL(JSONModel):
    url = StringProperty()
    article_id = IntegerProperty()

    @classmethod
    def get_article_id_by_url(cls, url):
        article_id = cls.redis_client.hget(cls.KEY, url)
        if article_id:
            return int(article_id)

    @classmethod
    def get_by_url(cls, url):
        article_id = cls.get_article_id_by_url(url)
        if article_id:
            return cls(url=url, id=article_id)

    @classmethod
    def search_by_date(cls, date, limit=CONFIG.SEARCH_PAGE_SIZE):
        cursor, result = cls.redis_client.hscan(cls.KEY, 0, date + '*', limit)
        return result

    def _save_self(self, redis_client, inserting=False):
        if self.url:
            if self.article_id:
                redis_client.hset(self.KEY, self.url, self.article_id)
            else:
                redis_client.hdel(self.KEY, self.url)

    def _check_inserting(self):
        article_id = self.get_article_id_by_url(self.url)
        if article_id:
            article_id = int(article_id)
            if article_id != self.article_id:
                raise IntegrityError(
                    'article url "%s" has been used by article %d' %
                    (self.url, article_id))
コード例 #9
0
class IDTestModel(IDModel):
    a = IntegerProperty()
    b = StringProperty()
    c = BooleanProperty()
    d = ListProperty()
コード例 #10
0
class HashTestModel(HashModel):
    a = IntegerProperty()
    b = StringProperty()
    c = BooleanProperty()
    d = ListProperty()
コード例 #11
0
ファイル: comment.py プロジェクト: zhangj47/Doodle
class Comment(PublicModel):
    article_id = IntegerProperty()
    user_id = IntegerProperty()
    content = StringProperty()
    format = IntegerProperty()
    ua = ListProperty()
    time = DateTimeProperty(auto_now=True)

    HTML_PATTERN = re.compile('<.*?>|\&.*?\;', re.UNICODE)
    ROOT_LINK_PATTERN = re.compile(r'<a href="/([^"]*)">')
    ANCHOR_LINK_PATTERN = re.compile(r'<a href="#([^"]*)">')
    REPLY_LINK_PATTERN = re.compile(r'<a href="[^"]*#comment-id-(\d+)">')

    def html_content(self):
        return format_content(self.content, self.format)

    def html_content_with_full_url(self, article_url):  # for email and ATOM
        content = self.html_content()
        content = self.ROOT_LINK_PATTERN.sub(
            r'<a href="%s/\1">' % CONFIG.MAJOR_HOST_URL, content)
        content = self.ANCHOR_LINK_PATTERN.sub(
            r'<a href="%s#\1">' % article_url, content)
        return content

    def striped_html_content(self, length=CONFIG.LATEST_COMMENTS_LENGTH):
        result = self.HTML_PATTERN.sub(' ', self.html_content())
        return result[:length].strip()

    @classmethod
    def get_comments_of_article(cls,
                                article_id,
                                order,
                                page,
                                page_size=CONFIG.COMMENTS_PER_PAGE,
                                public_only=True):
        comment_ids = ArticleComments.get_by_article_id(
            article_id, order, page, page_size)
        if comment_ids:
            has_next_page = len(comment_ids) == page_size
            return Comment.get_by_ids(comment_ids,
                                      filter_empty=True,
                                      public_only=public_only), has_next_page
        return [], False

    @classmethod
    def get_latest_comments(cls, limit=CONFIG.LATEST_COMMENTS_FOR_SIDEBAR):
        comments_json = cls.redis_client.lrange(cls.KEY, -limit, -1)
        if comments_json:
            comments = []
            for comment_json in reversed(comments_json):
                comment = Comment.from_json(comment_json)
                if comment.public:
                    comments.append(comment)
            if comments:
                article_ids = set()
                user_ids = set()
                for comment in comments:
                    article_ids.add(comment.article_id)
                    user_ids.add(comment.user_id)
                articles = Article.get_by_ids(article_ids, public_only=True)
                if articles:
                    article_dict = {
                        article.id: article
                        for article in articles
                    }
                    users = User.get_by_ids(user_ids, filter_empty=True)
                    if users:
                        user_dict = {user.id: user for user in users}
                        return comments, article_dict, user_dict
        return [], {}, {}

    def _get_relative_keys(self, inserting=False):
        if inserting:
            return [ArticleComments.KEY % self.article_id]
        return []

    def _save_relative(self, redis_client, inserting=False):
        if inserting:
            ArticleComments.append_comment_to_article(redis_client, self.id,
                                                      self.article_id)
コード例 #12
0
class Article(PublicModel):
    title = StringProperty()
    url = StringProperty()
    content = StringProperty()
    format = IntegerProperty()
    category = StringProperty()
    tags = ListProperty()
    keywords = StringProperty()
    public = BooleanProperty()
    pub_time = DateTimeProperty(auto_now=True)
    mod_time = DateTimeProperty(auto_now=True)

    def quoted_url(self):
        return quoted_string(self.url)

    def category_name(self):
        if self.category:
            return Category.get_parent_path_and_name(self.category)[1]

    def html_summary(self):
        content = self.content
        if CONFIG.SUMMARY_DELIMETER.search(content):
            summary = CONFIG.SUMMARY_DELIMETER.split(content, 1)[0]
        elif CONFIG.SUMMARY_DELIMETER2.search(content):
            summary = CONFIG.SUMMARY_DELIMETER2.split(content, 1)[0]
        else:
            summary = content
        return format_content(summary, self.format)

    def html_content(self):
        content = self.content
        if CONFIG.SUMMARY_DELIMETER.search(content):
            content = CONFIG.SUMMARY_DELIMETER.sub('', content, 1)
        elif CONFIG.SUMMARY_DELIMETER2.search(content):
            content = CONFIG.SUMMARY_DELIMETER2.split(content, 1)[1]
        return format_content(content, self.format)

    def _get_relative_keys(self, inserting=False):
        relative_keys = [
            PublicArticlePublishTime.KEY, ArticleUpdateTime.KEY,
            PrivateArticlePublishTime.KEY
        ]
        if inserting:
            relative_keys.append(ArticleURL.KEY)
            if self.category:
                relative_keys.extend(
                    [Category.KEY, CategoryArticle.KEY % self.category])
            if self.tags:
                relative_keys.extend(
                    [TagArticle.KEY % tag for tag in self.tags])
            if self.keywords:
                relative_keys.append(KeywordArticle.KEY)
        else:
            origin_data = self._origin_data

            old_url = origin_data.get('url')
            if old_url and old_url != self.url:
                relative_keys.append(ArticleURL.KEY)

            old_category = origin_data.get('category') or ''
            if old_category != self.category:
                relative_keys.append(Category.KEY)
                if old_category:
                    relative_keys.append(CategoryArticle.KEY % old_category)
                if self.category:
                    relative_keys.append(CategoryArticle.KEY % self.category)

            old_tags = origin_data.get('tags') or []
            if old_tags != self.tags:
                relative_keys.extend([
                    TagArticle.KEY % tag for tag in set(self.tags + old_tags)
                ])

            old_keywords = origin_data.get('keywords')
            if old_keywords != self.keywords:
                relative_keys.append(KeywordArticle.KEY)
        return relative_keys

    def _save_relative(self, redis_client, inserting=False):
        if inserting:
            ArticleURL(url=self.url, article_id=self.id).save(redis_client,
                                                              inserting=True)
            if self.category:
                CategoryArticle(category=self.category,
                                article_id=self.id,
                                time=self.pub_time).save(redis_client,
                                                         inserting=True)
            if self.tags:
                for tag_name in self.tags:
                    TagArticle(tag=tag_name,
                               article_id=self.id,
                               time=self.pub_time).save(redis_client,
                                                        inserting=True)
            if self.keywords:
                KeywordArticle(keywords=self.keywords,
                               article_id=self.id).save(redis_client,
                                                        inserting=True)
        else:
            origin_data = self._origin_data

            old_url = origin_data.get('url')
            if old_url and old_url != self.url:
                ArticleURL(url=self.url,
                           article_id=self.id).save(redis_client,
                                                    inserting=True)
                ArticleURL(url=old_url, article_id=None).save(redis_client)

            old_category = origin_data.get('category')
            if old_category != self.category:
                cache_keys = []
                if self.category:
                    CategoryArticle(category=self.category,
                                    article_id=self.id,
                                    time=self.pub_time).save(redis_client,
                                                             inserting=True)
                    cache_keys.append(CategoryArticles.KEY % self.category)
                if old_category:
                    CategoryArticle(category=old_category,
                                    article_id=self.id,
                                    time=None).save(redis_client)
                    cache_keys.append(CategoryArticles.KEY % old_category)
                if cache_keys:
                    redis_client.delete(*cache_keys)

            old_tags = origin_data.get('tags')
            if old_tags != self.tags:
                old_tag_set = set(old_tags)
                tag_set = set(self.tags)
                added_tag_set = tag_set - old_tag_set
                removed_tag_set = old_tag_set - tag_set
                for tag_name in added_tag_set:
                    TagArticle(tag=tag_name,
                               article_id=self.id,
                               time=self.pub_time).save(redis_client,
                                                        inserting=True)
                for tag_name in removed_tag_set:
                    TagArticle(tag=tag_name, article_id=self.id,
                               time=None).save(redis_client)

            old_keywords = origin_data.get('keywords')
            if old_keywords != self.keywords:
                if self.keywords:
                    KeywordArticle(keywords=self.keywords,
                                   article_id=self.id).save(redis_client,
                                                            inserting=True)
                if old_keywords:
                    KeywordArticle(keywords=old_keywords,
                                   article_id=self.id).delete(redis_client)

        if self.public:
            PublicArticlePublishTime(article_id=self.id,
                                     time=self.pub_time).save(redis_client)
            ArticleUpdateTime(article_id=self.id,
                              time=self.mod_time).save(redis_client)
            PrivateArticlePublishTime(article_id=self.id,
                                      time=None).save(redis_client)
        else:
            PublicArticlePublishTime(article_id=self.id,
                                     time=None).save(redis_client)
            ArticleUpdateTime(article_id=self.id, time=None).save(redis_client)
            PrivateArticlePublishTime(article_id=self.id,
                                      time=self.pub_time).save(redis_client)

    @classmethod
    def exist_url(cls, url):
        return ArticleURL.get_article_id_by_url(url) is not None

    @classmethod
    def get_by_url(cls, url):
        article_id = ArticleURL.get_article_id_by_url(url)
        if article_id:
            return cls.get_by_id(article_id)

    @classmethod
    def search(cls, date, url):
        article_ids = PublicArticlePublishTime.get_article_ids_by_data(date)
        if article_ids:
            articles = Article.get_by_ids(article_ids, public_only=True)
            if articles:
                if len(articles) == 1:
                    return articles[0].quoted_url()
                urls = [article.quoted_url() for article in articles]
                matched_urls = get_close_matches(url, urls, 1, 0)
                return matched_urls[0]

    @classmethod
    def get_articles_and_next_cursor(cls,
                                     article_ids_with_time,
                                     public_only=True,
                                     limit=CONFIG.ARTICLES_PER_PAGE):
        article_ids = [
            int(article_id) for article_id, timestamp in article_ids_with_time
        ]
        if len(article_ids) == limit:
            next_cursor = article_ids_with_time[-1][1]
        else:
            next_cursor = None
        articles = Article.get_by_ids(article_ids,
                                      filter_empty=True,
                                      public_only=public_only)
        return articles, next_cursor

    @classmethod
    def get_articles_for_homepage(cls,
                                  cursor=None,
                                  limit=CONFIG.ARTICLES_PER_PAGE):
        article_ids_with_time = PublicArticlePublishTime.get_article_ids(
            cursor, limit=limit)
        if article_ids_with_time:
            return cls.get_articles_and_next_cursor(article_ids_with_time,
                                                    limit=limit)
        return [], None

    @classmethod
    def get_unpublished_articles(cls,
                                 page,
                                 page_size=CONFIG.ARTICLES_PER_PAGE):
        article_ids = PrivateArticlePublishTime.get_article_ids_for_page(
            page, page_size)
        if article_ids:
            return cls.get_by_ids(article_ids, filter_empty=True)
        return []

    @classmethod
    def get_articles_count(cls, public=True):
        time_class = PublicArticlePublishTime if public else PrivateArticlePublishTime
        return time_class.get_count()

    @classmethod
    def get_articles_for_feed(cls, limit=CONFIG.ARTICLES_FOR_FEED):
        if CONFIG.SORT_FEED_BY_UPDATE_TIME:
            article_ids = ArticleUpdateTime.get_article_ids_for_page(1, limit)
        else:
            article_ids = PublicArticlePublishTime.get_article_ids(
                None, with_time=False, limit=limit)
        if article_ids:
            return cls.get_by_ids(article_ids, public_only=True)
        return []

    def get_previous_article(self):
        time_class = PublicArticlePublishTime if self.public else PrivateArticlePublishTime
        article_id = time_class.get_previous_article_id(self.pub_time)
        if article_id:
            return Article.get_by_id(article_id)

    def get_next_article(self):
        time_class = PublicArticlePublishTime if self.public else PrivateArticlePublishTime
        article_id = time_class.get_next_article_id(self.pub_time)
        if article_id:
            return Article.get_by_id(article_id)

    def get_nearby_articles(self):
        time_class = PublicArticlePublishTime if self.public else PrivateArticlePublishTime
        previous_article_id = time_class.get_previous_article_id(self.pub_time)
        next_article_id = time_class.get_next_article_id(self.pub_time)
        if previous_article_id:
            if next_article_id:
                return Article.get_by_ids(
                    (previous_article_id, next_article_id))
            else:
                return Article.get_by_id(previous_article_id), None
        else:
            if next_article_id:
                return None, Article.get_by_id(next_article_id)
            else:
                return None, None