杯具了,用了有8g居然不能在我的blog登录了

Saturday, Dec 05 21:49, 2009
0 comments/383 hits
看来还是只能用tancee的了,而且好消息是tancee的可以用了。
Author: gzguoer Categories: mindcyclone Tags: GFW

屏蔽机器垃圾留言的简单方法

Friday, Jun 19 13:44, 2009
21 comments/517 hits
最近有一小撮机器频繁地在我这里留垃圾留言,目前只能使用手动删除的原始手段。搞得我不胜其烦。

今天赫然发现右边的最新留言列表里全是垃圾留言,于是我想又该到做些什么的时候了。于是,速度的给添加了一个朴素的验证模块,来区分是否是人类。不过这些机器应该不会解析Javascript吧,要不然我的验证模块就露馅了。

其实也很简单,就是随机生成两个10以内的整数,然后要求用户填入相加得到的结果。

先试试看吧,如果it还能够留言,我就再想想办法,实在不行我就放个“草泥马”的汉字上去,让it输入拼音。恩,这招太狠了,做人要厚道。。。

还不行?我就开这车吓他
img
Author: gzguoer Categories: mindcyclone Tags: BBBlogSpamJavascript

Something about cookie

Monday, Jun 01 17:32, 2009
10 comments/572 hits
之前一直不明白cookie是个什么玩意,这两天看到别人的blog上面有一个功能我非常喜欢,那就是当我在他的blog上留言之后,我再次访问的时候,我就不用再次填入个人信息了,看起来非常之nb。后来发现他是用cookie实现的。实际上浏览器里面有一个cookie的玩意,cookie记录了一些基于站点的数据。

比如我留言之后,在我的浏览器里就留下了三个cookie,分别记录了我在该站点上的用户名,邮箱和网址,这样我下次登录该站点的时候,浏览器会自动把这些cookie信息发送过去,那么服务器就可以得到这些信息,从而显示在相关的地方。

明白了这个东西之后,我发现cookie也just so so啊,没什么神秘的。不就是需要一个把数据输送到用户浏览器的cookie和从cookie中读取数据的两个操作嘛。哈哈。

但是这两个操作怎么实现呢?尤其是在app engine上怎么实现呢?app engine的源代码就是金库啊,我想起来本地调试的时候,登录之后会被记住,这肯定就是cookie了,一查,果然是在cookie里发现了,然后就开始狂找对应的源代码,最后在tools\dev_appserver_login.py的函数LoginCGI里面找到了写cookie的代码,哈哈,赶紧学习。

通过阅读源代码,发现python自带了一个Cookie的类,用以处理这些事情。然后阅读cookie.py的月代码,发现it提供了三种cookie:SimpleCookie,SerialCookie和SmartCookie。而在SDK中使用的是SimpleCookie,由于我也不用是你么cpickle所以也就是用了SimpleCookie。
SimpleCookie的操作方法类似于dict,另外提供了一个load函数,可以把用户通过浏览器传送过来的cookie字符串转化为SimpleCookie对象。

对于读cookie,由于我之前就发现了os.environ中包含了cookie信息,然后加上SimpleCookie的load方法,那么就搞定了。写cookie呢?原始就是往sys.sdout写SimpleCookie对象就行了。

最后还有一个小插曲。在搞定了cookie之后,我看了cookie的RFC 2109,发现我之前使用的cookie的属性expires在RFC2109里解释如下:
Netscape's original proposal defined an Expires header that took a
date value in a fixed-length variant format in place of Max-Age:
他们就为了长度一定就使用那么负责的日期字符串,然后在处理的时候还要再转化为秒,他们完全不知道我使用了如下变态的方法构造出了这个GMT的expires时间:
datetime.datetime.now()+timedelta(days=365)).strftime("%a, %d-%b-%Y %H:%M:%S GMT")

马上就把expires换成了max-age,改进之后的代码如下:
##########写Cookie ############
cookies = Cookie.SimpleCookie()
cookies['comm_name'] = comment.author 
cookies['comm_name']['path'] = '/'
cookies['comm_name']['max-age'] = 3600*24*365
cookies['comm_email'] = comment.authorEmail  
cookies['comm_email']['path'] = '/'
cookies['comm_email']['max-age'] = 3600*24*365
cookies['comm_url'] = comment.authorWebsite 
cookies['comm_url']['path'] = '/'
cookies['comm_url']['max-age'] = 3600*24*365
output_headers = []
output_headers.append('%s\r\n' % cookies)
for header in output_headers:
  sys.stdout.write(header)  

##########读Cookie ############
 cookies = os.environ.get('HTTP_COOKIE', None)
