Permalink
Browse files

Now topic can be deleted in mobile edition.

  • Loading branch information...
1 parent 0611324 commit bccdf2b770b701ef682b44018f19f7057f739adc @livid committed Mar 2, 2011
View
@@ -167,6 +167,18 @@ handlers:
- url: /sso/(.*)
script: sso.py
+- url: /notifications/?
+ script: notifications.py
+
+- url: /n/([a-z0-9]+).xml
+ script: notifications.py
+
+- url: /notifications/(.*)
+ script: notifications.py
+
+- url: /bfbcs/poke/(ps3|360|pc)/(.*)
+ script: misc.py
+
- url: .*
script: main.py
View
@@ -76,6 +76,18 @@ indexes:
- name: last_modified
direction: desc
+- kind: Notification
+ properties:
+ - name: for_member_num
+ - name: created
+ direction: desc
+
+- kind: Notification
+ properties:
+ - name: for_member_num
+ - name: num
+ direction: desc
+
- kind: Page
properties:
- name: minisite
View
27 main.py
@@ -850,18 +850,21 @@ def get(self, q):
q_md5 = hashlib.md5(q_lowered).hexdigest()
topics = memcache.get('q::' + q_md5)
if topics is None:
- if os.environ['SERVER_SOFTWARE'] == 'Development/1.0':
- fts = u'http://127.0.0.1:20000/search?q=' + str(urllib.quote(q_lowered))
- else:
- fts = u'http://' + config.fts_server + '/search?q=' + str(urllib.quote(q_lowered))
- response = urlfetch.fetch(fts, headers = {"Authorization" : "Basic %s" % base64.b64encode(config.fts_username + ':' + config.fts_password)})
- if response.status_code == 200:
- results = json.loads(response.content)
- topics = []
- for num in results:
- topics.append(GetKindByNum('Topic', num))
- template_values['topics'] = topics
- memcache.set('q::' + q_md5, topics, 86400)
+ try:
+ if os.environ['SERVER_SOFTWARE'] == 'Development/1.0':
+ fts = u'http://127.0.0.1:20000/search?q=' + str(urllib.quote(q_lowered))
+ else:
+ fts = u'http://' + config.fts_server + '/search?q=' + str(urllib.quote(q_lowered))
+ response = urlfetch.fetch(fts, headers = {"Authorization" : "Basic %s" % base64.b64encode(config.fts_username + ':' + config.fts_password)})
+ if response.status_code == 200:
+ results = json.loads(response.content)
+ topics = []
+ for num in results:
+ topics.append(GetKindByNum('Topic', num))
+ template_values['topics'] = topics
+ memcache.set('q::' + q_md5, topics, 86400)
+ except:
+ template_values['topics'] = []
else:
template_values['topics'] = topics
path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'search.html')
View
32 misc.py
@@ -11,6 +11,7 @@
from google.appengine.ext import webapp
from google.appengine.api import memcache
+from google.appengine.api import urlfetch
from google.appengine.ext import db
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
@@ -59,11 +60,40 @@ def get(self, source):
self.values['sha1'] = hashlib.sha1(i).hexdigest()
self.set_title(u'MD5 / SHA1 计算器')
self.finalize(template_name='md5')
+
+class BFBCSPokeHandler(webapp.RequestHandler):
+ def get(self, platform, soldier):
+ ua = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'
+ referer = 'http://bfbcs.com/' + platform
+ cache_tag = 'bfbcs::' + platform + '/' + soldier
+ raw = memcache.get(cache_tag)
+ url = 'http://bfbcs.com/stats_' + platform + '/' + soldier
+ if raw is None:
+ response = urlfetch.fetch(url, headers={'User-Agent' : ua, 'Referer' : referer })
+ raw = response.content
+ memcache.set(cache_tag, raw, 600)
+ pcode = re.findall('([a-z0-9]{32})', raw)
+ self.response.out.write('<strong>PCODE</strong> ' + str(pcode[0]) + '<br />')
+ if len(pcode) == 1:
+ pcode = pcode[0]
+ payload = 'request=addplayerqueue&pcode=' + pcode
+ self.response.out.write('<strong>PAYLOAD</strong> ' + payload + ' (' + str(len(payload))+ ' bytes)<br />')
+ headers = {'User-Agent' : ua, 'Referer' : url, 'X-Requested-With' : 'XMLHttpRequest', 'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8', 'Content-Length' : '61', 'Accept' : 'application/json, text/javascript, */*', 'Accept-Language' : 'en-us,en;q=0.5', 'Accept-Encoding' : 'gzip,deflate', 'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Keep-Alive' : 115, 'Host' : 'bfbcs.com', 'Pragma' : 'no-cache', 'Cache-Control' : 'no-cache', 'Cookie' : '__utma=7878317.1843709575.1297205447.1298572822.1298577848.12; __utmz=7878317.1297205447.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); sessid=enqd028n30d2tr4lv4ned04qi0; __utmb=7878317.21.10.1298577848; __utmc=7878317' }
+ response = urlfetch.fetch(url, payload=payload, headers=headers, method='POST')
+ if response.status_code == 500:
+ response = urlfetch.fetch(url, payload=payload, headers=headers, method='POST')
+ if response.status_code == 500:
+ self.response.out.write('<strong>FAILED</strong>')
+ else:
+ self.response.out.write('<strong>RESULT</strong> OK ' + response.content)
+ else:
+ self.response.out.write('<strong>RESULT</strong> OK ' + response.content)
def main():
application = webapp.WSGIApplication([
('/time/?', WorldClockHandler),
- ('/(md5|sha1)/?', MD5Handler)
+ ('/(md5|sha1)/?', MD5Handler),
+ ('/bfbcs/poke/(ps3|360|pc)/(.*)', BFBCSPokeHandler)
],
debug=True)
util.run_wsgi_app(application)
View
@@ -27,6 +27,7 @@
from v2ex.babel import Node
from v2ex.babel import Topic
from v2ex.babel import Reply
+from v2ex.babel import Notification
from v2ex.babel import SYSTEM_VERSION
@@ -667,6 +668,51 @@ def post(self, topic_num):
counter.put()
counter2.put()
+ # Notifications
+
+ notified_members = []
+ keys = []
+
+ # type: reply
+
+ if reply.member_num != topic.member_num:
+ q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'notification.max')
+ if (q.count() == 1):
+ counter = q[0]
+ counter.value = counter.value + 1
+ else:
+ counter = Counter()
+ counter.name = 'notification.max'
+ counter.value = 1
+ q2 = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'notification.total')
+ if (q2.count() == 1):
+ counter2 = q2[0]
+ counter2.value = counter2.value + 1
+ else:
+ counter2 = Counter()
+ counter2.name = 'notification.total'
+ counter2.value = 1
+
+ notification = Notification(parent=topic.member)
+ notification.num = counter.value
+ notification.type = 'reply'
+ notification.payload = reply.content
+ notification.label1 = topic.title
+ notification.link1 = '/t/' + str(topic.num) + '#reply' + str(topic.replies)
+ notification.member = member
+ notification.for_member_num = topic.member_num
+
+ keys.append(str(topic.member.key()))
+
+ counter.put()
+ counter2.put()
+ notification.put()
+
+ for key in keys:
+ taskqueue.add(url='/notifications/check/' + key)
+
+ taskqueue.add(url='/notifications/reply/' + str(reply.key()))
+
page_size = TOPIC_PAGE_SIZE
pages = 1
if topic.replies > page_size:
@@ -692,10 +738,11 @@ def post(self, topic_num):
memcache.delete('home_rendered')
memcache.delete('home_rendered_mobile')
if topic.replies < 50:
- try:
- taskqueue.add(url='/index/topic/' + str(topic.num))
- except:
- pass
+ if config.fts_enabled:
+ try:
+ taskqueue.add(url='/index/topic/' + str(topic.num))
+ except:
+ pass
# Twitter Sync
if member.twitter_oauth == 1 and member.twitter_sync == 1:
access_token = OAuthToken.from_string(member.twitter_oauth_string)
@@ -1030,14 +1077,12 @@ def post(self, topic_num):
site = GetSite()
if config.fts_enabled:
if os.environ['SERVER_SOFTWARE'] == 'Development/1.0':
- urlfetch.fetch('http://127.0.0.1:20000/index/' + str(topic_num), headers = {"Authorization" : "Basic %s" % base64.b64encode(config.fts_username + ':' + config.fts_password)})
+ try:
+ urlfetch.fetch('http://127.0.0.1:20000/index/' + str(topic_num), headers = {"Authorization" : "Basic %s" % base64.b64encode(config.fts_username + ':' + config.fts_password)})
+ except:
+ pass
else:
urlfetch.fetch('http://' + config.fts_server + '/index/' + str(topic_num), headers = {"Authorization" : "Basic %s" % base64.b64encode(config.fts_username + ':' + config.fts_password)})
- try:
- logging.info('foo')
- except:
- logging.info('Topic #' + str(topic_num) + ' indexed with minor problem')
-
class ReplyEditHandler(webapp.RequestHandler):
def get(self, reply_num):
@@ -8,7 +8,7 @@
<div id="Rightbar">
{% include 'rightbar/user.html' %}
<div class="sep20"></div>
- {% include 'rightbar/ads.html' %}
+ {% include 'rightbar/ad_sample.html' %}
</div>
<div id="Content">
<div class="box">
@@ -33,7 +33,7 @@ <h1 style="padding-top: 0px;">Advertise on V2EX</h1>
</table>
</div>-->
- <span class="bigger">V2EX 是一个由创造者构成的社区。</span>
+ <span class="bigger">V2EX 是创作者们的社区。我们生活中的大部分时刻,都在创作那些人们不曾见过和体会过的美好事物。而其他的时候,我们聚在 V2EX,分享,探索,欢乐,寂静。</span>
<div class="sep10"></div>
<div class="sep20"></div>
<div class="bar">特别推荐给以下类型的广告主</div>
@@ -42,7 +42,7 @@ <h1 style="padding-top: 0px;">Advertisers</h1>
</span>
</td>
<td width="33%" valign="top">
- <a href="http://itunes.apple.com/app/id400003473?mt=8" class="black" onClick="recordOutboundLink(this, 'Outbound Links', 'itunes.apple.com');"><img src="http://web.me.com/v2ex.livid/badges/iview.png" border="0" width="120" height="90" alt="iWeek.ly" /></a>
+ <a href="http://itunes.apple.com/app/id400003473?mt=8" class="black" onClick="recordOutboundLink(this, 'Outbound Links', 'itunes.apple.com');"><img src="http://web.me.com/v2ex.livid/badges/iview.png" border="0" width="120" height="90" alt="iWeek.ly for iPad" /></a>
<div class="sep5"></div>
<span style="font-size: 11px; color: #666;">
<strong style="color: #000;"><a href="http://itunes.apple.com/app/id400003473?mt=8" class="black" onClick="recordOutboundLink(this, 'Outbound Links', 'itunes.apple.com');">周末画报·iWeekly HD for iPad</a></strong><div class="sep3"></div><span style="font-size: 12px;">全新的设计与内容定位 + iPad 对图像优异的表现力,呈现出拥有最佳觉体验的杂志内容</span>
@@ -72,11 +72,13 @@ <h1 style="padding-top: 0px;">Advertisers</h1>
<strong>Promoted by <a href="http://jiepang.com/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" target="_blank" onClick="recordOutboundLink(this, 'Outbound Links', 'jiepang.com');">街旁</a></strong>
<div clas="sep5"></div>
<strong class="fade">Reserved from 10/8 to 10/15, 2010</strong>
- <div class="sep10"></div>
+ <div class="sep5"></div>
+ 街旁是新一代的移动社交平台,帮您和朋友分享在哪里,做什么。你可以记录自己每天的足迹,成为你自己充满回忆的出行日记。还能轻松和朋友分享!街旁还能带你探索身边的城市,发现最潮的店铺和优惠!
+ <div class="sep20"></div>
<table cellpadding="10" cellspacing="0" border="0" width="100%">
<tr>
<td width="33%" valign="top">
- <a href="http://we.jiepang.com/careers/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" target="_blank" onClick="recordOutboundLink(this, 'Outbound Links', 'we.jiepang.com');"><img src="http://web.me.com/v2ex.livid/badges/jiepang.png" border="0" width="120" height="90" alt="iMoney HD" /></a>
+ <a href="http://we.jiepang.com/careers/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" target="_blank" onClick="recordOutboundLink(this, 'Outbound Links', 'we.jiepang.com');"><img src="http://web.me.com/v2ex.livid/badges/jiepang.png" border="0" width="120" height="90" alt="街旁" /></a>
<div class="sep5"></div>
<span style="font-size: 11px; color: #666;">
<strong style="color: #000;"><a href="http://we.jiepang.com/careers/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" class="black" onClick="recordOutboundLink(this, 'Outbound Links', 'we.jiepang.com');">街旁寻 iOS 开发者</a></strong><div class="sep3"></div><span style="font-size: 12px;">街旁是一支短小精悍的团队,期待你的加入 :)</span>
@@ -147,7 +149,15 @@ <h1 style="padding-top: 0px;">Advertisers</h1>
<strong>Promoted by <a href="http://apps.luokai.info/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" target="_blank" onClick="recordOutboundLink(this, 'Outbound Links', 'apps.luokai.info');">lk Design</a></strong>
<div clas="sep5"></div>
<strong class="fade">Reserved from 7/25 to 8/8, 2010</strong>
- <div class="sep10"></div>
+ <div class="sep5"></div>
+ Design 是一个很小规模的手工作坊,主要生产 iOS 系列应用。<br /><br />
+
+ 从 2009 年底开始,我们一直在努力尝试制作各种有意思的应用,虽然在这个巨大的行业里面几乎还没有我们的位置,我们却把它当作是生活的一部分,认真对待并且自然享受。<br /><br />
+
+ 除了制作感兴趣的程序之外,我们还为一些喜欢的乐队设计应用。刚刚结束的一个设计目前正在准备提交苹果,相信很快就可以和大家见面了,我们非常期待,因为我们并不是职业外包生产力,这件事情就像生活一样自然,我们只是作为忠实的乐迷在享受着这份快乐。<br /><br />
+
+ lK Design 目前还仅仅是一个手工作坊而已,远谈不上手工"艺",不过或许这个字就是我们的努力方向。
+ <div class="sep20"></div>
<table cellpadding="10" cellspacing="0" border="0" width="100%">
<tr>
<td width="33%" valign="top">
@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta content="True" name="HandheldFriendly" />
<meta content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0; name='viewport'" />
- <title>{{ page_title|escape }}</title>
+ <title>{{ page_title|escape }}{% if member.notifications %} {% ifequal member.notifications 0 %}{% else %}({{ member.notifications }}){% endifequal %}{% endif %}</title>
<link rel="stylesheet" type="text/css" media="screen" href="/css/{{ site.theme }}.css?v={{ system_version }}" />
<link rel="shortcut icon" href="/favicon.ico" />
{% if feed_link %}
@@ -3,11 +3,10 @@
<div style="width: 240px; text-align: left" >
<span style="font-weight: bold; font-size: 10px; color: #e2e2e2;">Sponsored by</span>
<div class="sep10"></div>
- <a href="/t/742"><img src="http://grab.by/5wO8" border="0" width="120" height="90" alt="V2EXtend" /></a>
+ <a href="http://iweek.ly/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" target="_blank" onClick="recordOutboundLink(this, 'Outbound Links', 'iweek.ly');"><img src="http://web.me.com/v2ex.livid/badges/iweekly_20101018_1.png" border="0" width="120" height="90" alt="iWeek.ly" /></a>
<div class="sep5"></div>
<span style="font-size: 11px; color: #666;">
- <strong style="color: #000;"><a href="/t/742" class="black">V2EXtend</a></strong> <span class="fade" style="font-family: 'Lucida Grande';">›</span> A Greasemonkey based plugin customized for V2EX. Extend your way to explore.
- </span>
+ <strong style="color: #000;"><a href="http://iweek.ly/?utm_source=v2ex&utm_medium=banner&utm_campaign=V2EX" class="black" onClick="recordOutboundLink(this, 'Outbound Links', 'iweek.ly');">周末画报·iWeekly</a></strong><div class="sep3"></div><span style="font-size: 12px;">全球最具影响力的 iPhone 中文媒体 app <span class="fade">•</span> 全面支持 iPhone 4 高清显示</span>
</div>
</div>
</div>
@@ -1,10 +1,6 @@
<div class="box">
{% if member %}
- {% if nodes_fav %}
<div class="cell">
- {% else %}
- <div class="inner">
- {% endif %}
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td width="48" valign="top"><a href="/member/{{ member.username }}">{{ member|avatar:"normal"}}</a></td>
@@ -32,10 +28,7 @@
</form>
{% endif %}
</div>
- {% if nodes_fav %}
- <div class="inner">
- </div>
- {% endif %}
+ <div class="inner">{% ifequal member.notifications 0 %}<a href="/notifications" class="fade">{{ member.notifications }} 条未读提醒</a>{% else %}<img src="/static/img/dot_orange.png" align="absmiddle" />&nbsp;<strong><a href="/notifications">{{ member.notifications }} 条未读提醒</a></strong>{% endifequal %}</div>
{% if member.avatar_large_url %}
{% else %}
<div class="yellow">
Oops, something went wrong.

0 comments on commit bccdf2b

Please sign in to comment.