Permalink
Browse files

bind wordpress

  • Loading branch information...
1 parent 65b8312 commit cc45f8e4d98b50295a36543c0ec0bf175d50df78 @laiwei committed Apr 10, 2012
View
8 cronjob/first_sync_timeline.py
@@ -28,8 +28,16 @@
sync_task = SyncTask.get(queue.task_id)
if not sync_task:
continue
+
+ ## 现在不同步豆瓣日记
if str(sync_task.category) == str(config.CATE_DOUBAN_NOTE):
continue
+
+ ## 同步wordpress rss
+ if str(sync_task.category) == str(config.CATE_WORDPRESS_POST):
+ jobs.sync_wordpress(sync_task)
+ continue
+
max_sync_times = 0
min_id = Status.get_min_origin_id(sync_task.category, sync_task.user_id)
if sync_task:
View
7 dep.txt
@@ -111,3 +111,10 @@ sudo apt-get install memcached
## telnet 127.0.0.1 11211 "stats"
pip install python-memcached
+
+## rss feed parse
+pip install feedparser
+#http://stackoverflow.com/questions/2244836/rss-feed-parser-library-in-python
+#http://packages.python.org/feedparser/
+
+
View
51 jobs.py
@@ -8,7 +8,7 @@
from past.utils.escape import json_encode, json_decode
from past.utils.logger import logging
from past.utils import datetime2timestamp
-from past.api_client import Douban, SinaWeibo, Twitter, QQWeibo
+from past.api_client import Douban, SinaWeibo, Twitter, QQWeibo, Wordpress
from past.corelib import category2provider
from past.model.data import (DoubanNoteData, DoubanMiniBlogData)
from past.model.status import Status, SyncTask
@@ -137,6 +137,32 @@ def sync(t, old=False):
import traceback; print traceback.format_exc()
return 0
+def sync_wordpress(t, refresh=False):
+ if not t:
+ log.warning('no_wordpress_sync_task')
+ return
+
+ #一个人可以有多个wordpress的rss源地址
+ rs = UserAlias.gets_by_user_id(t.user_id)
+ uas = []
+ for x in rs:
+ if x.type == config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS]:
+ uas.append(x)
+ if not uas:
+ log.warning('no_wordpress_alias')
+ return
+ for ua in uas:
+ try:
+ client = Wordpress(ua.alias)
+ rs = client.get_feeds(refresh)
+ if rs:
+ log.info("get wordpress succ, result length is:%s" % len(rs))
+ for x in rs:
+ Status.add_from_obj(t.user_id, x, json_encode(x.get_data()))
+ return
+ except:
+ import traceback; print traceback.format_exc()
+
def sync_helper(cate,old=False):
log.info("%s syncing old %s... cate=%s" % (datetime.datetime.now(), old, cate))
ids = SyncTask.get_ids()
@@ -150,7 +176,10 @@ def sync_helper(cate,old=False):
log.info("task_list length is %s" % len(task_list))
for t in task_list:
try:
- sync(t, old)
+ if t.category == config.CATE_WORDPRESS_POST:
+ sync_wordpress(t)
+ else:
+ sync(t, old)
except Exception, e:
import traceback
print "%s %s" % (datetime.datetime.now(), traceback.format_exc())
@@ -162,14 +191,16 @@ def sync_helper(cate,old=False):
parser.add_option("-n", "--num", type="int", dest="num", help="run how many times")
(options, args) = parser.parse_args()
- if not options.time or options.time not in ['new', 'old']:
- print 'sync old or new?'
- else:
- old = True if options.time=='old' else False
- cate = options.cate if options.cate else None
- num = options.num if options.num else 1
- for i in xrange(num):
- sync_helper(cate, old)
+ if not options.time:
+ options.time = 'new'
+ if options.time not in ['new', 'old']:
+ options.time = 'new'
+
+ old = True if options.time=='old' else False
+ cate = options.cate if options.cate else None
+ num = options.num if options.num else 1
+ for i in xrange(num):
+ sync_helper(cate, old)
##python jobs.py -t old -c 200 -n 2
View
44 past/api_client.py
@@ -4,12 +4,13 @@
import urllib
import tweepy
import config
+from past.store import mc
from past.utils.escape import json_encode, json_decode
from past.utils.logger import logging
from past.utils import httplib2_request
from past.model.data import (DoubanNoteData, DoubanStatusData,
DoubanMiniBlogData, SinaWeiboStatusData, TwitterStatusData,
- QQWeiboStatusData)
+ QQWeiboStatusData, WordpressData)
from past.model.user import User,UserAlias, OAuth2Token
from past.oauth_login import QQOAuth1Login
@@ -302,3 +303,44 @@ def get_timeline(self, format_="json", reqnum=200, type_=0, contenttype=0, paget
return [QQWeiboStatusData(c) for c in info]
+class Wordpress(object):
+
+ WORDPRESS_ETAG_KEY = "wordpress:etag:%s"
+
+ ## 同步wordpress rss
+ def __init__(self, alias):
+ ## alias means wordpress feed uri
+ self.alias = alias
+
+ def __repr__(self):
+ return "<Wordpress alias=%s>" %(self.alias)
+ __str__ = __repr__
+
+ def get_etag(self):
+ r = str(Wordpress.WORDPRESS_ETAG_KEY % self.alias)
+ return mc.get(r)
+
+ def set_etag(self, etag):
+ r = str(Wordpress.WORDPRESS_ETAG_KEY % self.alias)
+ mc.set(r, etag)
+
+ def get_feeds(self, refresh=False):
+ import feedparser
+ etag = self.get_etag()
+ if refresh:
+ d = feedparser.parse(self.alias)
+ else:
+ d = feedparser.parse(self.alias, etag=etag)
+ if not d:
+ return []
+ if not (d.status == 200 or d.status == 301):
+ log.warning("---get wordpress feeds, status is %s, not valid" % d.status)
+ return []
+
+ entries = d.entries
+ if not entries:
+ return []
+
+ self.set_etag(d.etag)
+ return [WordpressData(x) for x in entries]
+
View
4 past/config.py
@@ -37,19 +37,23 @@
OPENID_SINA = 'sina'
OPENID_QQ = 'qq' ##qq weibo
OPENID_TWITTER = 'twitter'
+##命名需要商榷
+OPENID_WORDPRESS = 'wordpress'
OPENID_TYPE_DICT = {
OPENID_DOUBAN : "D",
OPENID_SINA : "S",
OPENID_QQ : "Q",
OPENID_TWITTER : "T",
+ OPENID_WORDPRESS : "W",
}
OPENID_TYPE_NAME_DICT = {
"D" : u"豆瓣",
"S" : u"新浪微博",
"T" : u"twitter",
"Q" : u"腾讯微博",
+ "W" : u"Wordpress",
}
#-- oauth key & secret config --
View
18 past/dev.sql
@@ -1,11 +1,11 @@
-DROP TABLE IF EXISTS `passwd`;
-CREATE TABLE `passwd` (
- `user_id` int(11) unsigned NOT NULL,
- `email` varchar(63) NOT NULL,
- `salt` varchar(8) NOT NULL DEFAULT '',
- `passwd` varchar(15) NOT NULL DEFAULT '',
+DROP TABLE IF EXISTS `confirmation`;
+
+CREATE TABLE `confirmation` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `random_id` varchar(16) NOT NULL,
+ `text` varchar(128) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- UNIQUE KEY `uniq_idx_uid` (`user_id`),
- UNIQUE KEY `uniq_idx_email` (`email`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='passwd';
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uniq_idx_random` (`random_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='confirmation';
View
43 past/model/data.py
@@ -1,6 +1,7 @@
#-*- coding:utf-8 -*-
import datetime
+import hashlib
from past import config
from past.utils.escape import json_decode
@@ -256,6 +257,10 @@ def get_user(self):
def get_origin_uri(self):
return ""
+ ##摘要信息,对于blog等长文来说很有用,视情况在子类中覆盖该方法
+ def get_summary(self):
+ return self.get_content()
+
class DoubanData(AbsData):
def __init__(self, category, data):
@@ -437,15 +442,14 @@ def get_thumbnail_pic(self):
def get_middle_pic(self):
return self.data.get("bmiddle_pic", "")
- def get_images(self, size="middle"):
+ def get_images(self, size="origin"):
method = "get_%s_pic" % size
if hasattr(self, method):
i = getattr(self, method)()
if i:
return [i]
return []
-
# twitter status
class TwitterStatusData(AbsData):
def __init__(self, data):
@@ -530,3 +534,38 @@ def get_images(self, size="middle"):
def get_origin_uri(self):
return self.data.get("fromurl")
+
+
+class WordpressData(AbsData):
+ def __init__(self, data):
+ super(WordpressData, self).__init__(
+ config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS],
+ config.CATE_WORDPRESS_POST, data)
+
+ def get_origin_id(self):
+ id_ = self.data.get("id", "") or self.data.get("link", "")
+ m = hashlib.md5()
+ m.update(id_)
+ return m.hexdigest()[:16]
+
+ def get_create_time(self):
+ t = self.data.get("published", "")
+ return t and datetime.datetime.strptime(t, "%a, %d %b %Y %H:%M:%S +0000")
+
+ def get_title(self):
+ return self.data.get("title", "")
+
+ def get_content(self):
+ content = self.data.get("content")
+ if content:
+ c = content[0]
+ return c and c.get("value")
+
+ def get_user(self):
+ return self.data.get("author", "")
+
+ def get_origin_uri(self):
+ return self.data.get("id", "") or self.data.get("link", "")
+
+ def get_summary(self):
+ return self.data.get("summary", "")
View
29 past/model/status.py
@@ -12,7 +12,8 @@
from past.corelib.cache import cache, pcache, HALF_HOUR
from .user import UserAlias
from .data import DoubanMiniBlogData, DoubanNoteData, DoubanStatusData, \
- SinaWeiboStatusData, QQWeiboStatusData, TwitterStatusData
+ SinaWeiboStatusData, QQWeiboStatusData, TwitterStatusData,\
+ WordpressData
log = logging.getLogger(__file__)
@@ -30,9 +31,10 @@ def __init__(self, id, user_id, origin_id,
self.site = site
self.category = category
self.title = title
- self.text = mongo_conn.get(self.__class__.STATUS_REDIS_KEY % self.id)
- self.text = json_decode(self.text) if self.text else ""
self.origin_user_id = UserAlias.get_by_user_and_type(self.user_id, self.site).alias
+ _raw_data_obj = self.get_data()
+ ##对于140字以内的消息,summary和text相同;对于wordpress等长文,summary只是摘要,text为全文
+ self.summary = _raw_data_obj and _raw_data_obj.get_summary()
if self.site == config.OPENID_TYPE_DICT[config.OPENID_TWITTER]:
self.create_time += datetime.timedelta(seconds=8*3600)
@@ -57,7 +59,7 @@ def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
- if self.category == config.CATE_QQWEIBO_STATUS and self.get_retweeted_data() != self.text:
+ if self.category == config.CATE_QQWEIBO_STATUS and self.get_retweeted_data() != self.summary:
return int(self.id)
if (self.category == config.CATE_SINA_STATUS or self.category == config.CATE_DOUBAN_STATUS) \
and self.get_retweeted_data():
@@ -71,7 +73,7 @@ def __hash__(self):
return int(d.hexdigest(),16)
def _generate_bare_text(self, offset=150):
- bare_text = self.text[:offset]
+ bare_text = self.summary[:offset]
bare_text = clear_html_element(bare_text).replace(u"", "").replace(u"", "").replace("amp;","")
bare_text = re.sub("\s", "", bare_text)
bare_text = re.sub("http://t.cn/[a-zA-Z0-9]+", "", bare_text)
@@ -90,10 +92,10 @@ def _clear_cache(self, user_id, status_id, cate=None):
if cate:
mc.delete("status_ids:user:%scate:%s" % (user_id, cate))
- #@property
- #def text(self):
- # _text = mongo_conn.get(self.__class__.STATUS_REDIS_KEY % self.id)
- # return json_decode(_text) if _text else ""
+ @property
+ def text(self):
+ _text = mongo_conn.get(Status.STATUS_REDIS_KEY % self.id)
+ return json_decode(_text) if _text else ""
@property
def raw(self):
@@ -273,10 +275,13 @@ def get_data(self):
return QQWeiboStatusData(self.raw)
elif self.category == config.CATE_DOUBAN_STATUS:
return DoubanStatusData(self.raw)
+ elif self.category == config.CATE_WORDPRESS_POST:
+ return WordpressData(self.raw)
else:
return None
def get_origin_uri(self):
+ ##d是AbsData的子类实例
d = self.get_data()
if self.category == config.CATE_DOUBAN_MINIBLOG or self.category == config.CATE_DOUBAN_STATUS:
ua = UserAlias.get_by_user_and_type(self.user_id,
@@ -292,6 +297,8 @@ def get_origin_uri(self):
return (config.OPENID_TWITTER, d.get_origin_uri())
elif self.category == config.CATE_QQWEIBO_STATUS:
return (config.OPENID_QQ, config.QQWEIBO_STATUS % self.origin_id)
+ elif self.category == config.CATE_WORDPRESS_POST:
+ return (config.OPENID_WORDPRESS, d.get_origin_uri())
else:
return None
@@ -434,8 +441,8 @@ def get_all_text_by_user(user_id, limit=1000):
status_ids = Status.get_ids(user_id, limit=limit)
for s in Status.gets(status_ids):
try:
- #_t = ''.join( [x for x in s.text if is_cn_or_en(x)] )
- _t = s.text
+ ##TODO:这里用的summary,是为了效率上的考虑
+ _t = s.summary
retweeted_data = s.get_retweeted_data()
if retweeted_data:
View
73 past/model/user.py
@@ -320,6 +320,12 @@ def get_homepage_url(self):
User.get(self.user_id).get_thirdparty_profile(self.type).get("uid", "")), \
config.OPENID_QQ
+ if self.type == config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS]:
+ ##FIXME: wordpress显示rss地址代替blog地址
+ return config.OPENID_TYPE_NAME_DICT[self.type],\
+ self.alias, config.OPENID_WORDPRESS
+
+
class OAuth2Token(object):
def __init__(self, alias_id, access_token, refresh_token):
@@ -358,52 +364,39 @@ def add(cls, alias_id, access_token, refresh_token):
return ot
-def life(user):
- life_dict = {}
- uas = user.get_alias()
- for ua in uas:
- life_dict[ua.type] = [config.OPENID_TYPE_NAME_DICT.get(ua.type)]
- cate = None
- if ua.type == config.OPENID_TYPE_DICT[config.OPENID_DOUBAN]:
- cates = config.CATE_DOUBAN_STATUS
- elif ua.type == config.OPENID_TYPE_DICT[config.OPENID_SINA]:
- cates = config.CATE_SINA_STATUS
- elif ua.type == config.OPENID_TYPE_DICT[config.OPENID_QQ]:
- cates = config.CATE_QQWEIBO_STATUS
- elif ua.type == config.OPENID_TYPE_DICT[config.OPENID_TWITTER]:
- cates = config.CATE_TWITTER_STATUS
-
+class Confirmation(object):
+ def __init__(self, random_id, text, time):
+ self.random_id = random_id
+ self.text = text
+ self.time = time
- ## just for tecent_weibo
@classmethod
- def get_oldest_create_time(cls, cate, user_id):
- cursor = db_conn.execute('''select min(create_time) from status
- where category=%s and user_id=%s''', (cate, user_id))
+ def get_by_random_id(cls, random_id):
+ cursor = db_conn.execute('''select text, time from confirmation
+ where random_id=%s''', random_id)
row = cursor.fetchone()
cursor and cursor.close()
if row:
- return row[0]
- else:
- return None
+ return cls(random_id, row[0], row[1])
+ def delete(self):
+ Confirmation.delete_by_random_id(self.random_id)
+
@classmethod
- def get_count_by_cate(cls, cate, user_id):
- cursor = db_conn.execute('''select count(1) from status
- where category=%s and user_id=%s''', (cate, user_id))
- row = cursor.fetchone()
- cursor and cursor.close()
- if row:
- return row[0]
- else:
- return 0
+ def delete_by_random_id(cls, random_id):
+ db_conn.execute('''delete from confirmation
+ where random_id=%s''', random_id)
+ db_conn.commit()
@classmethod
- def get_count_by_user(cls, user_id):
- cursor = db_conn.execute('''select count(1) from status
- where user_id=%s''', user_id)
- row = cursor.fetchone()
- cursor and cursor.close()
- if row:
- return row[0]
- else:
- return 0
+ def add(cls, random_id, text):
+ cursor = None
+ try:
+ cursor = db_conn.execute('''insert into confirmation (random_id, text) values(%s, %s)''',
+ (random_id, text))
+ db_conn.commit()
+ return True
+ except IntegrityError:
+ db_conn.rollback()
+ finally:
+ cursor and cursor.close()
View
4 past/static/css/default.css
@@ -33,6 +33,7 @@ a:hover{color:#4d5256;text-decoration:underline;}
.from.twitter a{background-position:0 -16px;}
.from.sina a{background-position:0 -32px;}
.from.douban a{background-position:0 -48px;}
+.from.wordpress a{background-position:0 -64px;}
#content {
width: 960px;
@@ -213,6 +214,9 @@ vertical-align: middle;
.bigger {
font-size: 16px;
}
+.smaller{
+ font-size: 11px;
+}
.fade {
color: #999;
View
BIN past/static/img/sns.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
103 past/templates/bind_wordpress.html
@@ -0,0 +1,103 @@
+{% extends "layout.html" %}
+
+{% import "blocks.html" as blocks %}
+
+{% block content_block %}
+ <div id="sidebar"></div>
+ <div id="rightbar">
+ {{blocks.rightbar_intros_block(intros)}}
+ <div class="sep10"></div>
+ {{blocks.rightbar_feedback_block()}}
+ </div>
+
+ <div id="middlebar">
+ <!--提醒-->
+ {{ blocks.notification_block() }}
+
+ <!--绑定wordpress-->
+ <div class="box">
+ <div class="cell"><a href="/i">首页</a> &gt; 绑定wordpress</div>
+ {% if step == '1'%}
+ <div id="feed1" class="cell"><table>
+ <tr height="40px">
+ <td width="200px" align="right"><span class="fade">你的wordpress feed地址:</span></td>
+ <td width="280px" align="left">
+ <input type="text" class="sl" name="wordpress_feed" value=""></input>
+ <div class="sep3"></div>
+ <span class="tip smaller">比如: http://xxblog.com/feed/, 填写后不可更改</span>
+ </td>
+ </tr>
+ <tr height="30px"><td align="right"><span class="fade"></span></td>
+ <td> <input type="submit" name="bind_wordpress" value="确定"></input> </td>
+ </tr>
+ </table></div>
+
+ <div id="feed2" class="inner" style="display:none;">
+ <span id="feed2_0" style="display:none;"></span>
+ 你的wordpress feed地址为:<span id="feed2_1"></span>
+ <div class="sep10"></div>
+ <span id="feed2_2"></span>
+ <div class="sep10"></div>
+ <input type="submit" name="confirm_bind_wordpress" value="下一步"></input>
+ </div>
+ {%else%}
+ <div id="feed2" class="inner">
+ 你的blog feed地址为:<span id="feed2_1" class="fade">{{feed_uri}}</span>
+ <div class="sep10"></div>
+ 你的blog认领验证码为:<span id="feed2_0" class="fade">{{random_id}}</span>
+ <div class="sep10"></div>
+ 为了验证blog的主人^^,请发一篇blog,内容为 {{random_id}},完成该步骤后,请点下一步完成绑定
+ <div class="sep3"></div>
+
+ <input type="submit" name="confirm_bind_wordpress" value="下一步"></input>
+ </div>
+ {%endif%}
+
+ <div class="inner">
+ 1. 每个人只能认领一个blog^^
+ <div class="sep3"></div>
+ 2. 理论来说,支持导入所有的rss feed,而不仅仅是wordpress
+ <div class="sep3"></div>
+ 3. 对于wordpress rss feed来讲,只能导入最近的15篇文章,如果需要导入更多,需要去wordpress的控制面板中设置rss输出的文章数目。
+ <div class="sep3"></div>
+ </div>
+
+ </div>
+ </div>
+
+ <script language="javascript">
+ jQuery(function($) {
+ $("input[name='bind_wordpress']").bind("click", function(){
+ var feed_uri = $("input[name='wordpress_feed']").val();
+ $.post("/bind/wordpress", {'step':1, 'feed_uri':feed_uri}, function(data){
+ if(data.ok == 'true'){
+ $("#feed1").hide();
+ $("#feed2").show();
+ $("#feed2_0").text(data.code);
+ $("#feed2_1").text(data.feed_uri);
+ $("#feed2_2").text(data.msg);
+ }else{
+ alert(data.msg);
+ }
+ }, "json");
+ return false;
+ });
+
+ var c = $("input[name='confirm_bind_wordpress']");
+ c.bind("click", function(){
+ c.val("正在验证中... 可能需要1分钟,请不要刷新页面");
+ $.post("/bind/wordpress", {'step':2, 'random_id': $("#feed2_0").text()}, function(data){
+ c.val("下一步");
+ if(data.ok === 'true'){
+ alert(data.msg);
+ window.location = "/settings";
+ }else{
+ alert(data.msg + "," + "你是否还没有发含有验证码的文章呀?^^");
+ }
+ }, 'json');
+ });
+
+ });
+ </script>
+
+{% endblock %}
View
3 past/templates/layout.html
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>{%block title_block%} The Past of Me | 个人杂志计划{%endblock%}</title>
-<link rel="stylesheet" type="text/css" media="screen" href="/static/css/default.css?v=1.10">
+<link rel="stylesheet" type="text/css" media="screen" href="/static/css/default.css?v=1.11">
<script src="{{ url_for('static', filename='js/jquery.js') }}" type="text/javascript"></script>
<script src="{{ url_for('static', filename='js/jquery.magnifier.js') }}" type="text/javascript"></script>
</head>
@@ -38,6 +38,7 @@
<a href="/past">我的过去</a>
<a href="/user">浏览发现</a>
<a href="/settings">设置</a>
+ <a href="/bind/wordpress">绑定wordpress</a>
</ul>
</div>
{%endblock%}
View
17 past/templates/settings.html
@@ -11,7 +11,10 @@
</div>
<div id="middlebar">
+ <!--提醒-->
{{ blocks.notification_block() }}
+
+ <!--设置email-->
<div class="box">
<div class="cell"><a href="/i">首页</a> &gt; 设置</div>
<form method="post">
@@ -22,18 +25,28 @@
<tr height="30px"><td align="right"><span class="fade">注册时间:</span></td>
<td align="left">{{g.user.create_time}}</td>
</tr>
- <tr height="30px"><td align="right"><span class="fade">电子邮件:</span></td>
+ {% if wordpress_alias %}
+ <tr height="30px">
+ <td width="200px" align="right"><span class="fade">你的wordpress feed地址:</span></td>
+ <td width="280px" align="left"> {{wordpress_alias.alias}} </td>
+ </tr>
+ {% endif%}
+ <tr height="40px"><td align="right"><span class="fade">电子邮件:</span></td>
<td>
{%if g.user.get_email()%}
{{g.user.get_email()}}
{%else%}
- <input type="text" class="sl" name="email" value="">定期发送更新好的PDF版本</input>
+ <input type="text" class="sl" name="email" value=""></input>
+ <div class="sep3"></div>
+ <span class="fade smaller">定期发送更新好的PDF版本</span>
{%endif%}
</td>
</tr>
+ {%if not g.user.get_email()%}
<tr height="30px"><td align="right"><span class="fade"></span></td>
<td> <input type="submit" value="保存设置"></input> </td>
</tr>
+ {%endif%}
</table></div>
</form>
View
32 past/templates/status.html
@@ -1,9 +1,9 @@
{% macro douban_status(s, pdf=False) -%}
<!-- 正文 -->
{%if pdf%}
- {{s.text|wrap_long_line}}
+ {{s.summary|wrap_long_line}}
{%else%}
- {{s.text}}
+ {{s.summary}}
{%endif%}
@@ -82,9 +82,9 @@
{% macro sina_status(s, pdf=False) -%}
{%if pdf%}
- {{s.text|wrap_long_line}}
+ {{s.summary|wrap_long_line}}
{%else%}
- {{s.text}}
+ {{s.summary}}
{%endif%}
{% set images = s.get_data().get_images() or [] %}
@@ -120,9 +120,9 @@
{% macro twitter_status(s, pdf=False) -%}
{%if pdf%}
- {{s.text|wrap_long_line}}
+ {{s.summary|wrap_long_line}}
{%else%}
- {{s.text}}
+ {{s.summary}}
{%endif%}
{%if pdf%}
@@ -133,13 +133,13 @@
{% macro qq_weibo_status(s, pdf=False) -%}
{%if pdf%}
- {{s.text|wrap_long_line|safe}}
+ {{s.summary|wrap_long_line|safe}}
{%else%}
- {{s.text|safe}}
+ {{s.summary|safe}}
{%endif%}
{% set re = s.get_retweeted_data() %}
- {% if not s.text and re %}
+ {% if not s.summary and re %}
{{ "//" + re }}
{% endif %}
@@ -157,3 +157,17 @@
{%endif%}
{%- endmacro %}
+{% macro wordpress_status(s, pdf=False) -%}
+ {% set origin_uri = s.get_origin_uri() %}
+ <a href="{{origin_uri[1]}}" class="bigger">{{s.title}}</a><br/>
+ {%if pdf%}
+ {{s.text|wrap_long_line}}
+ {%else%}
+ {{s.summary|nl2br|safe}}
+ {%endif%}
+
+ {%if pdf%}
+ <div class="time">
+ From: {{origin_uri()[0]}} {{s.create_time.strftime("%Y-%m-%d %H:%M:%S")}}</div>
+ {%endif%}
+{%- endmacro %}
View
9 past/templates/timeline.html
@@ -90,6 +90,10 @@ <h2 class="title">{{m.replace("-","年")}}月</h2>
{{status_tmpl_helper.twitter_status(s)}}
{%endif%}
+ {%if s.category == config.CATE_WORDPRESS_POST%}
+ {{status_tmpl_helper.wordpress_status(s)}}
+ {%endif%}
+
</div>
</div>
</li>
@@ -115,8 +119,9 @@ <h2 class="title">{{m.replace("-","年")}}月</h2>
<div class="clear"></div>
<script>
-$("img").error( function(){$(this).css({ visibility:"hidden" });
-});
+ jQuery(function($) {
+ $("img").error( function(){$(this).css({ visibility:"hidden" }); });
+ });
</script>
{% endblock %}
View
4 past/utils/escape.py
@@ -26,6 +26,7 @@
import sys
import urllib
import datetime
+import time
import types
from HTMLParser import HTMLParser
@@ -223,6 +224,9 @@ def recursive_unicode(obj):
return to_unicode(obj.strftime("%s %s" % (_DATE_FORMAT, _TIME_FORMAT)))
elif isinstance(obj, datetime.date):
return to_unicode(obj.strftime("%s" % _DATE_FORMAT))
+ elif isinstance(obj, time.struct_time):
+ t = datetime.datetime(obj.tm_year, obj.tm_mon, obj.tm_mday, obj.tm_hour, obj.tm_min, obj.tm_sec)
+ return to_unicode(t.strftime("%s %s" % (_DATE_FORMAT, _TIME_FORMAT)))
elif isinstance(obj, datetime.time):
return to_unicode(obj.strftime("%s" % _TIME_FORMAT))
elif isinstance(obj, types.IntType) or isinstance(obj, types.LongType):
View
102 past/view/settings.py
@@ -5,17 +5,27 @@
from flask import g, flash, request, render_template, redirect
from past import app
from past import config
-from past.model.user import User
+from past.model.user import User, Confirmation, UserAlias
+from past.model.status import SyncTask, TaskQueue
from past.utils import is_valid_email
+from past.utils.escape import json_encode
+from past.utils import randbytes
+from past.api_client import Wordpress
+from past.store import mc
from .utils import require_login
@app.route("/settings", methods=["GET", "POST"])
@require_login("/settings")
def settings():
+ ##XXX:
intros = [g.user.get_thirdparty_profile(x).get("intro") for x in config.OPENID_TYPE_DICT.values()]
intros = filter(None, intros)
+ uas = g.user.get_alias()
+ wordpress_alias_list = [x for x in uas if x.type == config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS]]
+ wordpress_alias = wordpress_alias_list and wordpress_alias_list[0]
+
if request.method == "POST":
email = request.form.get("email")
if email and is_valid_email(email):
@@ -28,3 +38,93 @@ def settings():
flash(u'电子邮箱更新失败', 'error')
return render_template("settings.html", **locals())
+
+@app.route("/bind/wordpress", methods=["GET", "POST"])
+def bind_wordpress():
+ if not g.user:
+ flash(u"请先使用豆瓣、微博、QQ、Twitter任意一个帐号登录后,再来做绑定wordpress的操作^^", "tip")
+ return redirect("/home")
+
+ uas = g.user.get_alias()
+ wordpress_alias_list = [x for x in uas if x.type == config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS]]
+ if wordpress_alias_list:
+ flash(u"你的wordpress blog已经绑定过了^^", "tip")
+ return redirect("/settings")
+
+ if request.method == "GET":
+ step = "1"
+ random_id = mc.get("wordpress_bind:%s" % g.user.id)
+ c = random_id and Confirmation.get_by_random_id(random_id)
+ if c:
+ _, feed_uri = c.text.split(":", 1)
+ step = "2"
+ return render_template("bind_wordpress.html", **locals())
+
+ elif request.method == "POST":
+ ret = {}
+ ret['ok'] = False
+ step = request.form.get("step", '1')
+ if step == '1':
+ feed_uri = request.form.get("feed_uri")
+ if not feed_uri:
+ ret['msg'] = 'feed地址不能为空'
+ elif not (feed_uri.startswith("http://") or feed_uri.startswith("https://")):
+ ret['msg'] = 'feed地址貌似不对'
+ else:
+ ua = UserAlias.get(config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS], feed_uri)
+ if ua:
+ ret['msg'] = '该feed地址已被绑定'
+ else:
+ ##设置一个激活码
+ code = randbytes(8)
+ val = "%s:%s" % (g.user.id, feed_uri)
+ r = Confirmation.add(code, val)
+ if r:
+ ret['ok'] = True
+ ret['msg'] = '为了验证blog的主人^^,请发一篇blog,内容为 %s,完成该步骤后,请点下一步完成绑定' \
+ % code
+ ret['code'] = code
+ ret['feed_uri'] = feed_uri
+ mc.set("wordpress_bind:%s" %g.user.id, code)
+ else:
+ ret['msg'] = '抱歉,出错了,请重试'
+ return json_encode(ret)
+ elif step == '2':
+ random_id = request.form.get("random_id")
+ if not random_id:
+ ret['msg'] = '没有code^^'
+ else:
+ c = Confirmation.get_by_random_id(random_id)
+ if not c:
+ ret['msg'] = '这个code不对哦^^'
+ else:
+ text = c.text
+ user_id, feed_uri = text.split(":", 1)
+ ## 同步一下,看看验证码的文章是否正确
+ client = Wordpress(feed_uri)
+ rs = client.get_feeds(refresh=True)
+ if not rs:
+ ret['msg'] = '没有发现有验证码的文章呀'
+ else:
+ latest_post = rs[0]
+ if latest_post.get_content().encode("utf8").find(str(random_id)) == -1:
+ ret['msg'] = "没有发现有验证码的文章呀"
+ else:
+ ua = UserAlias.bind_to_exists_user(g.user,
+ config.OPENID_TYPE_DICT[config.OPENID_WORDPRESS], feed_uri)
+ if not ua:
+ ret['msg'] = '出错了,麻烦你重试一下吧^^'
+ else:
+ ##添加同步任务
+ t = SyncTask.add(config.CATE_WORDPRESS_POST, g.user.id)
+ t and TaskQueue.add(t.id, t.kind)
+ ##删除confiration记录
+ c.delete()
+ mc.delete("wordpress_bind:%s" %g.user.id)
+
+ ret['ok'] = True
+ ret['msg'] = '恭喜,绑定成功啦'
+ return json_encode(ret)
+ else:
+ return redirect("/settings")
+
View
1 past/view/views.py
@@ -238,6 +238,7 @@ def connect_callback(provider):
flash(u"连接到%s失败了,可能是对方网站忙,请稍等重试..." %provider, "error")
return redirect(url_for("home"))
+
@app.route("/sync/<cates>", methods=["GET", "POST"])
@require_login()
def sync(cates):

0 comments on commit cc45f8e

Please sign in to comment.