Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

commit first

  • Loading branch information...
commit e090a3060e7bf1d7ec2f560c01f67c318420250a 0 parents
jason authored
Showing with 31,283 additions and 0 deletions.
  1. +17 −0 README
  2. +40 −0 Rakefile
  3. +49 −0 app/controllers/application_controller.rb
  4. +38 −0 app/controllers/cpanel/application_controller.rb
  5. +86 −0 app/controllers/cpanel/categories_controller.rb
  6. +44 −0 app/controllers/cpanel/comments_controller.rb
  7. +41 −0 app/controllers/cpanel/home_controller.rb
  8. +86 −0 app/controllers/cpanel/menus_controller.rb
  9. +91 −0 app/controllers/cpanel/pages_controller.rb
  10. +129 −0 app/controllers/cpanel/posts_controller.rb
  11. +32 −0 app/controllers/cpanel/settings_controller.rb
  12. +39 −0 app/controllers/home_controller.rb
  13. +157 −0 app/controllers/posts_controller.rb
  14. +67 −0 app/helpers/application_helper.rb
  15. +62 −0 app/helpers/application_helper.rb.save
  16. +2 −0  app/helpers/comments_helper.rb
  17. +2 −0  app/helpers/home_helper.rb
  18. +2 −0  app/helpers/menus_helper.rb
  19. +6 −0 app/helpers/pages_helper.rb
  20. +2 −0  app/helpers/posts_helper.rb
  21. +2 −0  app/helpers/settings_helper.rb
  22. +11 −0 app/models/category.rb
  23. +59 −0 app/models/comment.rb
  24. +30 −0 app/models/comment_observer.rb
  25. +15 −0 app/models/fanfou.rb
  26. +12 −0 app/models/menu.rb
  27. +36 −0 app/models/page.rb
  28. +127 −0 app/models/post.rb
  29. +20 −0 app/models/post_observer.rb
  30. +61 −0 app/models/setting.rb
  31. +33 −0 app/models/share.rb
  32. +25 −0 app/models/tag.rb
  33. +17 −0 app/models/tweet.rb
  34. +39 −0 app/models/user.rb
  35. +19 −0 app/sweepers/category_sweeper.rb
  36. +37 −0 app/sweepers/comment_sweeper.rb
  37. +15 −0 app/sweepers/menu_sweeper.rb
  38. +19 −0 app/sweepers/page_sweeper.rb
  39. +35 −0 app/sweepers/post_sweeper.rb
  40. +12 −0 app/sweepers/setting_sweeper.rb
  41. +16 −0 app/views/cpanel/categories/_submenu.html.erb
  42. +23 −0 app/views/cpanel/categories/edit.html.erb
  43. +33 −0 app/views/cpanel/categories/index.html.erb
  44. +37 −0 app/views/cpanel/comments/index.html.erb
  45. +41 −0 app/views/cpanel/home/index.html.erb
  46. +38 −0 app/views/cpanel/home/login.html.erb
  47. +15 −0 app/views/cpanel/menus/_submenu.html.erb
  48. +31 −0 app/views/cpanel/menus/edit.html.erb
  49. +35 −0 app/views/cpanel/menus/index.html.erb
  50. +15 −0 app/views/cpanel/pages/_submenu.html.erb
  51. +41 −0 app/views/cpanel/pages/edit.html.erb
  52. +36 −0 app/views/cpanel/pages/index.html.erb
  53. +17 −0 app/views/cpanel/posts/_submenu.html.erb
  54. +69 −0 app/views/cpanel/posts/edit.html.erb
  55. +30 −0 app/views/cpanel/posts/importblogbus.html.erb
  56. +38 −0 app/views/cpanel/posts/index.html.erb
  57. +12 −0 app/views/cpanel/settings/_submenu.html.erb
  58. +58 −0 app/views/cpanel/settings/index.html.erb
  59. +28 −0 app/views/cpanel/settings/password.html.erb
  60. +26 −0 app/views/home/_fanfou.html.erb
  61. +26 −0 app/views/home/_recent_post.html.erb
  62. +3 −0  app/views/home/_side_show.html.erb
  63. +26 −0 app/views/home/_tweet.html.erb
  64. +7 −0 app/views/home/_webicons.html.erb
  65. +17 −0 app/views/home/error.html.erb
  66. +11 −0 app/views/home/index.html.erb
  67. +23 −0 app/views/home/share.html.erb
  68. +94 −0 app/views/layouts/application.html.erb
  69. +83 −0 app/views/layouts/cpanel.html.erb
  70. +6 −0 app/views/pages/show.html.erb
  71. +31 −0 app/views/posts/_comments.html.erb
  72. +41 −0 app/views/posts/_posts.html.erb
  73. +97 −0 app/views/posts/_sidebar.html.erb
  74. +11 −0 app/views/posts/index.html.erb
  75. +21 −0 app/views/posts/rss.rxml
  76. +66 −0 app/views/posts/show.html.erb
  77. +110 −0 config/boot.rb
  78. +74 −0 config/environment.rb
  79. +19 −0 config/environments/development.rb
  80. +28 −0 config/environments/production.rb
  81. +28 −0 config/environments/test.rb
  82. +7 −0 config/initializers/backtrace_silencers.rb
  83. +10 −0 config/initializers/inflections.rb
  84. +5 −0 config/initializers/mime_types.rb
  85. +19 −0 config/initializers/new_rails_defaults.rb
  86. +3 −0  config/initializers/rakismet.rb
  87. +15 −0 config/initializers/session_store.rb
  88. +5 −0 config/locales/en.yml
  89. +131 −0 config/locales/zh_cn.yml
  90. +6 −0 config/memcache.yml
  91. +41 −0 config/routes.rb
  92. +6 −0 db/import/index.html
  93. +16 −0 db/migrate/20090413152411_create_posts.rb
  94. +16 −0 db/migrate/20090413154027_create_pages.rb
  95. +15 −0 db/migrate/20090413154146_create_menus.rb
  96. +17 −0 db/migrate/20090413154413_create_shares.rb
  97. +18 −0 db/migrate/20090413155254_create_comments.rb
  98. +13 −0 db/migrate/20090413155442_post_fellow.rb
  99. +14 −0 db/migrate/20090414133351_create_table_user.rb
  100. +13 −0 db/migrate/20090416164745_add_new_window_to_menus.rb
  101. +13 −0 db/migrate/20090418165125_add_view_count_to_posts.rb
  102. +13 −0 db/migrate/20090418165332_add_comment_count_to_posts.rb
  103. +13 −0 db/migrate/20090418170234_create_tags.rb
  104. +18 −0 db/migrate/20090501114903_create_settings.rb
  105. +13 −0 db/migrate/20090501171421_add_fanfou_id_to_settings.rb
  106. +13 −0 db/migrate/20090502081323_add_blog_feed_html_to_settings.rb
  107. +15 −0 db/migrate/20090517034648_add_meta_to_posts.rb
  108. +13 −0 db/migrate/20090517061014_add_google_reader_id_to_settings.rb
  109. +18 −0 db/migrate/20090517064606_remove_shares.rb
  110. +13 −0 db/migrate/20090524113052_create_posts_tags.rb
  111. +11 −0 db/migrate/20090721085828_retotal_comment_count.rb
  112. +41 −0 db/migrate/20090815043049_add_sitemap_table.rb
  113. +19 −0 db/migrate/20090828013049_remove_tag_table.rb
  114. +15 −0 db/migrate/20090828013050_create_categories.rb
  115. +13 −0 db/migrate/20090828013051_add_category_to_posts.rb
  116. +29 −0 db/migrate/20090828031328_acts_as_taggable_on_migration.rb
  117. +13 −0 db/migrate/20090828031330_add_posts_count_to_categories.rb
  118. +14 −0 db/migrate/20090909030001_add_user_client_to_comments.rb
  119. +145 −0 db/schema.rb
  120. +2 −0  doc/README_FOR_APP
  121. +249 −0 doc/app/classes/ApplicationController.html
  122. +158 −0 doc/app/classes/ApplicationHelper.html
  123. +105 −0 doc/app/classes/BlogsHelper.html
  124. +172 −0 doc/app/classes/Comment.html
  125. +180 −0 doc/app/classes/CommentObserver.html
  126. +205 −0 doc/app/classes/CommentSweeper.html
  127. +105 −0 doc/app/classes/CommentsHelper.html
  128. +113 −0 doc/app/classes/Cpanel.html
  129. +231 −0 doc/app/classes/Cpanel/ApplicationController.html
  130. +202 −0 doc/app/classes/Cpanel/CommentsController.html
  131. +226 −0 doc/app/classes/Cpanel/HomeController.html
  132. +334 −0 doc/app/classes/Cpanel/MenusController.html
  133. +331 −0 doc/app/classes/Cpanel/PagesController.html
  134. +355 −0 doc/app/classes/Cpanel/PostsController.html
  135. +185 −0 doc/app/classes/Cpanel/SettingsController.html
  136. +666 −0 doc/app/classes/Guid.html
  137. +181 −0 doc/app/classes/HomeController.html
  138. +105 −0 doc/app/classes/HomeHelper.html
  139. +146 −0 doc/app/classes/Menu.html
  140. +194 −0 doc/app/classes/MenuSweeper.html
  141. +105 −0 doc/app/classes/MenusHelper.html
  142. +193 −0 doc/app/classes/Page.html
  143. +140 −0 doc/app/classes/PagesHelper.html
  144. +312 −0 doc/app/classes/Post.html
  145. +155 −0 doc/app/classes/PostObserver.html
  146. +194 −0 doc/app/classes/PostSweeper.html
  147. +243 −0 doc/app/classes/PostsController.html
  148. +105 −0 doc/app/classes/PostsHelper.html
  149. +181 −0 doc/app/classes/Setting.html
  150. +170 −0 doc/app/classes/SettingSweeper.html
  151. +105 −0 doc/app/classes/SettingsHelper.html
  152. +111 −0 doc/app/classes/Share.html
  153. +356 −0 doc/app/classes/SharesController.html
  154. +105 −0 doc/app/classes/SharesHelper.html
  155. +200 −0 doc/app/classes/String.html
  156. +111 −0 doc/app/classes/Tag.html
  157. +170 −0 doc/app/classes/User.html
  158. +1 −0  doc/app/created.rid
  159. +109 −0 doc/app/files/app/controllers/application_controller_rb.html
  160. +109 −0 doc/app/files/app/controllers/cpanel/application_controller_rb.html
  161. +111 −0 doc/app/files/app/controllers/cpanel/comments_controller_rb.html
  162. +107 −0 doc/app/files/app/controllers/cpanel/home_controller_rb.html
  163. +111 −0 doc/app/files/app/controllers/cpanel/menus_controller_rb.html
  164. +111 −0 doc/app/files/app/controllers/cpanel/pages_controller_rb.html
  165. +101 −0 doc/app/files/app/controllers/cpanel/posts_controller_rb.html
  166. +101 −0 doc/app/files/app/controllers/cpanel/settings_controller_rb.html
  167. +101 −0 doc/app/files/app/controllers/home_controller_rb.html
  168. +101 −0 doc/app/files/app/controllers/posts_controller_rb.html
  169. +101 −0 doc/app/files/app/controllers/shares_controller_rb.html
  170. +108 −0 doc/app/files/app/helpers/application_helper_rb.html
  171. +101 −0 doc/app/files/app/helpers/blogs_helper_rb.html
  172. +101 −0 doc/app/files/app/helpers/comments_helper_rb.html
  173. +101 −0 doc/app/files/app/helpers/home_helper_rb.html
  174. +101 −0 doc/app/files/app/helpers/menus_helper_rb.html
  175. +108 −0 doc/app/files/app/helpers/pages_helper_rb.html
  176. +101 −0 doc/app/files/app/helpers/posts_helper_rb.html
  177. +101 −0 doc/app/files/app/helpers/settings_helper_rb.html
  178. +101 −0 doc/app/files/app/helpers/shares_helper_rb.html
  179. +111 −0 doc/app/files/app/models/comment_observer_rb.html
  180. +101 −0 doc/app/files/app/models/comment_rb.html
  181. +101 −0 doc/app/files/app/models/menu_rb.html
  182. +101 −0 doc/app/files/app/models/page_rb.html
  183. +111 −0 doc/app/files/app/models/post_observer_rb.html
  184. +108 −0 doc/app/files/app/models/post_rb.html
  185. +101 −0 doc/app/files/app/models/setting_rb.html
  186. +101 −0 doc/app/files/app/models/share_rb.html
  187. +101 −0 doc/app/files/app/models/tag_rb.html
  188. +101 −0 doc/app/files/app/models/user_rb.html
  189. +111 −0 doc/app/files/app/sweepers/comment_sweeper_rb.html
  190. +101 −0 doc/app/files/app/sweepers/menu_sweeper_rb.html
  191. +101 −0 doc/app/files/app/sweepers/post_sweeper_rb.html
  192. +101 −0 doc/app/files/app/sweepers/setting_sweeper_rb.html
  193. +110 −0 doc/app/files/doc/README_FOR_APP.html
  194. +133 −0 doc/app/files/lib/guid_rb.html
  195. +109 −0 doc/app/files/lib/string_rb.html
  196. +63 −0 doc/app/fr_class_index.html
  197. +63 −0 doc/app/fr_file_index.html
  198. +114 −0 doc/app/fr_method_index.html
  199. +24 −0 doc/app/index.html
  200. +208 −0 doc/app/rdoc-style.css
  201. +3 −0  install.sh
  202. +491 −0 lib/fanfou_moulde.rb
  203. +281 −0 lib/guid.rb
  204. +13 −0 lib/importer/blog_bus.rb
  205. +58 −0 lib/string.rb
  206. +291 −0 personlab.tmproj
  207. +31 −0 public/404.html
  208. +30 −0 public/422.html
  209. +28 −0 public/500.html
  210. +113 −0 public/canvas.html
  211. +115 −0 public/doc/textile.html
  212. BIN  public/favicon.ico
  213. BIN  public/favicon_green.ico
  214. BIN  public/images/contact.jpg
  215. BIN  public/images/face.jpg
  216. BIN  public/images/feed/icon_subshot01_google.gif
  217. BIN  public/images/feed/icon_subshot01_qq.gif
  218. BIN  public/images/feed/icon_subshot01_xianguo.gif
  219. BIN  public/images/feed/icon_subshot01_youdao.gif
  220. BIN  public/images/feed/icon_subshot01_zhuaxia.gif
  221. BIN  public/images/feed_big.jpg
  222. BIN  public/images/fellow_button.jpg
  223. BIN  public/images/gmail_label.jpg
  224. BIN  public/images/header_bg.jpg
  225. BIN  public/images/header_domain.jpg
  226. BIN  public/images/home_blog_bg.jpg
  227. BIN  public/images/home_sidebar_icon_bg.jpg
  228. BIN  public/images/home_tweet_top.jpg
  229. BIN  public/images/home_tweet_top.jpg.1
  230. BIN  public/images/ie6nomore-chrome.jpg
  231. BIN  public/images/ie6nomore-cornerx.jpg
  232. BIN  public/images/ie6nomore-firefox.jpg
  233. BIN  public/images/ie6nomore-ie8.jpg
  234. BIN  public/images/ie6nomore-safari.jpg
  235. BIN  public/images/ie6nomore-warning.jpg
  236. BIN  public/images/nav_item.jpg
  237. BIN  public/images/nav_search_box.jpg
  238. BIN  public/images/nav_search_button.jpg
  239. BIN  public/images/rails.png
  240. BIN  public/images/slide_show_demo.jpg
  241. BIN  public/images/webicons/delicious.jpg
  242. BIN  public/images/webicons/douban.jpg
  243. BIN  public/images/webicons/fanfou.jpg
  244. BIN  public/images/webicons/flickr.jpg
  245. BIN  public/images/webicons/friendfeed.jpg
  246. BIN  public/images/webicons/lastfm.jpg
  247. BIN  public/images/webicons/picasaweb.jpg
  248. BIN  public/images/webicons/stumbleupon.jpg
  249. BIN  public/images/webicons/twitter.jpg
  250. BIN  public/images/webicons/wakoopa.jpg
  251. BIN  public/images/webicons/xiami.jpg
  252. BIN  public/images/webicons/youtube.jpg
  253. BIN  public/images/webicons/yupoo.jpg
  254. +153 −0 public/javascripts/cpanel/lib/common.js
  255. +10 −0 public/javascripts/cpanel/posts.js
  256. +153 −0 public/javascripts/lib/common.js
  257. +120 −0 public/javascripts/src/common.js
  258. +10 −0 public/javascripts/src/cpanel/posts.js
  259. +32 −0 public/javascripts/src/lib/jquery.js
  260. +149 −0 public/javascripts/src/lib/tiny_mce/.svn/entries
  261. +1 −0  public/javascripts/src/lib/tiny_mce/.svn/format
  262. +1 −0  public/javascripts/src/lib/tiny_mce/.svn/text-base/tiny_mce.js.svn-base
  263. +294 −0 public/javascripts/src/lib/tiny_mce/.svn/text-base/tiny_mce_popup.js.svn-base
  264. +11,138 −0 public/javascripts/src/lib/tiny_mce/.svn/text-base/tiny_mce_src.js.svn-base
  265. +103 −0 public/javascripts/src/lib/tiny_mce/langs/.svn/entries
  266. +1 −0  public/javascripts/src/lib/tiny_mce/langs/.svn/format
  267. +154 −0 public/javascripts/src/lib/tiny_mce/langs/.svn/text-base/en.js.svn-base
  268. +162 −0 public/javascripts/src/lib/tiny_mce/langs/.svn/text-base/zh.js.svn-base
  269. +154 −0 public/javascripts/src/lib/tiny_mce/langs/en.js
  270. +162 −0 public/javascripts/src/lib/tiny_mce/langs/zh.js
  271. +131 −0 public/javascripts/src/lib/tiny_mce/plugins/.svn/entries
  272. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/.svn/format
  273. +146 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/.svn/entries
  274. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advhr/.svn/format
  275. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advhr/.svn/text-base/editor_plugin.js.svn-base
  276. +54 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/.svn/text-base/editor_plugin_src.js.svn-base
  277. +63 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/.svn/text-base/rule.htm.svn-base
  278. +69 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/css/.svn/entries
  279. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advhr/css/.svn/format
  280. +5 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/css/.svn/text-base/advhr.css.svn-base
  281. +5 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/css/advhr.css
  282. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advhr/editor_plugin.js
  283. +54 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/editor_plugin_src.js
  284. +69 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/js/.svn/entries
  285. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advhr/js/.svn/format
  286. +43 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/js/.svn/text-base/rule.js.svn-base
  287. +43 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/js/rule.js
  288. +103 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/langs/.svn/entries
  289. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advhr/langs/.svn/format
  290. +5 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/langs/.svn/text-base/en_dlg.js.svn-base
  291. +5 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/langs/.svn/text-base/zh_dlg.js.svn-base
  292. +5 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/langs/en_dlg.js
  293. +5 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/langs/zh_dlg.js
  294. +63 −0 public/javascripts/src/lib/tiny_mce/plugins/advhr/rule.htm
  295. +149 −0 public/javascripts/src/lib/tiny_mce/plugins/advimage/.svn/entries
  296. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advimage/.svn/format
  297. +1 −0  public/javascripts/src/lib/tiny_mce/plugins/advimage/.svn/text-base/editor_plugin.js.svn-base
  298. +47 −0 public/javascripts/src/lib/tiny_mce/plugins/advimage/.svn/text-base/editor_plugin_src.js.svn-base
  299. +238 −0 public/javascripts/src/lib/tiny_mce/plugins/advimage/.svn/text-base/image.htm.svn-base
  300. +69 −0 public/javascripts/src/lib/tiny_mce/plugins/advimage/css/.svn/entries
