def get(self, url, date, _from_head=False): article = Article.get_by_url(url) if not article: redirect_url = Article.search(date, url) if redirect_url: self.redirect(CONFIG.BLOG_HOME_RELATIVE_PATH + redirect_url, permanent=True) return else: raise HTTPError(404) if not (article.public or self.is_admin): raise HTTPError(404) previous_article, next_article = article.get_nearby_articles() if _from_head or self.request.headers.get('If-None-Match') or self.is_spider: hit_count = ArticleHitCount.get(article.id) else: hit_count = ArticleHitCount.increase(article.id) replies = ArticleComments.get_comment_count_of_article(article.id) self.set_cache(CONFIG.DEFAULT_CACHE_TIME, is_public=article.public) self.render('web/article.html', { 'title': article.title, 'page': 'article', 'article': article, 'previous_article': previous_article, 'next_article': next_article, 'hits': hit_count, 'replies': replies })
def get(self, url, date, _from_head=False): article = Article.get_by_url(url) if not article: redirect_url = Article.search(date, url) if redirect_url: self.redirect(CONFIG.BLOG_HOME_RELATIVE_PATH + redirect_url, permanent=True) return else: raise HTTPError(404) if not (article.public or self.is_admin): raise HTTPError(404) previous_article, next_article = article.get_nearby_articles() if _from_head or self.request.headers.get( 'If-None-Match') or self.is_spider: hit_count = ArticleHitCount.get(article.id) else: hit_count = ArticleHitCount.increase(article.id) replies = ArticleComments.get_comment_count_of_article(article.id) self.set_cache(CONFIG.DEFAULT_CACHE_TIME, is_public=article.public) self.render( 'web/article.html', { 'title': article.title, 'page': 'article', 'article': article, 'previous_article': previous_article, 'next_article': next_article, 'hits': hit_count, 'replies': replies })
def get(self, article_id, order, page): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if not article: raise HTTPError(404) if not article.public: self.set_cache(is_public=False) if not self.is_admin: raise HTTPError(404) page = int(page) comments_list = [] comments, has_next_page = Comment.get_comments_of_article( article_id, order == 'asc', page) if comments: user_ids = {comment.user_id for comment in comments} users = User.get_by_ids(user_ids, filter_empty=True) if users: user_dict = {user.id: user for user in users} else: user_dict = {} for comment in comments: user = user_dict.get(comment.user_id) if user: user_name = user.name user_site = escape(user.site) if user.site else '' else: user_name = u'匿名用户' user_site = '' comments_list.append({ 'user_name': user_name, 'url': user_site, 'img': user.get_avatar(), 'ua': comment.ua, 'time': formatted_time(timestamp_to_datetime(comment.time)), 'id': comment.id, 'content': comment.html_content() }) output = {'comments': comments_list} if has_next_page: output['next_page'] = page + 1 self.write_json(output)
def get(self): self.set_content_type('atom') # todo: handler subscribers articles = Article.get_articles_for_feed() if articles: last_updated = iso_time_format(timestamp_to_datetime(articles[0].mod_time)) else: last_updated = iso_time_now() self.render('web/feed.xml', { 'articles': articles, 'last_updated': last_updated })
def get(self, article_id): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if article: if not article.public: self.set_cache(is_public=False) if not self.is_admin: raise HTTPError(404) self.redirect(CONFIG.BLOG_HOME_RELATIVE_PATH + article.url, permanent=True) else: raise HTTPError(404)
def get(self, article_id, order, page): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if not article: raise HTTPError(404) if not article.public: self.set_cache(is_public=False) if not self.is_admin: raise HTTPError(404) page = int(page) comments_list = [] comments, has_next_page = Comment.get_comments_of_article(article_id, order == 'asc', page) if comments: user_ids = {comment.user_id for comment in comments} users = User.get_by_ids(user_ids, filter_empty=True) if users: user_dict = {user.id: user for user in users} else: user_dict = {} for comment in comments: user = user_dict.get(comment.user_id) if user: user_name = user.name user_site = escape(user.site) if user.site else '' else: user_name = u'匿名用户' user_site = '' comments_list.append({ 'user_name': user_name, 'url': user_site, 'img': user.get_avatar(), 'ua': comment.ua, 'time': formatted_time(timestamp_to_datetime(comment.time)), 'id': comment.id, 'content': comment.html_content() }) output = {'comments': comments_list} if has_next_page: output['next_page'] = page + 1 self.write_json(output)
def get(self): articles, next_cursor = Article.get_articles_for_homepage(self.cursor) if articles: article_ids = [article.id for article in articles] hit_counts = ArticleHitCount.get_by_ids(article_ids) replies_dict = ArticleComments.get_comment_count_of_articles(article_ids) else: hit_counts = replies_dict = {} self.set_cache(CONFIG.DEFAULT_CACHE_TIME, is_public=True) self.render('web/home.html', { 'title': CONFIG.BLOG_TITLE, 'page': 'home', 'articles': articles, 'hit_counts': hit_counts, 'replies_dict': replies_dict, 'next_cursor': next_cursor })
def get(self, article_id): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if not article: raise HTTPError(404) categories = Category.get_all_names_with_paths() tags = Tag.get_all() self.render('admin/edit_article.html', { 'title': u'编辑《%s》' % article.title, 'page': 'edit_article', 'article': article, 'categories': categories, 'tags': sorted(tags) })
def get(self): articles, next_cursor = Article.get_articles_for_homepage(self.cursor) if articles: article_ids = [article.id for article in articles] hit_counts = ArticleHitCount.get_by_ids(article_ids) replies_dict = ArticleComments.get_comment_count_of_articles( article_ids) else: hit_counts = replies_dict = {} self.set_cache(CONFIG.DEFAULT_CACHE_TIME, is_public=True) self.render( 'web/home.html', { 'title': CONFIG.BLOG_TITLE, 'page': 'home', 'articles': articles, 'hit_counts': hit_counts, 'replies_dict': replies_dict, 'next_cursor': next_cursor })
def get(self, page): if page: page = int(page) else: page = 1 articles = Article.get_unpublished_articles(page) if articles: article_ids = [article.id for article in articles] hit_counts = ArticleHitCount.get_by_ids(article_ids) replies_dict = ArticleComments.get_comment_count_of_articles(article_ids) else: hit_counts = replies_dict = {} self.render('admin/unpublished_articles.html', { 'title': u'未发布的文章', 'page': 'unpublished_articles', 'articles': articles, 'hit_counts': hit_counts, 'replies_dict': replies_dict, 'next_page': page + 1 })
def get(self): keywords = self.get_argument('keywords', None) if keywords: article_ids = KeywordArticle.query_by_keyword(keywords) if article_ids: articles = Article.get_by_ids(article_ids, public_only=True) article_ids = [article.id for article in articles] hit_counts = ArticleHitCount.get_by_ids(article_ids) replies_dict = ArticleComments.get_comment_count_of_articles(article_ids) else: articles = [] hit_counts = replies_dict = {} self.set_cache(CONFIG.DEFAULT_CACHE_TIME, is_public=True) self.render('web/search.html', { 'title': u'搜索《%s》' % keywords, 'page': 'search', 'keywords': keywords, 'articles': articles, 'hit_counts': hit_counts, 'replies_dict': replies_dict }) else: raise HTTPError(400)
def post(self, article_id): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if not article: raise HTTPError(404) title = self.get_argument('title', None) if title: article.title = title now = None pub_time = self.get_argument('pub_time', None) if pub_time: pub_time = parse_time(pub_time) if pub_time: pub_timestamp = datetime_to_timestamp(pub_time) else: pub_time = datetime.utcnow() pub_timestamp = now = datetime_to_timestamp(pub_time) article.pub_time = pub_timestamp mod_time = self.get_argument('mod_time', None) if mod_time: mod_time = parse_time(mod_time) if mod_time: mod_timestamp = datetime_to_timestamp(mod_time) else: mod_timestamp = now article.mod_time = mod_timestamp url = self.get_argument('url', None) # todo: check url pattern if not url: formatted_date = formatted_date_for_url(pub_time) if CONFIG.REPLACE_SPECIAL_CHARACTERS_FOR_URL: url = formatted_date + replace_special_characters_for_url(article.title) else: url = formatted_date + article.title if article.url != url: if Article.exist_url(url): self.finish('编辑失败,同链接的文章已存在') return else: article.url = url article.public = self.get_argument('public', None) == 'on' bbcode = self.get_argument('bbcode', None) == 'on' html = self.get_argument('html', None) == 'on' article.format = bbcode * ContentFormatFlag.BBCODE + html * ContentFormatFlag.HTML article.content = self.get_argument('content').replace('\r\n', '\n').replace('\r', '\n') category_name = self.get_argument('category', None) if category_name: if not Category.exists(category_name): self.finish('发表失败,分类不存在') return article.category = category_name or None tag_names = self.get_arguments('tags') if tag_names: tag_names = set(tag_names) tag_names.discard('') article.tags = sorted(tag_names) if tag_names else None keywords = self.get_argument('keywords', None) if keywords: keywords = keywords.lower() article.keywords = keywords try: article.save() except IntegrityError: quoted_url = article.quoted_url() self.finish('编辑失败,已有<a href="%s%s">相同链接的文章</a>存在' % (CONFIG.BLOG_HOME_RELATIVE_PATH, quoted_url)) except Exception: logging.exception('failed to save modified article') self.finish('编辑失败') else: quoted_url = article.quoted_url() # 增加时间戳,已避免缓存造成影响,打开后会被 history.replaceState 去掉 query 部分 self.finish('编辑成功,查看<a href="%s%s?t=%d">更新后的文章</a>' % (CONFIG.BLOG_HOME_RELATIVE_PATH, quoted_url, int(time.time())))
def post(self, article_id): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if not (article and (article.public or self.is_admin)): raise HTTPError(404) content = self.get_argument('comment', None) if not content: raise HTTPError(400) content = content.strip().replace('\r\n', '\n').replace('\r', '\n') if not content: raise HTTPError(400) if self.get_argument('bbcode', None) == 'on': format = ContentFormatFlag.BBCODE else: format = ContentFormatFlag.PLAIN ua = [] browser, platform, os, os_version, vendor = self.ua_details if platform: if platform in ('iPhone', 'iPod Touch', 'iPad', 'Android'): ua.append(platform) elif self.is_mobile: ua.append('mobile') else: if self.is_mobile: ua.append('mobile') elif os and os in ('Windows', 'Mac OS', 'Linux', 'FreeBSD'): ua.append(os) if browser: if browser == 'Internet Explorer': ua.append('IE') elif browser in ('Firefox', 'Chrome', 'Safari', 'Opera'): ua.append(browser) elif browser == 'Mobile Safari': ua.append('Safari') elif browser in ('Opera Mini', 'Opera Mobile'): ua.append('Opera') # todo: check last comment current_user_id = self.current_user_id comment = Comment(article_id=article_id, user_id=current_user_id, content=content, format=format, ua=ua, public=True) comment.save(inserting=True) current_user = self.current_user self.write_json({ 'comment': { 'user_name': current_user.name, 'url': current_user.site, 'img': current_user.get_avatar(), 'ua': comment.ua, 'time': formatted_time(timestamp_to_datetime(comment.time)), 'id': comment.id, 'content': comment.html_content() } }) FragmentCache.delete('sidebar') if CONFIG.MAILGUN_API_KEY: url = html_content = html_body = title = '' if CONFIG.ADMIN_EMAIL and not self.is_admin: url = u'%s%s#comment-id-%d' % (CONFIG.BLOG_HOME_FULL_URL, article.quoted_url(), comment.id) html_content = comment.html_content_with_full_url(url) html_body = u'%s 在 <a href="%s">%s</a> 评论道:<br/>%s' % (escape( current_user.name), url, article.title, html_content) title = u'Re: ' + article.title yield send_email(to=CONFIG.ADMIN_EMAIL, subject=title, html=html_body) if format != ContentFormatFlag.PLAIN: if not html_content: url = u'%s%s#comment-id-%d' % (CONFIG.BLOG_HOME_FULL_URL, article.quoted_url(), comment.id) html_content = comment.html_content_with_full_url(url) comment_ids = set( int(comment_id) for comment_id in Comment.REPLY_LINK_PATTERN.findall(html_content)) if comment_ids: comments = Comment.get_by_ids(comment_ids) if comments: user_ids = {comment.user_id for comment in comments} user_ids.discard( CONFIG.ADMIN_USER_ID) # already sent to admin if user_ids: users = User.get_by_ids(user_ids) if users: if not html_body: html_body = u'%s 在 <a href="%s">%s</a> 评论道:<br/>%s<hr/>您收到这封邮件是因为有人回复了您的评论。您可前往原文回复,请勿直接回复该邮件。' % ( escape(current_user.name), url, article.title, html_content) title = u'Re: ' + article.title else: html_body += u'<hr/>您收到这封邮件是因为有人回复了您的评论。您可前往原文回复,请勿直接回复该邮件。' for user in users: yield send_email(to=user.email, subject=title, html=html_body)
# -*- coding: utf-8 -*- from doodle.core.models.article import Article, ArticleUpdateTime, PublicArticlePublishTime, PrivateArticlePublishTime from doodle.core.models.category import CategoryArticle from doodle.core.models.tag import TagArticle from doodle.core.redis_client import redis_main_client redis_main_client.delete(PublicArticlePublishTime.KEY, ArticleUpdateTime.KEY, PrivateArticlePublishTime.KEY) articles_data = redis_main_client.lrange(Article.KEY, 0, -1) for article_data in articles_data: article = Article.from_json(article_data) if article.public: PublicArticlePublishTime(article_id=article.id, time=article.pub_time).save(redis_main_client) ArticleUpdateTime(article_id=article.id, time=article.mod_time).save(redis_main_client) PrivateArticlePublishTime(article_id=article.id, time=None).save(redis_main_client) else: PublicArticlePublishTime(article_id=article.id, time=None).save(redis_main_client) ArticleUpdateTime(article_id=article.id, time=None).save(redis_main_client) PrivateArticlePublishTime(article_id=article.id, time=article.pub_time).save(redis_main_client) if article.category: CategoryArticle(category=article.category, article_id=article.id, time=article.pub_time).save(redis_main_client, inserting=True) for tag_name in article.tags: TagArticle(tag=tag_name, article_id=article.id, time=article.pub_time).save(redis_main_client, inserting=True)
def post(self, article_id): article_id = int(article_id) if not article_id: raise HTTPError(404) article = Article.get_by_id(article_id) if not (article and (article.public or self.is_admin)): raise HTTPError(404) content = self.get_argument('comment', None) if not content: raise HTTPError(400) content = content.strip().replace('\r\n', '\n').replace('\r', '\n') if not content: raise HTTPError(400) if self.get_argument('bbcode', None) == 'on': format = ContentFormatFlag.BBCODE else: format = ContentFormatFlag.PLAIN ua = [] browser, platform, os, os_version, vendor = self.ua_details if platform: if platform in ('iPhone', 'iPod Touch', 'iPad', 'Android'): ua.append(platform) elif self.is_mobile: ua.append('mobile') else: if self.is_mobile: ua.append('mobile') elif os and os in ('Windows', 'Mac OS', 'Linux', 'FreeBSD'): ua.append(os) if browser: if browser == 'Internet Explorer': ua.append('IE') elif browser in ('Firefox', 'Chrome', 'Safari', 'Opera'): ua.append(browser) elif browser == 'Mobile Safari': ua.append('Safari') elif browser in ('Opera Mini', 'Opera Mobile'): ua.append('Opera') # todo: check last comment current_user_id = self.current_user_id comment = Comment( article_id=article_id, user_id=current_user_id, content=content, format=format, ua=ua, public=True ) comment.save(inserting=True) current_user = self.current_user self.write_json({ 'comment': { 'user_name': current_user.name, 'url': current_user.site, 'img': current_user.get_avatar(), 'ua': comment.ua, 'time': formatted_time(timestamp_to_datetime(comment.time)), 'id': comment.id, 'content': comment.html_content() } }) FragmentCache.delete('sidebar') if CONFIG.MAILGUN_API_KEY: url = html_content = html_body = title = '' if CONFIG.ADMIN_EMAIL and not self.is_admin: url = u'%s%s#comment-id-%d' % (CONFIG.BLOG_HOME_FULL_URL, article.quoted_url(), comment.id) html_content = comment.html_content_with_full_url(url) html_body = u'%s 在 <a href="%s">%s</a> 评论道:<br/>%s' % (escape(current_user.name), url, article.title, html_content) title = u'Re: ' + article.title yield send_email(to=CONFIG.ADMIN_EMAIL, subject=title, html=html_body) if format != ContentFormatFlag.PLAIN: if not html_content: url = u'%s%s#comment-id-%d' % (CONFIG.BLOG_HOME_FULL_URL, article.quoted_url(), comment.id) html_content = comment.html_content_with_full_url(url) comment_ids = set(int(comment_id) for comment_id in Comment.REPLY_LINK_PATTERN.findall(html_content)) if comment_ids: comments = Comment.get_by_ids(comment_ids) if comments: user_ids = {comment.user_id for comment in comments} user_ids.discard(CONFIG.ADMIN_USER_ID) # already sent to admin if user_ids: users = User.get_by_ids(user_ids) if users: if not html_body: html_body = u'%s 在 <a href="%s">%s</a> 评论道:<br/>%s<hr/>您收到这封邮件是因为有人回复了您的评论。您可前往原文回复,请勿直接回复该邮件。' % (escape(current_user.name), url, article.title, html_content) title = u'Re: ' + article.title else: html_body += u'<hr/>您收到这封邮件是因为有人回复了您的评论。您可前往原文回复,请勿直接回复该邮件。' for user in users: yield send_email(to=user.email, subject=title, html=html_body)
def post(self): title = self.get_argument('title', None) if not title: self.finish('发表失败,标题不能为空') return pub_time = self.get_argument('pub_time', None) if pub_time: pub_time = parse_time(pub_time) if not pub_time: pub_time = datetime.utcnow() pub_timestamp = datetime_to_timestamp(pub_time) mod_time = self.get_argument('mod_time', None) if mod_time: mod_time = parse_time(mod_time) if not mod_time: mod_timestamp = pub_timestamp else: mod_timestamp = datetime_to_timestamp(mod_time) url = self.get_argument('url', None) # todo: check url pattern if not url: formatted_date = formatted_date_for_url(pub_time) if CONFIG.REPLACE_SPECIAL_CHARACTERS_FOR_URL: url = formatted_date + replace_special_characters_for_url(title) else: url = formatted_date + title if Article.exist_url(url): self.finish('发表失败,同链接的文章已存在') return public = self.get_argument('public', None) == 'on' bbcode = self.get_argument('bbcode', None) == 'on' html = self.get_argument('html', None) == 'on' format = bbcode * ContentFormatFlag.BBCODE + html * ContentFormatFlag.HTML content = self.get_argument('content').replace('\r\n', '\n').replace('\r', '\n') category_name = self.get_argument('category', None) if category_name: if not Category.exists(category_name): self.finish('发表失败,分类不存在') return tag_names = self.get_arguments('tags') if tag_names: tag_names = set(tag_names) tag_names.discard('') keywords = self.get_argument('keywords', None) if keywords: keywords = keywords.lower() article = Article( title=title, url=url, content=content, format=format, category=category_name or None, tags=sorted(tag_names) if tag_names else None, keywords=keywords, public=public, pub_time=pub_timestamp, mod_time=mod_timestamp ) try: article.save(inserting=True) except IntegrityError: quoted_url = article.quoted_url() self.finish('发表失败,已有<a href="%s%s">相同链接的文章</a>存在' % (CONFIG.BLOG_HOME_RELATIVE_PATH, quoted_url)) except Exception: logging.exception('failed to save new article') self.finish('发表失败') else: quoted_url = article.quoted_url() self.finish('发表成功,查看<a href="%s%s">发表后的文章</a>' % (CONFIG.BLOG_HOME_RELATIVE_PATH, quoted_url))
def test_save_and_get_by_id(self): self.assertIsNone(Article.get_by_id(1)) now = int(time.time()) article = Article( title='test title', url='test-url', content=u'测试', category='test', tags=('test1', 'test2'), ) self.assertRaises(PropertyError, article.save) article.save(inserting=True) self.assertEqual(article.id, 1) saved_article = Article.get_by_id(1) self.assertEqual(article, saved_article) self.assertGreaterEqual(saved_article.pub_time, now) self.assertGreaterEqual(saved_article.mod_time, now) self.assertIsNone(Article.get_by_id(2)) saved_article.title = u'测试' saved_article.save() saved_article = Article.get_by_id(1) self.assertEqual(saved_article.title, u'测试') self.assertIsNone(Article.get_by_id(2)) self.assertRaises(PropertyError, saved_article.save, inserting=True) article2 = Article( title='test', category='test', tags=('test1', 'test2'), pub_time=1, mod_time=2 ) article2.save(inserting=True) self.assertEqual(article2.id, 2) saved_article2 = Article.get_by_id(2) self.assertEqual(article2, saved_article2)