if cookies is not None:
  user_cookie = Cookie.SimpleCookie()
  user_cookie.load(cookies)
  try:
    comm_name = user_cookie['comm_name'].value
    comm_email = user_cookie['comm_email'].value
    comm_url = user_cookie['comm_url'].value
  except KeyError:
    pass        
Over,大功告成!
Author: gzguoer Categories: mindcyclone Tags: BBBlogCookiepython

BBBlog暂时告一段落

Saturday, May 30 20:40, 2009
0 comments/431 hits
昨天修改了gravatar的缓存和显示,其中把gravatar的转发url设置为如下的样子:
/rpc?action=get_gravatar&email=xxx@xxx.com
今天发现这样子不太好,暴露了邮箱地址,和评论时访客填写地址时标注的“will not be published”矛盾(现在还没有成型也没有推广,所以也没有访客,最近baidu使劲的爬我的网站,估计会有闲杂人等出现。。。),显然是不可以的,于是今天改了一下。变成如下所示:
/rpc?action=get_gravatar&id=72f76724e790a6603041bd21bba01675
id实际上就是gravatar_id,这个东西一般人破解不了吧。

改这个的时候,顺便把每篇文章的上一篇和下一篇链接也做了,然后删除了一些测试文件,还有一些没用的函数,模块等。然后剔除了google data library,打包成了初始的0.0.1版,哈哈!

代码放到了google project上了,参见这里:http://code.google.com/p/blowblood/

img
哈哈,小样,整不死你?
Author: gzguoer Categories: mindcyclone Tags: BBBlogBlowBlood

哇哈哈,加速了gravatar的显示

Friday, May 29 22:54, 2009
2 comments/441 hits
根据前两天使用google的URLFetch来翻墙的经验,现在实现了google替我读取gravatar的头像数据,然后返回给我,这样就可以让不能访问gravatar,甚至是gravatar被墙的时候也可以顺利的使用了,哈哈。不错。

不过,现在没有cache,所以每次访问都需要从gravatar服务器上读取信息。当然了,某些浏览器会在你不知情的情况下缓存一些东西,比如firefox,所以我现在在教育网访问也是嗷嗷快。

主要代码如下:
try:
  email = request_.get('email')
except ValueError:
  return response_.out.write("email is invalid")
gravatar_url = util.getGravatarUrl(email)
result = urlfetch.fetch(gravatar_url)
if result.status_code == 200:
  response_.headers['Content-Type'] = "image/png"
  response_.out.write(result.content)
else:
  response_.out.write("No Image")
哈哈,非常简单啊。
Author: gzguoer Categories: mindcyclone Tags: BBBloggravatarurlfetch

修修补补工作(续)

Friday, May 29 16:43, 2009
9 comments/531 hits
这个Blog的bug越来越少了,不过现在性能是个问题,主页的load时间很慢,应该是gravatar的图片问题,但愿近期能够搞定gravatar的缓存吧。

最近修改的问题:
  1. 修改了评论的顺序,现在是按照时间倒序排列;
  2. 修正了侧边栏的id duplication问题,使得现在可以顺利通过XHTML 1.0 Strict验证;
  3. 修正了log中urlencode的error,不过现在url由于被quote所以不可读,期待进一步的改进。。
  4. 缓存所有文章,然后根据不同的page,输出不同的文章段,由于每个memcache的内容最大为1M,所以这个需要进一步改进。
  5. 缓存具体的数据,而不是query本身,这个是最近看到的。我看了一下我的代码,才发现我之前缓存的都是query。。具体说明见下.
如下所示:我需要按时间倒序缓存所有的archives,但是实际上缓存的是一个query实体,而不是具体的结果。
archives = Archive.all().order("-date")
memcache.add(key_, archives, 3600)
修正的方法也很简单,把结果读取出来,放到一个list里即可。
archives_ = Archive.all().order("-date")
archives = [x for x in archives_]
memcache.add(key_, archives, 3600)
接下来要做的事情:
  1. 进一步改进页面的性能,使得主页load时间缩短;
  2. 评论的ajax显示,因为恶心的firefox强制的缓存措施,使的评论功能在firefox下显得特别糟糕
  3. Rich text editor。。。still in todo list
Author: gzguoer Categories: mindcyclone Tags: BBBlogbugXHTML

利用python的装饰函数添加blog的log功能

Wednesday, May 27 21:36, 2009
3 comments/478 hits
早就计划着要做log功能,但是最近琐事缠身,所以一直没有做,明天端午节放假,今晚无事,于是就把这个功能实现了,其实也很简单,利用了python的装饰函数的话更简单了。