Sorry, we could not display the entire diff because too many files (1,373) changed.
17 README
@@ -0,0 +1,17 @@
+h2. 介绍
+
+基于 Ruby on Rails 的个人网站系统(个人实验室),这不仅仅是一个简单的博客。它包括博客,自定义页面,Google Reader 分享引用,迷你博客消息引用等功能,代码插入等功能。
+
+h2. 演示地址
+
+ * "前台":http://personlab.heroku.com/
+ * "后台":http://personlab.heroku.com/cpanel (user:admin password:123123)
+
+h2. 项目特色
+
+* 饭否消息直接导入,并在首页显示功能;
+* 支持 Google Reader 分享展示功能,通过简单的设置你的 Google Reader ID就可以在 “分享” 页面上显示出你分享的文章列表;
+* 作者简介区自定义HTML代码功能,你可以像例子中哪样里面上加入你的照片、你在其它网站的个人页面连接等等;
+* 访客使用 Google Account,Twitter Account,OpenID 直接登录,并发表评论功能;
+* 使用简介的 Textile 做为自定义页面的内容格式;
+* BlogBus 备份文件导入功能,包括评论Tag等信息;
40 Rakefile
@@ -0,0 +1,40 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require(File.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+require 'tasks/rails'
+
+# Twitter
+namespace :tweet do
+ desc "Twitter reload."
+ task :update => :environment do
+ require 'app/models/setting'
+ require 'app/models/tweet'
+ setting = Setting.find_create
+ if !setting.fanfou_id.blank?
+ puts "#{Time.now}"
+ puts 'Load tweets from twitter.com...'
+ items = Tweet.get_home_messages(setting.fanfou_id,5,true)
+ puts "Done. there have #{items.count} tweet."
+ end
+ end
+end
+
+# Google Reader
+namespace :reader_share do
+ desc "Google Reader reload shere items."
+ task :update => :environment do
+ require 'app/models/setting'
+ require 'app/models/share'
+ setting = Setting.find_create
+ puts "#{Time.now}"
+ puts 'Load Google Reader share articles...'
+ items = Share.find_all(setting,true)
+ puts "Done. there got #{items.count} articles from Google Reader."
+ end
+end
+
49 app/controllers/application_controller.rb
@@ -0,0 +1,49 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class ApplicationController < ActionController::Base
+ helper :all # include all helpers, all the time
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
+ session :session_expires => 1.week.from_now
+
+ before_filter :init
+
+ # 初始化
+ def init
+ @menus = Menu.find_all
+
+ @setting = Setting.find_create
+
+ @guest = session[:guest]
+ if @guest.blank?
+ @guest = set_guest
+ end
+ end
+
+ # 输出404错误
+ def render_404
+ render_optional_error_file(404)
+ end
+
+ # 设置主菜单的活动标签
+ def set_nav_actived(name = "home")
+ @nav_actived = name
+ end
+
+ # 设置SEO 的Meta 值
+ def set_seo_meta(title,keywords = '',desc = '')
+ if title
+ @page_title = "#{title} &raquo; #{@setting.site_name}"
+ else
+ @page_title = @setting.site_name
+ end
+ @meta_keywords = keywords
+ @meta_description = desc
+ end
+
+ # 保存评论者信息
+ def set_guest(author = "",url = "",email = "")
+ session[:guest] = {:author => author,:url => url,:email => email}
+ end
+
+end
38 app/controllers/cpanel/application_controller.rb
@@ -0,0 +1,38 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class Cpanel::ApplicationController < ActionController::Base
+ helper :all # include all helpers, all the time
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
+
+ # Scrub sensitive parameters from your log
+ # filter_parameter_logging :password
+ layout "cpanel"
+
+ before_filter :check_login
+
+ def require_login
+ if not @current_user
+ redirect_to :controller => "cpanel/home", :action => "login"
+ return
+ end
+ end
+
+ def save_notice(notice)
+ flash[:notice] = notice
+ end
+
+ def save_login(user)
+ session[:user_id] = user.id
+ @current_user = User.find_by_id(session[:user_id])
+ end
+
+ def clear_login
+ @current_user = nil
+ session[:user_id] = nil
+ end
+
+ def check_login
+ @current_user = User.find_by_id(session[:user_id])
+ end
+end
86 app/controllers/cpanel/categories_controller.rb
@@ -0,0 +1,86 @@
+# ----------------------------------------------------
+# name: menus_controller.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at: 2009-04-16
+# summary:
+# cpanel menu controller
+# ----------------------------------------------------
+
+class Cpanel::CategoriesController < Cpanel::ApplicationController
+ before_filter :require_login
+
+ cache_sweeper :category_sweeper, :only => [:create,:update,:destroy]
+
+ # GET /menus
+ # GET /menus.xml
+ def index
+ @categories = Category.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @menus }
+ end
+ end
+
+ # GET /posts/new
+ # GET /posts/new.xml
+ def new
+ @category = Category.new
+
+ respond_to do |format|
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @menu }
+ end
+ end
+
+ # GET /posts/1/edit
+ def edit
+ @category = Category.find(params[:id])
+ end
+
+ # POST /menus
+ # POST /menus.xml
+ def create
+ @category = Category.new(params[:category])
+
+ respond_to do |format|
+ if @category.save
+ flash[:notice] = '分类创建成功.'
+ format.html { redirect_to(cpanel_categories_url) }
+ format.xml { render :xml => @menu, :status => :created, :location => @menu }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @menu.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /menus/1
+ # PUT /menus/1.xml
+ def update
+ @category = Category.find(params[:id])
+
+ respond_to do |format|
+ if @category.update_attributes(params[:category])
+ flash[:notice] = '分类修改成功.'
+ format.html { redirect_to(cpanel_categories_url) }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @menu.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /menus/1
+ # DELETE /menus/1.xml
+ def destroy
+ @category = Category.find(params[:id])
+ @category.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(cpanel_categories_url) }
+ format.xml { head :ok }
+ end
+ end
+end
44 app/controllers/cpanel/comments_controller.rb
@@ -0,0 +1,44 @@
+# ----------------------------------------------------
+# name: comments_controller.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at: 2009-04-16
+# summary:
+# cpanel comments manage controller
+# ----------------------------------------------------
+
+class Cpanel::CommentsController < Cpanel::ApplicationController
+ cache_sweeper :comment_sweeper,:only => [:destroy]
+
+ # GET /comments
+ # GET /comments.xml
+ def index
+ @comments = Comment.paginate(:page => params[:page],:per_page => 8, :order => 'id desc')
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @comments }
+ end
+ end
+
+ # DELETE /comments/1
+ # DELETE /comments/1.xml
+ def destroy
+ @comment = Comment.find(params[:id])
+ @comment.destroy
+
+ respond_to do |format|
+ format.html {
+ flash[:notice] = "评论删除成功."
+ redirect_to(cpanel_comments_url)
+ }
+ format.xml { head :ok }
+ end
+ end
+
+ def destroy_spams
+ Comment.delete_spams
+ flash[:notice] = "垃圾评论删除成功."
+ redirect_to(cpanel_comments_url)
+ end
+end
+
41 app/controllers/cpanel/home_controller.rb
@@ -0,0 +1,41 @@
+# admin home controller
+class Cpanel::HomeController < Cpanel::ApplicationController
+ before_filter :require_login,:only => [:index,:logout]
+
+ # cpanel
+ def index
+ @total = {}
+ @total[:post_count] = Post.count
+ @total[:page_count] = Page.count
+ @total[:comment_count] = Comment.count
+
+ @recent_posts = Post.find_recent(5)
+ @recent_comments = Comment.find_recent(5)
+ end
+
+ # cpanel/logout
+ def logout
+ clear_login
+ redirect_to :controller => "/home", :action => "index"
+ end
+
+ # cpanel/login
+ def login
+ @user = User.new
+
+ if params[:user]
+ @user = User.check_login(params[:user][:uname], User.encode(params[:user][:pwd]))
+ if @user
+ save_login(@user)
+ redirect_to :controller => "/cpanel"
+ return
+ else
+ @user = User.new
+ flash[:errors] = "用户名或密码不正确。"
+ end
+ end
+
+ render :action => "login", :layout => false
+ end
+
+end
86 app/controllers/cpanel/menus_controller.rb
@@ -0,0 +1,86 @@
+# ----------------------------------------------------
+# name: menus_controller.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at: 2009-04-16
+# summary:
+# cpanel menu controller
+# ----------------------------------------------------
+
+class Cpanel::MenusController < Cpanel::ApplicationController
+ before_filter :require_login
+
+ cache_sweeper :menu_sweeper, :only => [:create,:update,:destroy]
+
+ # GET /menus
+ # GET /menus.xml
+ def index
+ @menus = Menu.all
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @menus }
+ end
+ end
+
+ # GET /posts/new
+ # GET /posts/new.xml
+ def new
+ @menu = Menu.new
+
+ respond_to do |format|
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @menu }
+ end
+ end
+
+ # GET /posts/1/edit
+ def edit
+ @menu = Menu.find(params[:id])
+ end
+
+ # POST /menus
+ # POST /menus.xml
+ def create
+ @menu = Menu.new(params[:menu])
+
+ respond_to do |format|
+ if @menu.save
+ flash[:notice] = '菜单创建成功.'
+ format.html { redirect_to(cpanel_menus_url) }
+ format.xml { render :xml => @menu, :status => :created, :location => @menu }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @menu.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /menus/1
+ # PUT /menus/1.xml
+ def update
+ @menu = Menu.find(params[:id])
+
+ respond_to do |format|
+ if @menu.update_attributes(params[:menu])
+ flash[:notice] = '菜单修改成功.'
+ format.html { redirect_to(cpanel_menus_url) }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @menu.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /menus/1
+ # DELETE /menus/1.xml
+ def destroy
+ @menu = Menu.find(params[:id])
+ @menu.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(cpanel_menus_url) }
+ format.xml { head :ok }
+ end
+ end
+end
91 app/controllers/cpanel/pages_controller.rb
@@ -0,0 +1,91 @@
+# ----------------------------------------------------
+# name: pages_controller.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at:
+# summary:
+# CPanel Pages Controller
+# ----------------------------------------------------
+class Cpanel::PagesController < Cpanel::ApplicationController
+ before_filter :require_login
+
+ cache_sweeper :page_sweeper,:only => [:create,:update,:destory]
+
+ # 页面列表
+ def index
+ @pages = Page.find_list(1)
+ end
+
+ # 创建页面
+ # GET /pages/new
+ # GET /pages/new.xml
+ def new
+ @page = Page.new
+
+ respond_to do |format|
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @page }
+ end
+ end
+
+
+ # 修改页面
+ # GET /pages/1/edit
+ def edit
+ @page = Page.find(params[:id])
+
+ respond_to do |format|
+ format.html # edit.html.erb
+ format.xml { render :xml => @page }
+ end
+ end
+
+ # 提交页面信息
+ # POST /pages
+ # POST /pages.xml
+ def create
+ @page = Page.new(params[:page])
+
+ respond_to do |format|
+ if @page.save
+ save_notice("页面创建成功,可以 <a href=\"#{url_for(:controller => "/home", :action => "show", :slug => @page.slug)}\" target=\"_blank\">点击这里</a> 查看.")
+ format.html { redirect_to :action => "index" }
+ format.xml { render :xml => @page, :status => :created, :location => @page }
+ else
+ format.html { render :action => "index" }
+ format.xml { render :xml => @page.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # 更新页面
+ # PUT /pages/1
+ # PUT /pages/1.xml
+ def update
+ @page = Page.find(params[:id])
+
+ respond_to do |format|
+ if @page.update_attributes(params[:page])
+ save_notice("页面修改成功,可以 <a href=\"#{url_for(:controller => "/home", :action => "show", :slug => @page.slug)}\" target=\"_blank\">点击这里</a> 查看.")
+ format.html { redirect_to :action => "index" }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @page.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # 删除页面
+ # DELETE /pages/1
+ # DELETE /pages/1.xml
+ def destroy
+ @page = Page.find(params[:id])
+ @page.destroy
+
+ respond_to do |format|
+ save_notice("页面已经删除.")
+ format.html { redirect_to :action => "index" }
+ format.xml { head :ok }
+ end
+ end
+end
129 app/controllers/cpanel/posts_controller.rb
@@ -0,0 +1,129 @@
+class Cpanel::PostsController < Cpanel::ApplicationController
+ cache_sweeper :post_sweeper,:only => [:create,:update,:destory]
+ # GET /posts
+ # GET /posts.xml
+ def index
+ @posts = Post.find_list(params[:page])
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.xml { render :xml => @posts }
+ end
+ end
+
+ # GET show import form blogbus
+ # POST do import form blogbus
+ def importblogbus
+ require "lib/importer/blog_bus"
+ if request.post?
+ file_name = params[:file_name]
+ is_clear = params[:clear_old_date]
+ logger.debug { "#{is_clear}" }
+ if is_clear == "on"
+ Post.destroy_all
+ Tag.all.each{ |t| t.destroy }
+ end
+
+ # import posts
+ datas = BlogBus.read_backup(file_name)
+ datas.each do |d|
+ post = Post.new()
+ post.created_at = d.elements['LogDate'].text.to_time
+ post.updated_at = post.created_at
+ post.title = d.elements['Title'].text
+ post.slug = post.created_at.to_s('%y%m%d%H%M%S')
+ post.body = d.elements['Content'].text
+ post.status = d.elements['Status'].text
+ # import tags
+ if d.elements['Tags'].text
+ tags = d.elements['Tags'].text.split(' ')
+ tags.each do |t|
+ tag = Tag.new(:name => t)
+ post.tags << tag
+ end
+ end
+ post.save
+
+ # import comments
+ dcomments = d.elements['Comments']
+ dcomments.each do |c|
+ comment = Comment.new
+ comment.post = post
+ comment.status = 1
+ comment.email = c.elements['Email'].text
+ comment.url = c.elements['HomePage'].text
+ comment.created_at = c.elements['CreateTime'].text.to_time
+ comment.updated_at = comment.created_at
+ comment.author = c.elements['NiceName'].text
+ comment.body = c.elements['CommentText'].text
+ comment.save
+ end
+ end
+ else
+ render :action => "importblogbus"
+ end
+ end
+
+ # GET /posts/new
+ # GET /posts/new.xml
+ def new
+ @post = Post.new
+ respond_to do |format|
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @post }
+ end
+ end
+
+ # GET /posts/1/edit
+ def edit
+ @post = Post.find(params[:id])
+ end
+
+ # POST /posts
+ # POST /posts.xml
+ def create
+ @post = Post.new(params[:post])
+
+ respond_to do |format|
+ if @post.save
+ save_notice("文章创建成功,可以 <a href=\"#{url_for(:controller => "/posts", :action => "show", :slug => @post.slug)}\" target=\"_blank\">点击这里</a> 查看")
+ format.html { redirect_to :controller => "posts", :action => "index" }
+ format.xml { render :xml => @post, :status => :created, :location => @post }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @post.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /posts/1
+ # PUT /posts/1.xml
+ def update
+ @post = Post.find(params[:id])
+
+ respond_to do |format|
+ if @post.update_attributes(params[:post])
+ logger.debug { "post_update" }
+ save_notice("文章修改成功,可以 <a href=\"#{url_for(:controller => "/posts", :action => "show", :slug => @post.slug)}\" target=\"_blank\">点击这里</a> 查看")
+ format.html { redirect_to :controller => "posts", :action => "index" }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @post.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /posts/1
+ # DELETE /posts/1.xml
+ def destroy
+ @post = Post.find(params[:id])
+ @post.destroy
+
+ respond_to do |format|
+ save_notice("文章删除成功.")
+ format.html { redirect_to(cpanel_posts_url) }
+ format.xml { head :ok }
+ end
+ end
+end
32 app/controllers/cpanel/settings_controller.rb
@@ -0,0 +1,32 @@
+class Cpanel::SettingsController < Cpanel::ApplicationController
+ cache_sweeper :setting_sweeper,:page_sweeper, :only => [:update]
+
+ # GET /settings
+ # GET /settings.xml
+ def index
+ @setting = Setting.find_create
+ end
+
+ # PUT /settings/1
+ # PUT /settings/1.xml
+ def update
+ @setting = Setting.find(params[:id])
+
+ if @setting.update_attributes(params[:setting])
+ save_notice("设置修改成功.")
+ redirect_to :controller => "settings"
+ else
+ render :action => "index"
+ end
+ end
+
+ def password
+ if request.method == :put
+ if @current_user.update_pwd(params[:old_pwd], params[:new_pwd], params[:confirm_pwd])
+ save_notice("密码修改成功。")
+ redirect_to :action => "password"
+ end
+ end
+ end
+
+end
39 app/controllers/home_controller.rb
@@ -0,0 +1,39 @@
+class HomeController < ApplicationController
+ caches_page :show
+
+ def index
+ set_seo_meta(nil,@setting.meta_keywords,@setting.meta_description)
+ set_nav_actived("home")
+
+ # get fanfou messages
+ @fanfou_msgs = []
+ if !@setting.fanfou_id.blank?
+ #@fanfou_msgs = Fanfou.get_home_messages(@setting.fanfou_id,5)
+ @tweets = Tweet.get_home_messages(@setting.fanfou_id,5)
+ end
+
+
+ if !fragment_exist? "home/index/recent_posts"
+ @recent_post = Post.find(:first,:order => "created_at desc")
+ end
+ end
+
+ def show
+ @page = Page.find_show(params[:slug])
+
+ if not @page
+ render_404
+ return
+ end
+ set_seo_meta(@page.title)
+ set_nav_actived(@page.slug)
+ render :file => "pages/show", :layout => "application"
+ end
+
+ def share
+ set_nav_actived("share")
+ set_seo_meta("Google Reader 分享")
+ @api_url = Share.api_url(@setting)
+ @shares = Share.find_all(@setting)
+ end
+end
157 app/controllers/posts_controller.rb
@@ -0,0 +1,157 @@
+class PostsController < ApplicationController
+ cache_sweeper :comment_sweeper,:only => [:show]
+ before_filter :init_posts
+
+ private
+ def init_posts
+ set_nav_actived("blog")
+ end
+
+ def init_sidebar
+
+ if !fragment_exist? "posts/sidebar/recent_posts"
+ @recent_posts = Post.find_recent
+ end
+
+ if !fragment_exist? "posts/sidebar/recent_comments"
+ @recent_comments = Comment.find_recent
+ end
+
+ @categories = Rails.cache.read("data/categories")
+ if not @categories
+ @categories = Category.all
+ Rails.cache.write("data/categories",@categories)
+ end
+
+ end
+
+ public
+ def index
+ if params[:search]
+ set_seo_meta("#{params[:search]}的搜索结果")
+ elsif params[:category]
+ @category = Category.find_by_slug(params[:category])
+ if not @category
+ render_404
+ return
+ end
+ if not params[:page]
+ set_seo_meta("博客 &raquo; 分类:#{@category.name}")
+ else
+ set_seo_meta("博客 &raquo; 分类:#{@category.name} &raquo; 第#{params[:page]}")
+ end
+ elsif params[:tag]
+ if not params[:page]
+ set_seo_meta("博客 &raquo; Tag:#{params[:tag]}")
+ else
+ set_seo_meta("博客 &raquo; Tag:#{params[:tag]} &raquo; 第#{params[:page]}")
+ end
+ else
+ if not params[:page]
+ set_seo_meta("博客")
+ else
+ set_seo_meta("博客 &raquo; 第#{params[:page]}")
+ end
+ end
+
+ page = params[:page] ? params[:page] : 1
+ per_page = 5
+ if params[:search]
+ @cache_key = "posts/index/search/#{params[:search]}/#{page}"
+ if !fragment_exist? @cache_key
+ @posts = Post.find_list_with_front(params[:page],per_page,:conditions => ['title like ? or body like ? or meta_keywords like ?',"%#{params[:search]}%","%#{params[:search]}%","%#{params[:search]}%"])
+ end
+ elsif params[:category]
+ @cache_key = "posts/index/category/#{params[:category]}/#{page}"
+ if !fragment_exist? @cache_key
+ @posts = Post.find_list_with_front(params[:page],per_page,:conditions => ['categories.slug = ?',params[:category]])
+ end
+ elsif params[:tag]
+ @cache_key = "posts/index/category/#{params[:tag]}/#{page}"
+ if !fragment_exist? @cache_key
+ @posts = Post.find_list_with_front_by_tag(page,per_page,params[:tag])
+ end
+ else
+ @cache_key = "posts/index/#{page}"
+ if !fragment_exist? @cache_key
+ @posts = Post.find_list_with_front(params[:page],per_page)
+ end
+ end
+
+ init_sidebar
+ end
+
+
+
+ def rss
+ @cache_key = "posts/index/feed"
+ if !fragment_exist? @cache_key
+ # Get the 10 most recent photos
+ @posts = Post.find_list_with_front(1,20)
+ # Title for the RSS feed
+ @feed_title = "10 most recent photos"
+ # Get the absolute URL which produces the feed
+ @feed_url = "http://" + request.host_with_port + request.request_uri
+ # Description of the feed as a whole
+ @feed_description = "20 most recent posts"
+ end
+ # Set the content type to the standard one for RSS
+ response.headers['Content-Type'] = 'application/rss+xml'
+ # Render the feed using an RXML template
+ render :action => 'rss', :layout => false
+
+ end
+
+ def show
+ @post_key = "data/posts/#{params[:slug]}"
+ # update pv
+
+ init_sidebar
+
+ @view_count = Post.update_view_count(params[:slug])
+
+ @post = Rails.cache.read(@post_key)
+ if (not @post) or (@view_count == 0)
+ @post = Post.find_slug(params[:slug])
+ if not @post
+ return render_404
+ end
+
+ Rails.cache.write(@post_key,@post)
+ end
+
+ if request.post?
+ # post comment
+ @pcomment = params[:comment]
+ @comment = Comment.new(params[:comment])
+ @comment.request = request
+ @comment.post_id = @post.id
+
+ set_guest(@comment.author,@comment.url,@comment.email)
+
+ if @comment.save
+ if @comment.status == 2
+ flash[:notice] = "评论发表成功。<br />但由于经过 Akismet 自动判定,您的评论内容需要由管理人员审核过后方可显示。"
+ else
+ flash[:notice] = "评论发表成功."
+ end
+ redirect_to :action => "show", :slug => @post.slug, :anchor => "comment"
+ end
+ else
+ @comment = Comment.new
+ @comment.author = @guest[:author]
+ @comment.url = @guest[:url]
+ @comment.email = @guest[:email]
+ end
+
+ set_seo_meta(@post.title,@post.meta_keywords,@post.meta_description)
+
+ # get comments list
+ if !fragment_exist? "posts/show/#{params[:slug]}/comments"
+ @comments = @post.comments.find_list
+ end
+
+ end
+
+end
+
67 app/helpers/application_helper.rb
@@ -0,0 +1,67 @@
+require "md5"
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+
+ # return the formatted flash[:notice] html
+ def success_messages
+ if flash[:notice]
+ '
+ <div id="successMessage" class="successMessage">
+ '+flash[:notice]+'
+ </div>
+ '
+ else
+ ''
+ end
+ end
+
+ # form auth token
+ def auth_token
+ "<input name=\"authenticity_token\" type=\"hidden\" value=\"#{form_authenticity_token}\" />"
+ end
+
+ # return the Gravatar face by Email
+ def face_url(email)
+ hash = MD5::md5(email)
+ "http://www.gravatar.com/avatar/#{hash}?s=32"
+ end
+
+ # close html tag when truncated
+ def close_tags(text)
+ open_tags = []
+ text.scan(/\<([^\>\s\/]+)[^\>\/]*?\>/).each { |t| open_tags.unshift(t) }
+ text.scan(/\<\/([^\>\s\/]+)[^\>]*?\>/).each { |t| open_tags.slice!(open_tags.index(t)) }
+ open_tags.each {|t| text += "</#{t}>" }
+ return text
+ end
+
+ def truncate_html(html, options={})
+ # Does not behave identical to current Rails truncate method i.e. you must pass options as a hash not just values
+ # Sample usage: <%= html_truncate(category.description, :length => 120, :omission => "(continued...)" ) -%>...
+ previous_tag = ""
+ text, result = [], []
+
+ # get all text (including punctuation) and tags and stick them in a hash
+ html.scan(/<\/?[^>]*>|[A-Za-z.,;!"'?]+/).each { |t| text << t }
+
+ text.each do |str|
+ if options[:length] > 0
+ if str =~ /<\/?[^>]*>/
+ previous_tag = str
+ result << str
+ else
+ result << str
+ options[:length] -= str.length
+ end
+ else
+ # now stick the next tag with a </> that matches the previous open tag on the end of the result
+ if str =~ /<\/([#{previous_tag}]*)>/
+ result << str
+ else
+ end
+ end
+ end
+ return result.join(" ") + options[:omission].to_s
+ end
+
+end
62 app/helpers/application_helper.rb.save
@@ -0,0 +1,62 @@
+require "md5"
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+
+ # return the formatted flash[:notice] html
+ def success_messages
+ if flash[:notice]
+ '
+ <div id="successMessage" class="successMessage">
+ '+flash[:notice]+'
+ </div>
+ '
+ else
+ ''
+ end
+ end
+
+ # form auth token
+ def auth_token
+ "<input name=\"authenticity_token\" type=\"hidden\" value=\"#{form_authenticity_token}\" />"
+ end
+
+ # return the Gravatar face by Email
+ def face_url(email)
+ hash = MD5::md5(email)
+ "http://www.gravatar.com/avatar/#{hash}?s=32"
+ end
+
+ # close html tag when truncated
+ def close_tags(text)
+ open_tags = []
+ text.scan(/\<([^\>\s\/]+)[^\>\/]*?\>/).each { |t| open_tags.unshift(t) }
+ text.scan(/\<\/([^\>\s\/]+)[^\>]*?\>/).each { |t| open_tags.slice!(open_tags.index(t)) }
+ open_tags.each {|t| text += "</#{t}>" }
+ return text
+ end
+
+def truncate_html(html, size=50 )
+ # 2nd Textile HTML truncate by Joe Melberg
+ # assumes textile output.
+ # Sample usage: <%= html_truncate(category.description, 120 ) -%>...
+ tags = []
+ text = []
+ result = []
+ # get all opening and closing tags by themselves
+ html.scan(/<[^\>]*?\>/).each { |t| tags << t }
+ # get all non-tag text.
+ html.scan(/>([^\>]+)[^\>]*?\&lt;/).each { |t| text << t }
+ text &lt;&lt; #prevent nill error when threading arrays together.
+ # Thread arrays into new array (I'm sure there's a slicker way)
+ tags.each_index { |i|
+ result << tags[i]
+ if size > 0
+ t = text[i].to_s.chars[0,size]
+ size -= t.chars.length
+ result << t
+ end
+ }
+ result = result.join("")
+end
+
+end
2  app/helpers/comments_helper.rb
@@ -0,0 +1,2 @@
+module CommentsHelper
+end
2  app/helpers/home_helper.rb
@@ -0,0 +1,2 @@
+module HomeHelper
+end
2  app/helpers/menus_helper.rb
@@ -0,0 +1,2 @@
+module MenusHelper
+end
6 app/helpers/pages_helper.rb
@@ -0,0 +1,6 @@
+require "RedCloth"
+module PagesHelper
+ def textile(body)
+ RedCloth.new(body).to_html
+ end
+end
2  app/helpers/posts_helper.rb
@@ -0,0 +1,2 @@
+module PostsHelper
+end
2  app/helpers/settings_helper.rb
@@ -0,0 +1,2 @@
+module SettingsHelper
+end
11 app/models/category.rb
@@ -0,0 +1,11 @@
+class Category < ActiveRecord::Base
+ validates_presence_of :name
+
+ has_many :posts
+
+ before_update :before_update
+
+ def before_update
+ self.posts_count = self.posts.count
+ end
+end
59 app/models/comment.rb
@@ -0,0 +1,59 @@
+class Comment < ActiveRecord::Base
+ belongs_to :post
+
+ validates_presence_of :author,:email,:body, :message => "还未填写."
+ default_scope :order => 'id ASC'
+ has_rakismet :author => :author,
+ :author_url => :url,
+ :author_email => :email,
+ :content => :body,
+ :user_ip => :user_ip,
+ :user_agent => :user_agent,
+ :referrer => :referrer
+
+ before_create :before_create
+
+ def created_at_s
+ created_at.to_s(:short_time_string)
+ end
+
+ def self.find_list(page = 1, per_page = 20,options = {})
+ with_scope :find => options do
+ paginate(:page => page, :per_page => per_page, :conditions => ['status = ?', 1])
+ end
+ end
+
+ def self.find_recent(size = 10, options = {})
+ with_scope :find => options do
+ paginate :page => 1, :per_page => size, :conditions => ['status = ?', 1], :order => "id desc"
+ end
+ end
+
+ # 删除所有 spams
+ def self.delete_spams
+ destroy_all(:status => 2)
+ end
+
+ def before_create
+ if self.spam?
+ self.status = 2
+ else
+ self.status = 1
+ end
+ end
+
+ def request=(request)
+ self.user_ip = request.remote_ip
+ self.user_agent = request.env['HTTP_USER_AGENT']
+ self.referrer = request.env['HTTP_REFERER']
+ end
+
+ def mark_as_spam!
+ update_attribute(:status, 2)
+ end
+
+ def mark_as_ham!
+ update_attribute(:status, 1)
+ end
+end
+
30 app/models/comment_observer.rb
@@ -0,0 +1,30 @@
+# ----------------------------------------------------
+# name: comment_observer.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at: 2009-04-20
+# summary:
+# this comment_observer.rb summary
+# ----------------------------------------------------
+require "sweepers/comment_sweeper"
+class CommentObserver < ActiveRecord::Observer
+
+ def after_create(m)
+ total_comment_count(m)
+ end
+
+ def after_destroy(m)
+ total_comment_count(m)
+ end
+
+ private
+ # tatal the comments count of this post and save it.
+ def total_comment_count(m)
+ post = m.post
+ if post
+ count = post.comments.length
+ post.comment_count = count
+ post.save
+ end
+ CommentSweeper.instance.after_create(m)
+ end
+end
15 app/models/fanfou.rb
@@ -0,0 +1,15 @@
+# Fanfou API data model
+# virtual model not have database table
+class Fanfou < ActiveRecord::Base
+
+ def self.get_home_messages(id,len = 4)
+ @expire_minutes = 15.minutes
+ @fanfou_msgs = Rails.cache.read("data/fanfou/me")
+ if not @fanfou_msgs
+ @fanfou_msgs = FanfouMoulde.get_messages_by_id(id,len)
+ Rails.cache.write("data/fanfou/me",@fanfou_msgs,:expires_in => @expire_minutes)
+ end
+
+ @fanfou_msgs
+ end
+end
12 app/models/menu.rb
@@ -0,0 +1,12 @@
+class Menu < ActiveRecord::Base
+ validates_presence_of :name,:url, :message => "不能为空"
+ validates_uniqueness_of :name,:case_sensitive => false, :message => "已经有同名的存在."
+
+
+ def self.find_all
+ Rails.cache.fetch("data/menus") {
+ find(:all,:order => "sort desc")
+ }
+ end
+
+end
36 app/models/page.rb
@@ -0,0 +1,36 @@
+class Page < ActiveRecord::Base
+ validates_uniqueness_of :title, :slug, :case_sensitive => false , :message => "已经有同名的存在,请检查是否重发了."
+ before_save :before_save
+ before_validation :before_validation
+
+ # status
+ STATUS = [
+ ["请选择状态",-1],
+ ["发布",1],
+ ["草稿",2],
+ ].freeze
+
+ private
+ # callback events
+ def before_save
+ end
+
+ # before validation
+ def before_validation
+ self.slug = self.slug.safe_slug
+ end
+
+ # custom methods
+ public
+ # find list
+ def self.find_list(page = 1, per_page = 20,options = {})
+ with_scope :find => options do
+ paginate :page => page,:per_page => per_page, :order => 'created_at desc'
+ end
+ end
+
+ def self.find_show(slug)
+ find_by_slug_and_status(slug,1)
+ end
+
+end
127 app/models/post.rb
@@ -0,0 +1,127 @@
+require "lib/string"
+
+class Post < ActiveRecord::Base
+ validates_uniqueness_of :title, :slug, :case_sensitive => false , :message => "已经有同名的存在,请检查是否重发了."
+ validates_presence_of :title,:body,:status
+ has_many :comments
+ belongs_to :category, :counter_cache => true
+ acts_as_taggable_on :tags
+ default_scope :order => 'id desc'
+
+ # callback events
+ before_validation :before_validation
+ before_save :before_save
+
+ # enum sets
+
+ # status
+ STATUS = [
+ ["请选择状态",-1],
+ ["发布",1],
+ ["草稿",2],
+ ].freeze
+
+ # custome field
+
+ # string formated created_at
+ def created_at_s
+ created_at.to_s(:short_date_string)
+ end
+
+ # body summary
+ def summary
+ @sumarry_mark = "<!--{/summary}-->"
+ if body.index(@sumarry_mark)
+ body.split(@sumarry_mark)[0]
+ else
+ body.truncate_html(1500,'')
+ end
+ end
+
+ # cache delayed view_count
+ def delay_view_count
+ cache_key = "data/posts/view_count/#{slug}"
+ Rails.cache.read(cache_key).to_i || 0
+ end
+
+ # callback events
+ private
+ # before save
+ def before_save
+ if self.comment_count < 0
+ self.comment_count = 0
+ end
+ end
+
+ # before validation
+ def before_validation
+ self.slug = self.slug.safe_slug
+ end
+
+
+ # custom method
+ public
+ # list
+ def self.find_list(page = 1, per_page = 20,options = {})
+ with_scope :find => options do
+ paginate(:page => page,:per_page => per_page,:joins => [:category],:include => [:tags])
+ end
+ end
+
+ def self.find_list_with_front(page = 1, per_page = 5, options = {})
+ with_scope :find => options do
+ find_list(page, per_page,:conditions => ["status = 1"])
+ end
+ end
+
+ def self.find_list_with_front_by_tag(page = 1, per_page = 5,tag = '', options = {})
+ tagged_with(tag,:on => :tags).paginate(:page => page,:per_page => per_page,:joins => [:category],:include => [:tags],:conditions => ["status =1"])
+ end
+
+ # find posts order by comment_count
+ def self.find_hot(size = 10, options = {})
+ with_scope :find => options do
+ paginate(:page => 1,:per_page => size, :conditions => ["status = 1"] , :order => 'comment_count desc')
+ end
+ end
+
+ # find recent posts
+ def self.find_recent(size = 10, options = {})
+ with_scope :find => options do
+ paginate(:page => 1,:per_page => size, :conditions => ["status = 1"])
+ end
+ end
+
+ # show
+ def self.find_slug(slug)
+ find_by_slug_and_status(slug,1,:include => [:tags,:category])
+ end
+
+
+ # static method
+ def self.update_view_count(slug)
+ delay = 30
+ cache_key = "data/posts/view_count/#{slug}"
+ count = Rails.cache.read(cache_key).to_i || 0
+ if count % delay == 0 && count != 0
+ post = find_by_slug(slug)
+ if post
+ post.view_count += count + 1
+ post.save
+ end
+ count = 0
+ else
+ count += 1
+ end
+ Rails.cache.write(cache_key,count)
+ count
+ end
+
+
+
+ def self.destroy_all
+ all.each do |p|
+ p.destroy
+ end
+ end
+end
20 app/models/post_observer.rb
@@ -0,0 +1,20 @@
+# ----------------------------------------------------
+# name: post_observer.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at: 2009-04-20
+# summary:
+# this post_observer.rb summary
+# ----------------------------------------------------
+class PostObserver < ActiveRecord::Observer
+
+ def after_update(post)
+
+ end
+
+ def after_destroy(post)
+ # destroy post.comments
+ post.comments.each { |c| c.destroy() }
+ # destroy posts_tags relete info
+ post.tags.destroy
+ end
+end
61 app/models/setting.rb
@@ -0,0 +1,61 @@
+class Setting < ActiveRecord::Base
+
+ def self.find_create
+ Rails.cache.fetch("data/setting") {
+ @setting = first
+ if not @setting
+ @setting = new(:site_name => "PersonLab Demo", :sub_title => "This is an person website build by Ruby on Rails.",
+ :meta_keywords => "personlab,ruby on rails",
+ :email => "huacnlee@gmail.com",
+ :meta_description => "This is an person website build by Ruby on Rails.",
+ :fanfou_id => "huacn",
+ :google_reader_id => "08982619185204047523",
+ :home_show => '
+ <div class="info">
+ <div class="face">
+ <img alt="李华顺的照片" src="/images/face.jpg">
+ </div>
+ <div class="feed">
+ <a id="get_feed" href="#" title="订阅我的博客">
+ <img alt="订阅我的博客" src="/images/feed_big.jpg">
+ </a><br>
+ <img alt="Email:huacnlee@gmail.com" src="/images/gmail_label.jpg">
+ </div>
+ </div>
+ <div class="icons">
+ <a href="http://fanfou.com/huacn" target="_blank" title="关注我的饭否"><img alt="我的饭否" src="/images/webicons/fanfou.jpg"></a>
+ <a href="http://twitter.com/huacnlee" target="_blank" title="我的Twitter"><img alt="我的Twitter" src="/images/webicons/twitter.jpg"></a> <a href="http://www.xiami.com/u/8008" title="我的虾米音乐分享" target="_blank"><img alt="我的虾米音乐分享" src="/images/webicons/xiami.jpg"></a>
+ <a href="http://del.icio.us/huacnlee" target="_blank" title="我的Delicious收藏夹"><img alt="我的Delicious收藏夹" src="/images/webicons/delicious.jpg"></a>
+ <a href="http://www.douban.com/people/huacnlee/" target="_blank" title="我的豆瓣"><img alt="我的豆瓣" src="/images/webicons/douban.jpg"></a>
+ <a href="http://huacnlee.stumbleupon.com/" style="display: none;" title="我的
+ StumbleUpon"><img alt="simple" src="/images/webicons/stumbleupon.jpg"></a>
+ <a href="http://friendfeed.com/huacn" target="_blank" title="我的FriendFeed"><img alt="我的FriendFeed分享" src="/images/webicons/friendfeed.jpg"></a>
+ <a href="http://huacn.yupoo.com/" target="_blank" title="我的Yupoo相册"><img alt="我的Yupoo相册" src="/images/webicons/yupoo.jpg"></a>
+ <a href="http://flickr.com/photos/huacnlee" traget="_blank"><img alt="我的Flickr相册" src="/images/webicons/flickr.jpg"></a>
+ <a href="http://picasaweb.google.com/huacnlee" title="我的Picasa相册"><img alt="我的Picasa相册" src="/images/webicons/picasaweb.jpg"></a>
+ <a href="http://www.youtube.com/huacnlee" target="_blank" title="我的Youtube收藏"><img alt="我的Youtube收藏" src="/images/webicons/youtube.jpg"></a>
+ <a href="http://cn.last.fm/user/huacnlee/" target="_blank" title="我的Last.fm"><img alt="我的Last.fm" src="/images/webicons/lastfm.jpg"></a>
+ <a href="http://wakoopa.com/huacnlee" title="我最常用的软件及评价(Wakoopa)"><img alt="我最常用的软件及评价(Wakoopa)" src="/images/webicons/wakoopa.jpg"></a>
+ </div>',
+ :blog_feed_html => '<div id="big_feed">
+ <a id="get_feed" href="#" title="订阅我的博客"><img alt="订阅我的博客" src="/images/feed_big.jpg"></a>
+ </div>
+ <div id="other_feed">
+ <!-- Feedsky FEED发布代码开始 -->
+ <!-- FEED自动发现标记开始 -->
+ <link title="RSS 2.0" type="application/rss+xml" href="http://feed.feedsky.com/huacn" rel="alternate" />
+ <!-- FEED自动发现标记结束 -->
+ <a href="http://www.zhuaxia.com/add_channel.php?url=http://feed.feedsky.com/huacn"><img border="0" src="http://img.feedsky.com/images/icon_subshot01_zhuaxia.gif" alt="&#25235;&#34430;" vspace="2" style="margin-bottom:3px" ></a><br />
+ <a href="http://fusion.google.com/add?feedurl=http://feed.feedsky.com/huacn"><img border="0" src="http://img.feedsky.com/images/icon_subshot01_google.gif" alt="google reader" vspace="2" style="margin-bottom:3px" ></a><br />
+ <a href="http://www.xianguo.com/subscribe.php?url=http://feed.feedsky.com/huacn"><img border="0" src="http://img.feedsky.com/images/icon_subshot01_xianguo.gif" alt="&#40092;&#26524;" vspace="2" style="margin-bottom:3px" ></a><br />
+ <a href="http://reader.youdao.com/b.do?keyfrom=feedsky&url=http://feed.feedsky.com/huacn"><img border="0" src="http://img.feedsky.com/images/icon_subshot01_youdao.gif" alt="&#26377;&#36947;" vspace="2" style="margin-bottom:3px" ></a><br />
+ <a href="http://mail.qq.com/cgi-bin/feed?u=http://feed.feedsky.com/huacn"><img border="0" src="http://img.feedsky.com/images/icon_subshot01_qq.gif" alt="QQ&#37038;&#31665;" vspace="2" style="margin-bottom:3px" ></a><br />
+ <!-- Feedsky FEED发布代码结束 -->
+ </div>
+ ')
+ @setting.save
+ end
+ @setting
+ }
+ end
+end
33 app/models/share.rb
@@ -0,0 +1,33 @@
+require "rubygems"
+require 'simple-rss'
+require 'open-uri'
+require "lib/string"
+
+class Share < ActiveRecord::Base
+
+ def self.api_url(setting)
+ "http://www.google.com/reader/public/atom/user%2F#{setting.google_reader_id}%2Fstate%2Fcom.google%2Fbroadcast"
+ end
+
+ def self.find_all(setting,force = false)
+ cache_key = "data/shares"
+ feeds = Rails.cache.read(cache_key)
+ if not feeds or force
+ feeds = []
+ feed = SimpleRSS::parse open(api_url(setting))
+ if feed != nil
+ feed.items.each do |item|
+ feeds << {
+ "title" => item.title,
+ "link" => item.link,
+ "content" => item.content == nil ? item.summary.html_decode.remove_html_tag : item.content.html_decode.remove_html_tag,
+ "updated_at" => item.updated,
+ "author" => item.author,
+ }
+ end
+ end
+ Rails.cache.write(cache_key,feeds)
+ end
+ feeds
+ end
+end
25 app/models/tag.rb
@@ -0,0 +1,25 @@
+class Tag < ActiveRecord::Base
+ has_and_belongs_to_many :posts
+
+ def posts_count
+ posts.count
+ end
+
+ # override save for name unique
+ def save
+ old = self.class::find_by_name(self.name)
+ if old
+ logger.debug { "existed!" }
+ self.id = old.id
+ self.created_at = old.created_at
+ self.updated_at = old.updated_at
+ return true
+ else
+ super
+ end
+ end
+
+ def self.find_top(size = 10)
+ paginate :per_page => size, :page => 1
+ end
+end
17 app/models/tweet.rb
@@ -0,0 +1,17 @@
+# Twitter API data model
+require "twitter"
+# virtual model not have database table
+class Tweet < ActiveRecord::Base
+
+ def self.get_home_messages(uid = 'huacnlee',count = 5,force = false)
+ msgs = Rails.cache.read("data/tweet/#{uid}")
+ if not msgs or force
+ config_file = "#{RAILS_ROOT}/config/twitter.yml"
+ twitter = Twitter::Client.from_config(config_file,RAILS_ENV)
+ msgs = twitter.timeline_for(:user, :id => uid,:count => count)
+ Rails.cache.write("data/tweet/#{uid}",msgs)
+ end
+
+ msgs
+ end
+end
39 app/models/user.rb
@@ -0,0 +1,39 @@
+class User < ActiveRecord::Base
+ validates_presence_of :uname, :pwd, :name,:message => "不能为空."
+
+ def self.encode(pwd)
+ Digest::MD5.hexdigest("--@*&^!*987-!^!*--#{pwd}")
+ end
+
+ def self.check_login(uname,pwd)
+ find(:first, :conditions => ['uname = ? and pwd = ?', uname, pwd])
+ end
+
+ # 更新密码
+ def update_pwd(old_pwd,new_pwd,confirm_pwd)
+ if old_pwd.blank?
+ self.errors.add("旧密码","还未填写。")
+ return false
+ end
+
+ if new_pwd.blank?
+ self.errors.add("新密码","还未填写。")
+ return false
+ end
+
+ if User.encode(old_pwd) != self.pwd
+ self.errors.add("旧密码","不正确。")
+ return false
+ end
+
+ if new_pwd != confirm_pwd
+ self.errors.add("新密码与确认密码","不一至。")
+ return false
+ end
+
+ self.pwd = User.encode(new_pwd)
+ if self.save
+ return true
+ end
+ end
+end
19 app/sweepers/category_sweeper.rb
@@ -0,0 +1,19 @@
+class CategorySweeper < ActionController::Caching::Sweeper
+ observe Category
+
+ def after_save(category)
+ clear_category_cache(category)
+ end
+
+ def after_destroy(category)
+ clear_category_cache(category)
+ end
+
+ def clear_category_cache(category)
+ Rails.cache.delete("data/categories")
+ expire_fragment %r"posts/index/*"
+ for p in category.posts do
+ Rails.cache.write("data/posts/#{p.slug}",nil)
+ end
+ end
+end
37 app/sweepers/comment_sweeper.rb
@@ -0,0 +1,37 @@
+# ----------------------------------------------------
+# name: comment_speeper.rb
+# authors: Jason Lee<huacnlee@gmail.com>,
+# create at: 2009-04-20
+# summary:
+# this comment_speeper.rb summary
+# ----------------------------------------------------
+class CommentSweeper < ActionController::Caching::Sweeper
+ observe Comment
+
+ def after_create(comment)
+ sweeper(comment)
+ end
+
+ def after_destroy(comment)
+ sweeper(comment)
+ end
+
+ def sweeper(comment)
+ expire_fragment %r"posts/index/*"
+ clear_posts_sidebar(comment)
+ clear_post_comments(comment)
+ end
+
+ # 清除评论列表
+ def clear_post_comments(comment)
+ if comment.post
+ expire_fragment "posts/show/#{comment.post.slug}/comments"
+ end
+ end
+
+ # 清除 posts controller 的 sidebar 缓存
+ def clear_posts_sidebar(comment)
+ expire_fragment 'posts/sidebar/recent_comments'
+ expire_fragment 'posts/sidebar/hot_posts'
+ end
+end
15 app/sweepers/menu_sweeper.rb
@@ -0,0 +1,15 @@
+class MenuSweeper < ActionController::Caching::Sweeper
+ observe Menu
+
+ def after_save(menu)
+ clear_menu_cache(menu)
+ end
+
+ def after_destroy(menu)
+ clear_menu_cache(menu)
+ end
+
+ def clear_menu_cache(menu)
+ Rails.cache.delete("data/menus")
+ end
+end
19 app/sweepers/page_sweeper.rb
@@ -0,0 +1,19 @@
+class PageSweeper < ActionController::Caching::Sweeper
+ observe Page
+
+ def after_save(page)
+ clear_page_cache(page)
+ end
+
+ def after_destroy(page)
+ clear_page_cache(page)
+ end
+
+ def clear_page_cache(page)
+ expire_page :controller => "/home", :action => "show", :slug => page.slug
+ end
+
+ def clear_all()
+ expire_page :controller => "/home", :action => "show"
+ end
+end
35 app/sweepers/post_sweeper.rb
@@ -0,0 +1,35 @@
+class PostSweeper < ActionController::Caching::Sweeper
+ observe Post
+
+ def after_update(post)
+ sweeper(post)
+ end
+
+ def after_create(post)
+ clear_index_recent_posts
+ end
+
+ def after_destroy(post)
+ sweeper(post)
+ end
+
+ def sweeper(post)
+ clear_index_recent_posts
+ expire_fragment %r"posts/index/*"
+ Rails.cache.write("data/posts/#{post.slug}",nil)
+ clear_post_comments(post)
+ Rails.cache.delete("data/categories")
+ end
+
+ # 清除评论列表
+ def clear_post_comments(post)
+ expire_fragment "posts/show/#{post.slug}/comments"
+ end
+
+ # 清除首页缓存
+ def clear_index_recent_posts
+ expire_fragment "home/index/recent_posts"
+ expire_fragment 'posts/sidebar/recent_posts'
+ end
+
+end
12 app/sweepers/setting_sweeper.rb
@@ -0,0 +1,12 @@
+class SettingSweeper < ActionController::Caching::Sweeper
+ observe Setting
+
+ def after_save(setting)
+ clear_setting_cache(setting)
+ end
+
+ def clear_setting_cache(setting)
+ Rails.cache.delete("data/setting")
+ Rails.cache.delete("data/fanfou/me")
+ end
+end
16 app/views/cpanel/categories/_submenu.html.erb
@@ -0,0 +1,16 @@
+<% content_for :submenu do %>
+ <li><%= link_to "文章管理", :controller => "posts", :action => "index" %></li>
+ <% if params[:action] == 'index' %>
+ <li class="current"><span>分类管理</span></li>
+ <% else %>
+ <li><%= link_to "分类管理", :controller => "categories", :action => "index" %></li>
+ <% end %>
+ <% if params[:action] == 'new' %>
+ <li class="current"><span>创建</span></li>
+ <% else %>
+ <li><%= link_to "创建", :controller => "categories", :action => "new" %></li>
+ <% end %>
+ <% if params[:action] == 'edit' %>
+ <li class="current"><span>编辑</span></li>
+ <% end %>
+<% end %>
23 app/views/cpanel/categories/edit.html.erb
@@ -0,0 +1,23 @@
+<% content_for :styles do %>
+<%= stylesheet_link_tag "src/cpanel/categories", :cache => "cpanel/categories" %>
+<% end %>
+<%= render :partial => 'submenu' %>
+<div class="form">
+ <% form_for(@category,:url => (@category.id ? cpanel_category_url(@category) : cpanel_categories_url)) do |f| %>
+ <%= f.error_messages %>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr class="row">
+ <td class="field">名称</td>
+ <td><%= f.text_field :name, :class => "text" %></td>
+ </tr>
+ <tr class="row">
+ <td class="field">Slug</td>
+ <td><%= f.text_field :slug, :class => "text" %></td>
+ </tr>
+ <tr class="buttons row">
+ <td class="field"></td>
+ <td><%= f.submit (@category.id ? "保存" : "创建")%><%= link_to '返回', :action => "index" %></td>
+ </tr>
+ </table>
+ <% end %>
+</div>
33 app/views/cpanel/categories/index.html.erb
@@ -0,0 +1,33 @@
+<% content_for :styles do %>
+<%= stylesheet_link_tag "src/cpanel/categories" %>
+<% end %>
+<%= render :partial => 'submenu' %>
+<%= success_messages %>
+<div id="categories" class="form">
+<% if !@categories.blank? %>
+ <table class="grid" border="0" cellspacing="0" cellpadding="0">
+ <tr class="head">
+ <td class="name first">名称</td>
+ <td class="slug">Slug</td>
+ <td class="posts_count">文章数</td>
+ <td class="opt"></td>
+ </tr>
+ <% for item in @categories %>
+ <tr class="row">
+ <td class="name first"><%= item.name %></td>
+ <td class="slug"><%= item.slug %></td>
+ <td class="posts_count"><%= item.posts_count %></td>
+ <td class="opt">
+ <%= link_to "修改", edit_cpanel_category_url(item) %>
+ <%= link_to '删除', cpanel_category_url(item), :confirm => '确定要删除吗?', :method => :delete %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+<% else %>
+ <div class="none_result">
+ There have no categories,please create.
+ </div>
+<% end %>
+</div>
+
37 app/views/cpanel/comments/index.html.erb
@@ -0,0 +1,37 @@
+<% content_for :styles do %>
+<%= stylesheet_link_tag "src/cpanel/comments", :cache => "cpanel/comments" %>
+<% end %>
+<% content_for :submenu do %>
+<%= link_to '清除所有垃圾评论',{:controller => "/cpanel/comments",:action => "destroy_spams" }, :confirm => '确定要清除所有垃圾评论吗?', :method => :post %>
+<% end %>
+<%= success_messages %>
+<div id="comments">
+ <% @comments.each do |comment| %>
+ <div class="row">
+ <div class="info">
+ #<%= comment.id %> <span class="author"><a href="<%=h comment.url %>"><%=h comment.author %></a></span>
+ | <span class="email"><%=h comment.email %></span> | <span class="user_ip"><%= comment.user_ip %></span>
+ | <span class="user_agent" title="<%=h comment.user_agent %>"><%=h truncate(comment.user_agent,25) %></span>
+ | <span class="spam"><% if comment.status == 2%>[垃圾]<% end %></span>
+ </div>
+ <div class="body">
+ <div class="face">
+ <%= image_tag(face_url(comment.email), :alt => comment.author) %>
+ </div>
+ <%= h(comment.body) %>
+ </div>
+ <div