EliteJournal 1.9.400

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. data/AUTHORS +1 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +22 -0
  4. data/app/controllers/account_controller.rb +25 -0
  5. data/app/controllers/application.rb +83 -0
  6. data/app/controllers/atom_controller.rb +26 -0
  7. data/app/controllers/auth_controller.rb +23 -0
  8. data/app/controllers/backend_controller.rb +14 -0
  9. data/app/controllers/css_controller.rb +31 -0
  10. data/app/controllers/draft_controller.rb +62 -0
  11. data/app/controllers/image_controller.rb +11 -0
  12. data/app/controllers/journal_controller.rb +53 -0
  13. data/app/controllers/link_controller.rb +29 -0
  14. data/app/controllers/ping_controller.rb +44 -0
  15. data/app/controllers/post_controller.rb +131 -0
  16. data/app/controllers/rss_controller.rb +22 -0
  17. data/app/controllers/tags_controller.rb +74 -0
  18. data/app/controllers/user_controller.rb +30 -0
  19. data/app/controllers/users_controller.rb +13 -0
  20. data/app/helpers/account_helper.rb +2 -0
  21. data/app/helpers/application_helper.rb +117 -0
  22. data/app/helpers/atom_helper.rb +2 -0
  23. data/app/helpers/auth_helper.rb +2 -0
  24. data/app/helpers/backend_helper.rb +2 -0
  25. data/app/helpers/css_helper.rb +2 -0
  26. data/app/helpers/draft_helper.rb +2 -0
  27. data/app/helpers/image_helper.rb +2 -0
  28. data/app/helpers/journal_helper.rb +2 -0
  29. data/app/helpers/link_helper.rb +2 -0
  30. data/app/helpers/ping_helper.rb +5 -0
  31. data/app/helpers/post_helper.rb +2 -0
  32. data/app/helpers/rss_helper.rb +5 -0
  33. data/app/helpers/tags_helper.rb +7 -0
  34. data/app/helpers/user_helper.rb +2 -0
  35. data/app/helpers/users_helper.rb +2 -0
  36. data/app/models/blogger_api.rb +24 -0
  37. data/app/models/comment.rb +18 -0
  38. data/app/models/draft.rb +12 -0
  39. data/app/models/face.rb +24 -0
  40. data/app/models/feed_killer.rb +17 -0
  41. data/app/models/image.rb +7 -0
  42. data/app/models/link.rb +10 -0
  43. data/app/models/meta_weblog_api.rb +82 -0
  44. data/app/models/ping.rb +16 -0
  45. data/app/models/post.rb +30 -0
  46. data/app/models/stylesheet.rb +7 -0
  47. data/app/models/tag.rb +16 -0
  48. data/app/models/user.rb +35 -0
  49. data/app/views/account/info.rhtml +30 -0
  50. data/app/views/atom/feed.rxml +15 -0
  51. data/app/views/auth/login.rhtml +9 -0
  52. data/app/views/css/edit.rhtml +18 -0
  53. data/app/views/css/list.rhtml +24 -0
  54. data/app/views/css/new.rhtml +6 -0
  55. data/app/views/draft/edit.rhtml +9 -0
  56. data/app/views/draft/list.rhtml +22 -0
  57. data/app/views/draft/new.rhtml +9 -0
  58. data/app/views/journal/_comment.rhtml +10 -0
  59. data/app/views/journal/_post.rhtml +40 -0
  60. data/app/views/journal/_trackback.rhtml +4 -0
  61. data/app/views/journal/error.rhtml +1 -0
  62. data/app/views/journal/index.rhtml +1 -0
  63. data/app/views/journal/view.rhtml +15 -0
  64. data/app/views/layouts/application.rhtml +90 -0
  65. data/app/views/link/list.rhtml +19 -0
  66. data/app/views/link/new.rhtml +7 -0
  67. data/app/views/ping/trackback.rxml +4 -0
  68. data/app/views/post/_reply.rhtml +10 -0
  69. data/app/views/post/destroyxml.rxml +3 -0
  70. data/app/views/post/edit.rhtml +7 -0
  71. data/app/views/post/new.rhtml +13 -0
  72. data/app/views/post/postxml.rxml +7 -0
  73. data/app/views/post/reply.rhtml +33 -0
  74. data/app/views/post/replyxml.rxml +5 -0
  75. data/app/views/post/toggle_commentingxml.rxml +9 -0
  76. data/app/views/rss/index.rxml +15 -0
  77. data/app/views/tags/addxml.rxml +4 -0
  78. data/app/views/tags/index.rhtml +3 -0
  79. data/app/views/tags/no_completions.rhtml +1 -0
  80. data/app/views/tags/search.rhtml +10 -0
  81. data/app/views/tags/search_completer.rhtml +1 -0
  82. data/app/views/user/list.rhtml +21 -0
  83. data/app/views/user/new.rhtml +12 -0
  84. data/app/views/users/index.rhtml +6 -0
  85. data/config/app.yml +15 -0
  86. data/config/database.yml +17 -0
  87. data/config/environment.rb +58 -0
  88. data/config/environments/development.rb +5 -0
  89. data/config/environments/geminstall.rb +4 -0
  90. data/config/environments/production.rb +3 -0
  91. data/config/environments/shared.rb +17 -0
  92. data/config/environments/test.rb +3 -0
  93. data/db/db-mysql.sql +95 -0
  94. data/db/db-postgresql.sql +94 -0
  95. data/db/db-sqlite.sql +94 -0
  96. data/db/default_user.sql +1 -0
  97. data/db/development_structure.sql +257 -0
  98. data/elitejournal +132 -0
  99. data/lib/image_size.rb +277 -0
  100. data/lib/trackback.rb +45 -0
  101. data/public/404.html +6 -0
  102. data/public/500.html +6 -0
  103. data/public/dispatch.cgi +10 -0
  104. data/public/dispatch.fcgi +7 -0
  105. data/public/dispatch.rb +10 -0
  106. data/public/stylesheets/ej-layout.css +126 -0
  107. data/public/stylesheets/ej-style.css +105 -0
  108. data/public/stylesheets/undohtml.css +9 -0
  109. metadata +178 -0