首先在新的文件log.py中创建一个函数:
def counter(handler_method):
def wrapper(self, *args, **kwargs):
counter = Counter.all().get()
if counter is None:
counter = Counter()
counter.put()
if not users.is_current_user_admin():
counter.count += 1
counter.put()
return handler_method(self, *args, **kwargs)
return wrapper
该装饰函数实现的功能也非常简单:在数据库中有一个表为Counter,其中只包含一条数据,这条数据只包含一个字段count,代表本blog某些页面被访问的次数总和。设计的这么简单是为了提高效率(感觉上字段越少速度越快,不知道是不是真的)。每次访问的时候,如果不是admin的话,那么就让记录加一。

使用的方法也很简单,在需要加上技术功能的函数前加上标注该装饰函数即可,例如:
class MainPage(BaseRequestHandler):
@log.counter
def get(self):
那么就给主页添加了计数功能,另外我给单篇文章文章展示和主页的paginator部分加上了计数,其他部分,比如category,tag,archieve等,我觉得没有必要就没有加。 另外还用装饰函数实现了记录visitor的功能,还有用普通方法实现了文章hit计数,呵呵,这个更简单了。 P.S visitor记录了USER_EMAIL(if login), REMOTE_ADDR, HTTP_USER_AGENT, HTTP_REFERER, URL.
img
Author: gzguoer Categories: mindcyclone Tags: BBBlogpythondecorationlog

对BBBlog修修补补

Saturday, May 23 16:14, 2009
1 comments/458 hits
sigh, 英语不好,有些时候就是不行,刚刚改了半天的permalink,最后把原始的permalink替换成新的permalink了。。。问题就出在这里,permalink是固定连接,永久链接,是不能失效的,如果替换了的话,原有的连接就失效了,比如从reader里连接过来就发现页面不存在了。。于是,我只好灰溜溜的把原来的permalink有找回来,现在对于之前的每篇文章都有两个permalink,而新的文章当然只有一个permalink了。

另外,今天下午还重写了Category相关的地方,主要包含了新增文章,修改文章的category选择框,侧边栏categories显示部分,category视图,管理页面的category相关部分。真多啊,前一发动全身,不过还是硬着头皮做完也没费多少时间。

另外,对于memcache的模块,删掉了大多数的cache,现在只会cache侧边栏四个列表:recent comments,archives,categories和tags。恩,日历是直接生成的,反正也没有数据库操作,非常快。此外,就还有一个PublicPostList需要cache。

如果再加上一个Log记录,那么前台所有的东西就搞定了。不错bug肯定还是要不断的修修补补才能陆续写完。后台的部分,当然是rich text editor了。现在还很简陋。
Author: gzguoer Categories: mindcyclone Tags: BBBlogmemcachePermalink

学习的代价

Saturday, May 23 13:58, 2009
4 comments/417 hits
之前上学的时候,经常听到一种关于考试抄袭说法:如果某人的错误和另外一个人的错误雷同,那么就可以认为某人在抄袭。做就是抄袭的弊端,连错误或者说不好的地方也抄袭过来。

在本博客的后台程序的完成过程中,不可避免的学习了大量的其他优秀blog程序的优点,但是由于在学习的时候产生了先入为主的思想,所以使得对于某些设计不合理的地方,也认为是“就应该这么设计,这样是最好的”想法。从而使得自己的设计也不能得到进一步的提高。这就是学习的代价。当然了,学习别人还是必须得,只是要在学习的时候学会独立思考。

今天躺在床上的时候,我突然想不起来对于这个blog系统,某一片文章是怎么展示的。我记得用到一个变量permalink,而且这个permalink产生的过程,相仿的复杂。每篇文章的url格式如下所示:

youdomain.com/2009/5/your-english-title

之前一直以为这是个不错的想法,直接从url就可以看出文章的年月河标题,可能是有利于搜索引擎或者是对用户友好?但是后来查询代码才发现在每次显示文章的时候,都会进行一次数据库关于permalink比较的查询:

post = db.Query(Post).filter('permalink =',perm_stem).get()

然后,我就想为啥不对文章id使用更加高效的get_by_id的方法产生,对于我立马重构了url,现在时通过

youdomain.com/post/post_id

这样的url来访问实际的地址的。而查询blog的语句也变得更加的高效:

    post_id_ = int(post_id)
    post = Post.get_by_id(post_id_)

同时由于原来的permalink没用了,所以在博客创建的时候也省掉了复杂的把文章标题转化为英语的过程。之前转化的过程为:先对文章标题进行trim,然后调用tranlaite.google.com,再用BeautifulSoap得到结果页面中ID为result_box的div的内容,并且用‘-’代替其中的空格。整个过程非常的麻烦,还容易出错。我之前就一直想怎么解决这个问题,现在好了。问题根本就不存在了,哈哈。

注1:通过baidu所搜我得知,原始样式的链接是通过设置WordPress中的url参数为: /%year%/%monthnum%/%postname%/ 来实现的。鉴于大量的博客使用WordPress,所以使用这样的url也就不为奇怪了。但是我发现更大量的博客使用的是/archives/%post_id%, 也有人使用由于本博客的archive用于显示archive(好像的确应该这样吧),那么文章就只好选择之前描述的那样:/post/%post_id%的样式了。
注2:系统之中还有一些别的不太好的地方,比如可以利用GAE数据库提供的reference_set的强大功能,大大简化数据库查询操作的,但是因为不太好改了,所以就不想改了。
Author: gzguoer Categories: mindcyclone Tags: BBBlog潜意识Permalink

搞定了Archives

Thursday, May 21 22:35, 2009
0 comments/376 hits
今天搞定了Archives,顺便修正了一个Ajax代码在firefox的bug,当'POST'模式调用ajax请求时,在firefox下使用ajax.send(null)会产生411:Length Required错误。把ajax.send(null)换成ajax.send('')即可。
恩,大多数的前台的问题都差不多搞定了。
恩,还有log记录还没有做。。
Author: gzguoer Categories: mindcyclone Tags: BBBlogArchivesAjax

Ajax入门(python webapp服务端)

Thursday, May 21 17:46, 2009
0 comments/546 hits
Ajax用了才知道这玩意好,可以在后台偷偷的干一些坏事,哈哈,适合我的风格。

Ajax其实就是Asychronous JavaScript and XML,不过和XML的关系不太大,因为XML这种语言因为通用所以臃肿。不太适合小型应用。说的通俗点,就是使用一种叫做XMLHttpRequest的浏览器对象,偷偷的在后台访问服务器,得到服务器反馈后,就可以更新当前页面的局部数据,或者不更新(就是干坏事的时候)。

这种XMLHttpRequest对象实际上就像一个mini的浏览器对象,打开一个网址,然后发送'GET'或者'POST'请求,附带上一些数据,注意:对于'POST'请求一定要使用:

setRequestHeader("Content-length", len(yourdate));

来设置'POST‘请求发送的数据长度,如果没有数据,则直接设为0,这在发送某些命令时会使用到。

XMLHttpRequest的创建方法有很多种,其中的种类多样性显然是源自于IE浏览器的种类繁多和彼此不兼容。各种浏览器有各自不同的XMLHttpRequest,我也懒得自己研究,在wiki上找了一个创建方法,就直接使用了:
ajaxObject = function() {
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e){
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e){
try { return new XMLHttpRequest(); } catch(e){
throw new Error( "This browser does not support XMLHttpRequest." );
}}}}
var ajax = new ajaxObject();
接下来就可以使用创建好的XMLHttpRequest对象ajax来完成我们的ajax任务了。
ajax.onreadystatechange = function(){
if(ajax.readyState < 4){$(action).innerHTML="building";}
if(ajax.readyState == 4&& ajax.status == 200){
$(action).innerHTML=ajax.responseText;}}
pwurl = "/rpc?action="+action;
try{ajax.open("POST",pwurl,true);} catch(e){alert(e);}
ajax.setRequestHeader("Content-length", 0);
ajax.send(null);
上述javascript实现的功能就是往wpurl网站的rpc接口发送名称为action的操作,其中发送的数据为空,在请求未返回是,原始页面id为action的元素显示“loading”,当操作完成后显示返回的结果。该例采用了'POST'方法,只用了8行javascript代码就可以完成一个ajax实现,是不是好简单啊。哈哈:) 如果是采用'GET'方法的话,第7行都可以省略了,并且把第6行改成如下语句就行了。

try{ajax.open("GET",pwurl,true);} catch(e){alert(e);}

看来Ajax这种东西的面纱一揭下来也没什么神秘的。就是打开一个网址,发送点数据,然后等待结果,并且反馈给页面而已。
Author: gzguoer Categories: mindcyclone Tags: AjaxXMLHttpRequestPythonwebapp

这几天的blog进展