@@ -0,0 +1,7 @@
1
+ module TagsHelper
2
+ def show_tags(tags)
3
+ links = []
4
+ tags.each { |t| links << link_to(t.tag, :controller => 'journal', :action => 'tag', :params => {'tag' => t.tag})}
5
+ links.join(', ')
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ module UserHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module UsersHelper
2
+ end
@@ -0,0 +1,24 @@
1
+ class BloggerApi
2
+ attr_reader :request
3
+
4
+ def initialize(request)
5
+ @request = request
6
+ end
7
+
8
+ def deletePost(appkey, postid, username, password, publish)
9
+ raise 'Invalid login' unless User.authenticate(username, password)
10
+ post = Post.find(postid)
11
+ post.destroy
12
+ true
13
+ end
14
+
15
+ def getUsersBlogs(appkey, username, password)
16
+ raise 'Invalid login' unless user = User.authenticate(username, password)
17
+ [ {'ur' => server_url, 'blogid' => 1, 'blogName' => user.title }]
18
+ end
19
+
20
+ private
21
+ def server_url
22
+ 'http://' << request.host << request.port_string
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :post
3
+ has_many :comments, :dependent => true
4
+
5
+ validates_presence_of :body
6
+
7
+ def before_save
8
+ self.posted_by = 'Anonymous' if self.posted_by.nil? or self.posted_by.empty?
9
+ self.subject = '' if self.subject.nil?
10
+
11
+ # Scrub up
12
+ self.posted_by = CGI.escapeElement self.posted_by, 'script'
13
+ self.subject = CGI.escapeElement self.subject, 'script'
14
+ self.body = CGI.escapeElement self.body, 'script'
15
+
16
+ self.rendered = RedCloth.new(self.body).to_html
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ class Draft < ActiveRecord::Base
2
+ belongs_to :category
3
+ belongs_to :user
4
+
5
+ validates_presence_of :user_id
6
+
7
+ def before_save
8
+ self.subject = CGI.escapeElement(self.subject, 'script') if self.subject
9
+ self.tb_url = CGI.escapeElement(self.tb_url, 'script') if self.tb_url
10
+ self.body = CGI.escapeElement(self.body, 'script') if self.body
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ class Face < Image
2
+ # A user's "face" should be no bigger than 75x75. So scale it with RMagick, if available
3
+ begin
4
+ require 'RMagick'
5
+
6
+ def before_save
7
+ image = Magick::Image.read_inline(encode64(self.picture)).first
8
+ image.change_geometry!('75x75') { |c,r,i| i.resize!(c, r) }
9
+ self.height = image.rows.to_s
10
+ self.width = image.columns.to_s
11
+ self.picture = image.to_blob
12
+ end
13
+ rescue LoadError
14
+ # If RMagick isn't available, well, just dump the whole thing into the DB without scaling.
15
+ # Too bad, so sorry. Install RMagick or write us some pure Ruby to scale images :).
16
+ require_dependency 'image_size'
17
+ def before_save
18
+ image = ImageSize.new(self.picture)
19
+ ratio = 75.0 / image.get_width
20
+ self.width = (image.get_width * ratio).to_i
21
+ self.height = (image.get_height * ratio).to_i
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ class FeedKiller < ActiveRecord::Observer
2
+ observe Post
3
+
4
+ def after_save(post)
5
+ @user = post.user.username
6
+ end
7
+
8
+ def filter(controller)
9
+ # Invalidate the user's feed
10
+ controller.expire_page :controller => 'rss', :action => @user
11
+ controller.expire_page :controller => 'atom', :action => @user
12
+
13
+ # Invalidate the main feeds
14
+ controller.expire_page :controller => 'rss', :action => 'index'
15
+ controller.expire_page :controller => 'atom', :action => 'feed'
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ class Image < ActiveRecord::Base
2
+ validates_presence_of :user_id
3
+ validates_presence_of :picture
4
+ validates_presence_of :content_type
5
+ validates_presence_of :height
6
+ validates_presence_of :width
7
+ end
@@ -0,0 +1,10 @@
1
+ class Link < ActiveRecord::Base
2
+ belongs_to :user
3
+
4
+ validates_presence_of :link_text, :link_url, :user_id
5
+
6
+ def before_save
7
+ self.link_text = CGI.escapeElement self.link_text, 'script'
8
+ self.link_url = CGI.escapeElement self.link_url, 'script'
9
+ end
10
+ end
@@ -0,0 +1,82 @@
1
+ class MetaWeblogApi
2
+ attr_reader :request
3
+
4
+ def initialize(request)
5
+ @request = request
6
+ end
7
+
8
+ def newPost(blogid, username, password, struct, publish)
9
+ raise 'Invalid login' unless user = User.authenticate(username, password)
10
+
11
+ post = Post.new
12
+ post.user = user
13
+ post.body = struct['description']
14
+ post.subject = struct['title']
15
+
16
+ if struct['categories']
17
+ struct['categories'].each do |c|
18
+ thetag = Tag.find_by_tag(c) || Tag.new('tag' => c)
19
+ thetag.increment('numitems')
20
+ thetag.save
21
+ post.tags << thetag
22
+ end
23
+ end
24
+
25
+ post.save
26
+ post.id.to_s
27
+ end
28
+
29
+ def deletePost(appkey, postid, username, password, publish)
30
+ raise 'Invalid login' unless User.authenticate(username, password)
31
+ Post.find(postid).destroy rescue nil
32
+ true
33
+ end
34
+
35
+ def editPost(postid, username, password, struct, publish)
36
+ raise 'Invalid login' unless user = User.authenticate(username, password)
37
+
38
+ post = Post.find(postid)
39
+ raise 'Not your post' unless post.user.id == user.id
40
+
41
+ post.body = struct['description']
42
+ post.subject = struct['title']
43
+
44
+ # Add tags Need Editing of Tags.
45
+
46
+ post.save
47
+ true
48
+ end
49
+
50
+ def getCategories(blogid, username, password)
51
+ raise 'Invalid login' unless User.authenticate(username, password)
52
+ Tag.find_all(nil, 'tag').collect { |t| t.tag }
53
+ end
54
+
55
+ def getRecentPosts(blogid, username, password, numberOfPosts)
56
+ raise 'Invalid login' unless user = User.authenticate(username, password)
57
+
58
+ user.posts.find_all(nil, 'created_at DESC', numberOfPosts).collect { |p| item_from(p) }
59
+ end
60
+
61
+ def getPost(postid, username, password)
62
+ raise 'Invalid login' unless User.authenticate(username, password)
63
+
64
+ item_from(Post.find(postid))
65
+ end
66
+
67
+ private
68
+ def item_from(post, rendered=true)
69
+ item = {
70
+ 'description' => post.body,
71
+ 'title' => post.subject,
72
+ 'postid' => post.id.to_s,
73
+ 'url' => "#{server_url}/view/#{post.id}",
74
+ 'dateCreated' => post.created_at,
75
+ 'categories' => post.tags.collect { |t| t.tag }
76
+ }
77
+ end
78
+
79
+ def server_url
80
+ 'http://' << request.host << request.port_string
81
+ end
82
+ end
@@ -0,0 +1,16 @@
1
+ class Ping < ActiveRecord::Base
2
+ belongs_to :post
3
+
4
+ validates_presence_of :post_id, :url
5
+
6
+ def validate
7
+ errors.add('post_id', 'Must have a post id') if self.post_id == 0
8
+ end
9
+
10
+ def before_save
11
+ self.title = CGI.escapeElement(self.title, 'script')
12
+ self.excerpt = CGI.escapeElement(self.excerpt, 'script')
13
+ self.url = CGI.escapeElement(self.url, 'script')
14
+ self.blog_name = CGI.escapeElement(self.blog_name, 'script')
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ class Post < ActiveRecord::Base
2
+ SECTION_DELIMITER = '<!--ej:section-->'
3
+
4
+ has_many :comments, :dependent => true
5
+ has_many :pings, :dependent => true
6
+ belongs_to :user
7
+ has_and_belongs_to_many :tags
8
+
9
+ validates_presence_of :subject, :body, :user_id
10
+
11
+ # The updated_on time stamp is always updated to now.
12
+ def before_save
13
+ self.subject = CGI.escapeElement(self.subject, 'script')
14
+ self.body = CGI.escapeElement(self.body, 'script')
15
+
16
+ @sections = self.body.split(/^----\s*$/).map! do |section|
17
+ RedCloth.new(section).to_html.gsub(/\t/, '')
18
+ end
19
+ self.rendered = @sections.join(SECTION_DELIMITER)
20
+ end
21
+
22
+ def updated?
23
+ self.created_at.strftime('%Y%m%d%H%M%S') != self.updated_at.strftime('%Y%m%d%H%M%S')
24
+ end
25
+
26
+ def sections
27
+ return @sections.dup if @sections
28
+ (@sections = self.rendered.split(SECTION_DELIMITER)).dup
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ class Stylesheet < ActiveRecord::Base
2
+ belongs_to :user
3
+
4
+ def before_save
5
+ self.data = CGI.escapeElement(self.data, 'script')
6
+ end
7
+ end
data/app/models/tag.rb ADDED
@@ -0,0 +1,16 @@
1
+ class Tag < ActiveRecord::Base
2
+ has_and_belongs_to_many :posts, :order => 'created_at DESC'
3
+
4
+ validates_presence_of :tag
5
+ validates_uniqueness_of :tag
6
+
7
+ def before_save
8
+ self.tag = CGI.escapeElement(self.tag, 'script')
9
+ end
10
+
11
+ def related_tags
12
+ related_tags = []
13
+ self.posts.each { |p| p.tags.each { |tt| related_tags << tt } }
14
+ related_tags.uniq.select { |t| t.tag != self.tag }
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ require 'digest/md5'
2
+
3
+ class User < ActiveRecord::Base
4
+ has_many :posts, :order => 'created_at DESC'
5
+ has_many :drafts, :dependent => true
6
+ has_many :links, :dependent => true
7
+ has_many :images, :dependent => true
8
+ has_one :stylesheet, :dependent => true
9
+ has_one :face, :dependent => true
10
+
11
+ validates_presence_of :username, :name
12
+ validates_uniqueness_of :username
13
+ validates_confirmation_of :password
14
+
15
+ def before_save
16
+ self.password = password.empty? ? self.class.find(id).password : Digest::MD5.hexdigest(password)
17
+ end
18
+
19
+ class << self
20
+ def authenticate(username, password)
21
+ find_first(["username = ? AND password = ?", username, Digest::MD5.hexdigest(password)])
22
+ end
23
+
24
+ def top_posters(n=5)
25
+ posters = find_by_sql("SELECT u.id FROM users u, posts p " +
26
+ "WHERE u.id = p.user_id GROUP BY u.id " +
27
+ "ORDER BY COUNT(p.id) DESC LIMIT #{n}").flatten
28
+ posters.map { |p| find(p) }
29
+ end
30
+ end
31
+
32
+ def last_post
33
+ self.posts.find_first(nil, 'created_at DESC') || self.posts.build('subject' => 'Example Post', 'rendered' => '<p>This is what a post looks like.</p>', 'created_at' => Time.now)
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ <div id="accountinfo">
2
+ <form action="/account/info" method="post" enctype="multipart/form-data">
3
+ <input type="hidden" name="id" value="<%= @user.id %>" />
4
+
5
+ <p><label for="user_username">Username</label><br />
6
+ <%= text_field 'user', 'username' %></p>
7
+
8
+ <p><label for="user_name">Name</label><br />
9
+ <%= text_field 'user', 'name' %></p>
10
+
11
+ <p><label for="user_title">Journal Title</label><br /><%= text_field('user', 'title') %></p>
12
+
13
+ <p><label for="user_subtitle">Journal Subtitle</label><br /><%= text_field('user', 'subtitle') %></p>
14
+
15
+ <p><label for="user_allows_comments">Allow Commenting?</label>&nbsp;&nbsp;<%= check_box('user', 'allows_comment', 'style' => 'width: auto;') %></p>
16
+ <p><label for="user_password">Password</label><br />
17
+ <input type="password" name="user[password]" id="user_password" size="30" /></p>
18
+
19
+ <p><label for="user_password_confirm">Confirm Password</label><br />
20
+ <input type="password" name="user[password_confirmation]" id="user_password_confirm" size="30" /></p>
21
+
22
+ <p style="float: left;"><label for="face_picture">Picture</label>
23
+ <small>will be scaled to 75x75 pixels</small><br />
24
+ <input type="hidden" name="MAX_FILE_SIZE" value="<%= @app_config['uploads']['max_face_size'] %>" />
25
+ <input type="file" name="face[picture]" id="face_picture" /></p>
26
+ <p style="float: right;"><%= user_face(@user) %></p>
27
+ <p><input style="width: auto;" type="submit" value="Update Info" /></p>
28
+
29
+ <%= end_form_tag %>
30
+ </div>
@@ -0,0 +1,15 @@
1
+ xml.feed('version' => '0.3', 'xmlns' => 'http://purl.org/atom/ns#') do
2
+ xml.title @title
3
+ xml.link 'rel' => 'alternate', 'type' => 'text/html', 'href' => "#{@request.protocol}#{@request.host_with_port}#{@app_config['main']['app_base']}"
4
+ xml.modified @posts.first.updated_at.xmlschema if @posts.first
5
+ @posts.each do |p|
6
+ xml.entry do
7
+ xml.title p.subject
8
+ xml.link 'rel' => 'alternate', 'type' => 'text/html', 'href' => "http://#{@request.host}#{@app_config['main']['app_base']}view/#{p.id}"
9
+ xml.author { xml.name p.user.name }
10
+ xml.issued p.created_at.xmlschema
11
+ xml.modified p.updated_at.xmlschema
12
+ xml.content({'type' => 'text/html', 'mode' => 'escaped'}, p.rendered)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ <div id="login">
2
+ <%= form_tag %>
3
+ <p><label for="username">Username</label><br />
4
+ <input type="text" id="username" name="username" /></p>
5
+ <p><label for="password">Password<br />
6
+ <input type="password" id="password" name="password" /></p>
7
+ <p><input type="submit" value="Log In" /></p>
8
+ <%= end_form_tag %>
9
+ </div>
@@ -0,0 +1,18 @@
1
+ <script type="text/javascript" src="/javascripts/livecss.js"></script>
2
+ <h1>Editing stylesheet</h1>
3
+
4
+ <div id="example_post">
5
+ <%= render_partial 'journal/post', @lastpost %>
6
+ </div>
7
+
8
+ <%= error_messages_for 'stylesheet' %>
9
+ <%= form_tag :action => 'update' %>
10
+ <p><label for="css">Enter Your CSS Below</label></p>
11
+ <p><input type="checkbox" id="css_toggle" onclick="toggleLiveCss();" /> <label for="css_toggle">Turn Off Live CSS</label></p>
12
+ <p><textarea style="width: 100%; height: 200px;" id="css" name="stylesheet[data]"><%= @stylesheet.data %></textarea></p>
13
+ <p><input type="submit" value="Update CSS" /></p>
14
+ <%= end_form_tag %>
15
+
16
+ <script type="text/javascript">
17
+ document.onload = startLiveCss();
18
+ </script>
@@ -0,0 +1,24 @@
1
+ <h1>Listing stylesheets</h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <% for column in Stylesheet.content_columns %>
6
+ <th><%= column.human_name %></th>
7
+ <% end %>
8
+ </tr>
9
+
10
+ <% for stylesheet in @stylesheets %>
11
+ <tr>
12
+ <% for column in Stylesheet.content_columns %>
13
+ <td><%=h stylesheet[column.name] %></td>
14
+ <% end %>
15
+ <td><%= link_to 'Show', :action => 'show', :id => stylesheet.id %></td>
16
+ <td><%= link_to 'Edit', :action => 'edit', :id => stylesheet.id %></td>
17
+ <td><%= link_to 'Destroy', :action => 'destroy', :id => stylesheet.id %></td>
18
+ </tr>
19
+ <% end %>
20
+ </table>
21
+
22
+ <br />
23
+
24
+ <%= link_to 'New stylesheet', :action => 'new' %>