Thursday, May 21 16:52, 2009
1 comments/525 hits
这几天比较忙,同时所做的事情难度也越来越大,每天都要学习新的东西,所以进度很慢。
这几天完成的进度为:
  1. 完成评论的数据库创建,记录评论的作者,内容,作者的邮箱(用于gravatar显示头像)和作者的网址(用来显示在品论列表里)等;
  2. 在每篇文章末尾显示评论和添加评论的表单(UI部分参考的iNove),对于登陆用户会自动填写评论栏的用户名和邮箱(当然是gmail了。。。);
  3. 在侧边栏显示最新的评论,最多8条;
  4. 给每条评论增加了AJAX请求具体评论的功能;用了AJAX才知道AJAX技术真是简单又实用,真的很强大;
  5. 修改admin页面,使得现在可以查看/管理memcache,categories,tags等信息
  6. 给页面的绝大部分连接添加nofollow属性,发现google.com搜索我的页面还算比较勤快的,虽然google.com不懂中文。。。
  7. 支持gravatar头像显示;
  8. 侧边栏的评论现实时,去掉html标签,并且显示字数为50个
  9. 增加tags功能,现在侧边栏的tags是真的了:)
接下来还要做的事情:
  1. rich text editor的进一步改进;
  2. 增加achieve功能,和categories的效率改进(虽然很简单,但是懒的写了。。)
  3. 整体页面的memcache的重新设计,改进某些装在速度,可能使用AJAX装在侧边栏。
Author: gzguoer Categories: mindcyclone Tags: BBBlogPythonAJAX

XHTML valid的一些心得

Monday, May 18 11:05, 2009
4 comments/578 hits

在这个博客网站网站的制作过程中,用户所见页我都使用了XHTML 1.0 Strict和CSS3标准验证。
其中css部分由Inove模板的作者完成,XHTML部分则有我自己写好。
写的过程中遇到很多问题,主要是原来没有写过XHTML代码,甚至连HTML都没怎么写过。所以很多尝试都不知道,哈哈。

下面介绍一些我这个新手在这段时间取得的心得:

  1. 标签元素要闭合,包括空标签的闭合,比如<br />;
  2. url地址中不要使用&,而是采用&amp;这个对于自己的url地址还好说,可以自己生成,主要需要注意google account的login和logout帐户的url地址的转化,其实也很简单,就是用str.replace或者re模块把&转化成&amp;就可以了;
  3. img标签需要一个alt属性,用来在图片不能显示的时候,显示alt中的文本;
  4. blockquote内部需要一个块级元素,比如是div、p等;
  5. 所有的标签和属性都是用小写;
  6. 每个标签的属性值都需要使用双引号""括起来;
  7. 对于最小化的二值属性,应该使用完成模式,这些属性包括:compact, nowrap, ismap, declare, noshade, checked, disabled, readonly, multiple, selected, noresize, defer。完成属性形式为:checked="checked";
  8. 不要是注释hack XHTML中的javascript代码;
  9. 对于元素a, applet, form, frame, iframe, img和map使用id属性来标记这些元素,而不要使用name,实际上,除了form中的input,select,textarea等需要在服务器端获取信息的元素之外,其他的地方尽量避免使用name属性;
  10. 主文件需要使用utl-8编码,并且是没有BOM信息的。
Author: gzguoer Categories: mindcyclone Tags: XHTMLBBBlog

添加了分页功能和日历

Sunday, May 17 18:09, 2009
1 comments/502 hits
今天添加了右侧的日历和文章的分页功能。
分页暂时受到总数1000的限制,不过我估计三年之后才会遇到这个问题,暂时就不更新了。

日历也非常简单,采用了python自带的caleander.HTMLCalendar直接实现产生HTML版的日历代码,然后再用re模块给当天日期加上today id。如右侧日历所示。
img
Author: gzguoer Categories: mindcyclone Tags: BBBlogCanlendarPaginator

给rich text editer添加大量功能

Friday, May 15 19:17, 2009
1 comments/575 hits
今天添加的功能包括:粗体,斜体,下划线,贯穿线,居左,居中,居右,插入链接,取消链接,插入块引用。
另外还修正了之前图片上传的一个小bug。
此外,还把rich text editor的代码集中放到了static的目录下。
其实,实现上述的功能非常的简单,比如要实现加粗效果,那么只需要在工具栏添加:

<a href="javascript:rteAction('bold')">B</a>

然后在实现如下的js代码即可

function rteAction(param) {
   document.execCommand(param, false, null);  
};

哈哈,超级简单啊,如果要实现斜体,只需要把bold换为italic即可。对于execCommand能够接受的参数,请参见这里,不同浏览器对于execCommand的兼容性请参见这里,对于超链接的实现超微复杂一点,但是也是超级简单。
另外,我发现我之前的那个弹出半透明div里面使用js添加iframe的方法,真是好用啊。使用iframe之后,不影响原来的页面的选中区域,同时之间可以使用parent, conetWindow等方法互相调用。再加上高人指点的服务器端调用客户端js的方法,现在多方通信很流畅,哈哈。
Author: gzguoer Categories: mindcyclone Tags: BugBBBlogRTE

今天搞定了Category

Thursday, May 14 20:16, 2009
0 comments/421 hits
恩,不错。接下来把评论和achieve和tags搞定就差不多圆满了。
Author: gzguoer Categories: mindcyclone Tags: Category

Picasa外链的使用

Thursday, May 14 14:53, 2009
0 comments/446 hits
昨天一直怀疑的picasa外链的问题,原来是因为google为了防止技术不行的人使用滥用图片,所以增加了一些外链的难度,并且使得外链的图片大小收到限制,如下图所示:
img
原来要在外部链接使用宽度或者高度限定参数(上图中的尺寸指的是高度参数)来限制外链图的大小。参考google web albums的reference guide.
所以,对于原始的图片地址,比如http://*.ggpht.com/*/blogimg.jpg, 可以使用如下的两种方式外链:
  • http://*.ggpht.com/*/s512/blogimg.jpg
  • http://*.ggpht.com/*/blogimg.jpg?imgmax=512
我采用了第二种,因为简单嘛,哈哈。直接在原始链接后面加东西就行了。选择512是因为这个数字在我做图像处理的工作中非常熟悉,另外就是我的blog主体宽度是600px。所以选择512比较美观,哈哈。

另外,经过高人指点我的upload页面变得更加简单高效了。
@authorized.role("admin")
def post(self):
filename = self.request.get('imgfile')
filetitle = self.request.get('imgtitle')
file_handle = StringIO.StringIO(filename) #convert string to file-like object
gd_client = gdata.photos.service.PhotosService()
gd_client.email = 'gzguoer@gmail.com'
gd_client.password = bbpsw.getpassword()
gd_client.source = 'blowblood-upload-image'
gd_client.ProgrammaticLogin()
album_url = '/data/feed/api/user/gzguoer/albumid/5334765855583692065'
try:
photo = gd_client.InsertPhotoSimple(album_url, 'blogimg',filetitle,
file_handle, content_type='image/jpeg')
img_url = photo.GetMediaURL()+"?imgmax=512"
self.response.out.write('<script type="text/javascript">
window.parent.rteGetImage("%s")</script>' % img_url)
except gdata.service.RequestError:
self.response.out.write(GooglePhotosException)
上传完毕之后,直接调用该iframe他爹的javascript函数rteGetImage函数,并且把图片的外链url传输过去,哈哈,然后他爹页面把图片外链url做成一个img标签,嵌入到rich text editor的编辑区域中,并且关闭这个上传页面。哈哈,不错。下面再来一幅nb图像,看看我的摄影技术,哈哈。
img
Author: gzguoer Categories: mindcyclone Tags: PicasaExternal_link

haha! wonderful!

Thursday, May 14 10:11, 2009
0 comments/467 hits
it's amazing:) kiss~
Author: xqlonger Categories: mindcyclone Tags: excited

实现图片上传到gogole picasa的步骤

Wednesday, May 13 18:09, 2009
2 comments/603 hits
要在app engine中使用google的picasa的上传服务,首先需要安装 Google Data Python Library包,步骤在此, 安装完毕后需要把src下的atom和gdata文件夹放到app的根目录。
然后,可以在python shell中使用python下耍耍这个功能。
这个时候遇到第一个问题:

def InsertPhotoSimple(self, album_or_uri, title, summary, filename_or_handle,
        content_type='image/jpeg', keywords=None)

如上语句里面的fielname_or_handle,人家说是一个A file-like object or file name where the image/video will be read from。可惜我不太会python,所以不知道是个啥玩意。后来发现,这个东东可以使本地文件的绝对路径,哈哈。太nb了,至今我还不能获得用户选择的文件的绝对路径。。
对于file类的input元素,javascipt获得的是文件名,服务器端使用request.get获得的是文件的内容。幸好后来偶然知道了StringIO这个东西,哈哈,就是把字符串伪装成文件的,也就是传说中的a file-like object,那么接下来的任务就很简单了。
首先使用form中的file input元素把文件的内容传送到服务器,服务器收到数据后使用StringIO把它转化为a file-like object,然后就可以使用InsertPhotoSimple函数把图片上传到picasa了。该函数返回上传后的文件的"句柄",我们根据这个“句柄”来得到图片的外联地址。代码如下所示(注意使用gdata.url来覆盖uanshi的http_request_handler):
import gdata.urlfetch
gdata.service.http_request_handler = gdata.urlfetch
#override original http handler
...
filename = self.request.get('imgfile')
filetitle = self.request.get('imgtitle')
file_handle = StringIO.StringIO(filename)#convert string to file-like object
gd_client = gdata.photos.service.PhotosService()
gd_client.email = 'gzguoer@gmail.com'
gd_client.password = bbpsw.getpassword()
gd_client.source = 'blowblood-upload-image'
gd_client.ProgrammaticLogin()
album_url = '/data/feed/api/user/gzguoer/albumid/5334765855583692065'
try:
photo = gd_client.InsertPhotoSimple(album_url, 'blogimg',filetitle,
file_handle,content_type='image/jpeg')
template_values = {
'imgtitle':'title',
'img_url':photo.GetMediaURL(),
'response':'upload_complelted,<a href="javascript:getimgurl()">use it</a>',
}
path = os.path.join(os.path.dirname(__file__), '../templates/upload.html')
self.response.out.write(template.render(path, template_values))
except gdata.service.RequestError:
self.response.out.write(GooglePhotosException)
*另外注意密码保护,由于本程序可以在google code上下载到,所以密码我保存到本机的bbpsw类中,然后定义一个方法getpassword得到密码,或许由更好的方法,但是我不想在每次上传图片的时候跳转到别的页面,所以还是采用这种方法了。 还遇到一个问题:就是图片上传完毕之后,服务器端不好触发客户端的javascript程序,所以我直接产生一个use it的超链接,触发javascript函数,把图片的地址做成img标签,然后加入到编辑页面中。如果不这么做,或许我需要ajax?我不想学那么多新东西啊。。。
P.S. 插入图片的iframe在/upload下可以看到(为了防止低级别坏人滥用,所以我没有写超连接。)上传之后的图片会出现在我的picasa相册的bbblog目录。
总结一下:通过学习做这个按钮,我学习了以下的东西:
form的使用
iframe的使用
google data服务
超多javascipt使用,这语言真的很强大,但是很难用。
夕阳西下,回家了,哈哈!!
Author: gzguoer Categories: mindcyclone Tags: BBBlogPicasaimage_upload

测试图片功能

Wednesday, May 13 17:08, 2009
0 comments/415 hits
哈哈,测试图片输入功能,应该可以用了,现在blog里的所有图片都可存储在我的google相册里面的bbblog目录下。
Image
啊?编辑状态下居然不能预览图片。。。这个不知道是哪里的问题,我直接使用别的网站的图片地址是可以用的,为什么在我的编辑器下不行呢?难道是我编辑的时候它正在下载吗?哈哈。这个有点搞笑了。下载速度这么慢。。。
不过好像不是啊,我把图片的地址换成别的,都是可以直接在编辑器里显示,而且我直接输入图片地址也是可以看到图片的,难道google的这玩意对自家兄弟的请求设置了某种不可告人的限制?
哦,现在突然好了,不知道是什么原因。。
再贴一副小的试试
http://lh5.ggpht.com/_0vQB3OwI7l4/SgqSnN7yQII/AAAAAAAAAOQ/NJKmhMnl_BQ/blogimg.jpg
看来还是不行啊,非得等半天。。。。
我用firebug查看了一下这个图片,赫然发现就可以显示出来了。难道真的是app engine对于google picasa的请求会被拒绝掉吗?这也太发指了吧。
Author: gzguoer Categories: mindcyclone Tags: PicasaRTEimage_upload

几个不错的生成XHTML输出的Rich Text editor

Sunday, May 10 01:28, 2009
0 comments/458 hits

在google上找了半天,终于发现几个非常不错的XHTML的网页编辑器。

XStandard:

功能强大,稳定,而且历史悠久,兼容性等非常好,但是客户端非常大,而且免费的lite版本用起来限制很多。同时每次在新的机器上使用的时候,都需要安装一下程序。。。

FCKeditor:

非 常好用的编辑器,baidu空间使用的就是这个,支持多国语言,使用方便,去它的网站http://www.fckeditor.net/ 上看的时候发现Oracle和Adobe都是用了该编辑器,呵呵,看来用户还是很多的。但是许可协议比较猛:GPL,LGPL,MPL,三个 Copyleft协议都有,所以我退却了。

TinyMCE:

以LGPL发布,功能非常的强大。网址为:http://tinymce.moxiecode.com/ 而且还可以搭配文件管理和图片管理插件,估计是用起来非常爽。

Free Rich Text Editor:

支持xhtml输出,支持code/edit/preview三种模式之间切换,支持插入图片,支持各种浏览器,估计我将使用这个nb的XHTML的编辑器作为我这个系统的输入工具。。不过发现一个小问题

Author: gzguoer Categories: mindcyclone Tags: BBBlogXHTMLRTE

完成ATOM的feed输出

Friday, May 08 14:26, 2009
0 comments/388 hits

我记得原来订阅的RSS,怎么现在都交ATOM了呢?到网上查了一下,才发现ATOM是RSS的升级版。。。比RSS简单,而且可以同时支持摘要和全文,虽然我只想要全文。

要支持ATOM的Feed也很简单,首先在首页的head里面加上如下的语句,这样可以让Firefox等浏览器检测到该页含有Feed链接,从而在地址栏或者其他的地方出现一个Feed标志的小图标:

<link rel="alternate" type="application/atom+xml" title="BlowBlood" href="http://www.blowblood.com/atom">

然后制作/atom页面即可。首先在main.py里面添加url的控制语句,使得/atom页面被blog类的相应方法:FeedHandler所控制,然后在FeedHandler方法中构建atom页面需要的内容,主要是每个post的内容,和该次更新的时间,时间可以取最新一篇post的时间(如果没有的话,则取当前时间),然后把这些数据输出到文件atom.xml中即可。atom.xml的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title><![CDATA[BlowBlood]]></title>
    <id>http://www.blowblood.com-by-gzguoer</id>
    <subtitle>BlowBlood@WestGate</subtitle>
    <link href="http://www.blowblood.com" />
    <link href="http://www.blowblood.com/atom" rel="self" />
    <updated>{{last_updated}}</updated>
    <author>
      <name>blowblood</name>
    </author>
    {%for post in posts%}
  <entry>
      <link href="{{post.full_permalink}}"/>
      <id>{{post.full_permalink}}</id>
      <title><![CDATA[ {{post.title}} ]]></title>
      <content type="html"><![CDATA[ {{post.content}} ]]></content>
      <author>
          <name>{{post.author}}</name>
      </author>
      <updated>{{post.formatted_date}}</updated>
  </entry>
     {%endfor%}
</feed>

然后就行了,哈哈,是不是非常简单呢?

不过有个很普遍的问题,msIE6出生的时候,还没有RSS这玩意,或者没有引起关注,总之IE6还不支持atom,应该有办法可以解决。。

恩,这个编辑器真的不太好用,非常郁闷,在Code和View之间切换的时候,<br />会变成<br>,而且光标所在也不对。。。难道逼我改进吗?或者我直接换一个nb的richtexteditor?

Author: gzguoer Categories: mindcyclone Tags: BBBlogATOM

测试一下

Thursday, May 07 16:06, 2009
0 comments/385 hits

测试一下多管理员模式,哈哈,好像可以用啊!

Author: xqlonger Categories: mindcyclone Tags: multi-userBBBlog

接下来的任务

Wednesday, May 06 20:33, 2009
0 comments/489 hits

接下来的任务:

  • 增加回复功能
  • 增加每篇文章的访问、回复计数功能
  • 增加整个网站的点击计数功能
  • 激活Archives和Tags cloud功能
  • 增加feed功能
  • 使用memcached来优化网站系统
恩,努力完成it!
Author: gzguoer Categories: mindcyclone Tags: BBBlog

今天完成的任务

Wednesday, May 06 20:15, 2009
1 comments/540 hits

这周总的来说没有什么事情,所以抓紧时间把这个blog系统搞起来,之前采用cpedia做的那个各种不爽,索性自己从头来做一遍。

之前已经建立好了关于blog的文章的数据库,具体的model描述如下所示:

class Post(db.Model):
    permalink = db.StringProperty()
    title = db.StringProperty()
    content = db.TextProperty()
    date = db.DateTimeProperty(auto_now_add=True)
    author = db.UserProperty()
    catalog = db.StringProperty()
    private = db.BooleanProperty()    
    hitcount = db.IntegerProperty(default=0)
    commentcount = db.IntegerProperty(default=0)
    lastModifiedDate = db.DateTimeProperty()
    lastModifiedBy = db.UserProperty()
    tags = db.ListProperty(db.Category)
    monthyear = db.StringProperty(multiline=False)
由于没有评论的数据库,所以不能评论,今天完成的任务如下:
  1. 应用WordPress的主题iNove到我这里,哈哈,现在真pp;
  2. 修复bug,尤其是google提供的url地址的xhtml化...(实际上就是用&amp;来代替&);
  3. 修改部分代码使得通过xhtml1.1和css3测试;
  4. 增加文章删除和修改功能;
  5. 文章的分类和tag现在可用了。但是右边的tag cloud还不能用,archives也不能用;

恩,干的不错,加油!马上就要写答辩ppt了,所以时间无多啊。。。

Author: gzguoer Categories: mindcyclone Tags: BBBlog