typo 5.4.1 → 5.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/CHANGELOG +10 -24
  2. data/app/controllers/accounts_controller.rb +18 -1
  3. data/app/controllers/admin/content_controller.rb +1 -0
  4. data/app/controllers/admin/resources_controller.rb +17 -3
  5. data/app/controllers/application_controller.rb +2 -5
  6. data/app/helpers/admin/base_helper.rb +16 -6
  7. data/app/helpers/admin/resources_helper.rb +6 -0
  8. data/app/helpers/application_helper.rb +7 -8
  9. data/app/models/article.rb +8 -10
  10. data/app/models/blog.rb +26 -24
  11. data/app/models/content.rb +17 -10
  12. data/app/models/feedback.rb +1 -1
  13. data/app/models/page.rb +1 -1
  14. data/app/models/resource.rb +14 -0
  15. data/app/models/user.rb +1 -0
  16. data/app/views/accounts/login.html.erb +2 -1
  17. data/app/views/accounts/recover_password.html.erb +18 -0
  18. data/app/views/admin/content/_form.html.erb +8 -5
  19. data/app/views/admin/content/_images.html.erb +14 -0
  20. data/app/views/admin/content/_visual_editor.html.erb +5 -0
  21. data/app/views/admin/pages/_visual_editor.html.erb +9 -5
  22. data/app/views/admin/resources/_upload.html.erb +10 -0
  23. data/app/views/admin/resources/get_thumbnails.html.erb +5 -0
  24. data/app/views/admin/resources/images.html.erb +28 -0
  25. data/app/views/admin/resources/index.html.erb +42 -11
  26. data/app/views/layouts/administration.html.erb +1 -1
  27. data/app/views/notification_mailer/notif_user.html.erb +1 -1
  28. data/config/environment.rb +1 -1
  29. data/config/initializers/access_rules.rb +2 -1
  30. data/config/initializers/inflector.rb +4 -1
  31. data/db/schema.rb +26 -32
  32. data/lib/tasks/release.rake +1 -1
  33. data/lib/typo_version.rb +1 -1
  34. data/public/images/thumb_blank.jpg +0 -0
  35. data/public/javascripts/base_packaged.js +377 -0
  36. data/public/javascripts/ckeditor/config.bak +27 -11
  37. data/public/javascripts/quicktags.js +11 -0
  38. data/public/javascripts/typo_carousel.js +340 -0
  39. data/public/stylesheets/administration.css +16 -0
  40. data/public/stylesheets/base_packaged.css +100 -0
  41. data/script/about +3 -2
  42. data/script/console +1 -1
  43. data/script/dbconsole +1 -1
  44. data/script/destroy +1 -1
  45. data/script/generate +1 -1
  46. data/script/performance/benchmarker +1 -1
  47. data/script/performance/profiler +1 -1
  48. data/script/plugin +2 -2
  49. data/script/runner +2 -2
  50. data/script/server +2 -2
  51. data/spec/controllers/accounts_controller_spec.rb +47 -0
  52. data/spec/controllers/admin/content_controller_spec.rb +4 -0
  53. data/spec/controllers/admin/resources_controller_spec.rb +8 -0
  54. data/spec/controllers/xml_controller_spec.rb +13 -16
  55. data/spec/factories.rb +14 -1
  56. data/spec/models/article_spec.rb +57 -14
  57. data/spec/models/blog_spec.rb +50 -3
  58. data/spec/models/trackback_spec.rb +1 -1
  59. data/spec/models/user_spec.rb +7 -12
  60. data/spec/spec_helper.rb +1 -1
  61. data/test/fixtures/users.yml +15 -8
  62. data/themes/true-blue-3/images/background.gif +0 -0
  63. data/vendor/plugins/easy-ckeditor/lib/ckeditor.rb +1 -2
  64. data/vendor/plugins/easy-ckeditor/lib/ckeditor_file_utils.rb +2 -2
  65. metadata +11 -11
  66. data/app/views/admin/resources/_resources.html.erb +0 -41
  67. data/script/benchmarker +0 -19
  68. data/script/performance/request +0 -3
  69. data/script/process/inspector +0 -3
  70. data/script/process/reaper +0 -3
  71. data/script/process/spawner +0 -3
  72. data/script/process/spinner +0 -3
  73. data/script/profiler +0 -34
  74. data/script/spec_server +0 -9
data/CHANGELOG CHANGED
@@ -1,37 +1,23 @@
1
- Only 1 week after releasing Typo 5.4, we're back with another cool Typo release. Since it was fixing a major security breach, Typo 5.4 was released a bit too quickly, and we left some bugs here and there we promptly fixed. So don't expect any new feature here, it's only about bug fixing and refactoring. Apparently, Matijs and Cyril had great fun doing this. I started to work on the first Typo user's guide as in our documentation effort. The 0.1 version is provided in Typo 5.4.1. We've also upgraded every theme at Typogarden to make them 5.4.1 compliant.
1
+ 3 weeks after releasing Typo 5.4.1, and only 1 month after releasing Typo 5.4, we're happy to release Typo 5.4.2, an important bugfix release. Don't expect many feature here, even though we thought about some of them, it's really a bugfix, and nothing else.
2
2
 
3
- Since we're still working on what we want to see in the next Typo, don't mind opening a ticket to ask for something you want.
3
+ ** Features
4
4
 
5
- [#68] Atom feed has duplicated content
6
- There was a duplicate content in atom feed because of the use of atom:summary with extended content. Since summary is not mandatory, and it should not duplicate content, we've decided to remove it one from the feed.
5
+ We've split the attachments between images and non images assets. Provided you're using the simple editor, you can now use a fancy images carousel and insert your images in your text within a single click. This comes with a nice set of thumbnails.
7
6
 
8
- [#75] <typo:code> textfilter need change all < by &lt; in atom feed
7
+ Finally, the long awaited "forgot my password" link is here. It will send you a new password whenever you lose yours. Cool isn't it?
9
8
 
10
- [#86] Migrations out of necessary sequence
9
+ We've also done some optimization in the way Typo sends assets and manages cache. CSS and Javascript are now sent into 1 file, making them faster to load. RSS generation has also been fastened up.
11
10
 
12
- [#124] &gt; and &lt; entities are decoded in the atom feed
11
+ ** Bugs
13
12
 
14
- [#126] Previews give an application error
13
+ A bug screwing up the editor when switching from simple to visual, causing users to lose their content when switching. Fixing that is a good reason to release today in itself.
15
14
 
16
- [#127] Changing post's title changes the permalink slug
15
+ A bug preventing your registration email to go when creating your account, making you lose your password unless you change it manually before logging out.
17
16
 
18
- [#128] Fix typogarden themes
19
- Seems obvious isn't it?
17
+ Fixed a security issue making the user passwords to be logged in clear in the application logs.
20
18
 
21
- [#130] Theme editor textbox is too small
22
- There was actually wet paint in our new admin. We fixed that quickly.
19
+ Fixed a bug causing CKEditor to crash under MS Windows due to the lack of symlinks on windows.
23
20
 
24
- [#131] New Tags are created two times
25
- The way autosave on new / saved articles worked was quite complicated and ended with strange behavior.
26
-
27
- [#132] Categories are brocken
28
- A typo in the category views.
29
-
30
- [#133] Installer parameter database=sqlite3 doesn't work
31
- Awated parameter was database=sqlite, but since this could be confusing, we've made sqlite3 avaliable as well.
32
-
33
- [#134] "Continue reading ..." link appears for posts that do not have additional content.
34
- This one was actually the tree hiding the forest of all our themes being brocken because it constant renaming of the read controller and action name.
35
21
 
36
22
 
37
23
 
@@ -1,6 +1,7 @@
1
1
  class AccountsController < ApplicationController
2
2
 
3
- before_filter :verify_users, :only => [:login]
3
+ before_filter :verify_users, :only => [:login, :recover_password]
4
+ filter_parameter_logging "password"
4
5
 
5
6
  def login
6
7
  if session[:user_id] && session[:user_id] == self.current_user.id
@@ -65,6 +66,22 @@ class AccountsController < ApplicationController
65
66
  end
66
67
  end
67
68
  end
69
+
70
+ def recover_password
71
+ @page_title = "#{this_blog.blog_name} - #{_('Recover your password')}"
72
+ if request.post?
73
+ @user = User.find(:first, :conditions => ["login = ? or email = ?", params[:user][:login], params[:user][:login]])
74
+
75
+ if @user
76
+ @user.password = generate_password
77
+ @user.save
78
+ flash[:notice] = _("An email has been successfully sent to your address with your new password")
79
+ redirect_to :action => 'login'
80
+ else
81
+ flash[:error] = _("Oops, something wrong just happened")
82
+ end
83
+ end
84
+ end
68
85
 
69
86
  def logout
70
87
  flash[:notice] = _("Successfully logged out")
@@ -147,6 +147,7 @@ class Admin::ContentController < Admin::BaseController
147
147
  params[:article] ||= {}
148
148
 
149
149
  @resources = Resource.find(:all, :order => 'filename')
150
+ @images = Resource.paginate :page => params[:page], :conditions => "mime LIKE '%image%'", :order => 'created_at DESC', :per_page => 10
150
151
  @article.attributes = params[:article]
151
152
 
152
153
 
@@ -16,7 +16,8 @@ class Admin::ResourcesController < Admin::BaseController
16
16
  @up = Resource.create(:filename => file.original_filename, :mime => mime, :created_at => Time.now)
17
17
 
18
18
  @up.write_to_disk(file)
19
-
19
+ @up.create_thumbnail
20
+
20
21
  @message = _('File uploaded: ')+ file.size.to_s
21
22
  finish_upload_status "'#{@message}'"
22
23
  end
@@ -78,9 +79,22 @@ class Admin::ResourcesController < Admin::BaseController
78
79
  def index
79
80
  @r = Resource.new
80
81
  @itunes_category_list = @r.get_itunes_categories
81
- @resources = Resource.paginate :page => params[:page], :conditions => @conditions, :order => 'created_at DESC', :per_page => this_blog.admin_display_elements
82
+ @resources = Resource.paginate :page => params[:page], :conditions => "mime NOT LIKE '%image%'", :order => 'created_at DESC', :per_page => this_blog.admin_display_elements
82
83
  end
83
-
84
+
85
+ def images
86
+ @resources = Resource.paginate :page => params[:page], :conditions => "mime LIKE '%image%'", :order => 'created_at DESC', :per_page => this_blog.admin_display_elements
87
+ end
88
+
89
+ def get_thumbnails
90
+ position = params[:position].to_i
91
+
92
+ @resources = Resource.find(:all, :conditions => "mime LIKE '%image%'", :order => 'created_at DESC', :limit => "#{position}, 10")
93
+
94
+ render 'get_thumbnails', :layout => false
95
+
96
+ end
97
+
84
98
  def destroy
85
99
  begin
86
100
  @file = Resource.find(params[:id])
@@ -52,9 +52,7 @@ class ApplicationController < ActionController::Base
52
52
  @current_user = nil
53
53
  end
54
54
 
55
- # The Blog object for the blog that matches the current request. This is looked
56
- # up using Blog.find_blog and cached for the lifetime of the controller instance;
57
- # generally one request.
55
+ # Helper method to get the blog object.
58
56
  def this_blog
59
57
  @blog ||= Blog.default
60
58
  end
@@ -62,8 +60,7 @@ class ApplicationController < ActionController::Base
62
60
  helper_method :this_blog
63
61
 
64
62
  # The base URL for this request, calculated by looking up the URL for the main
65
- # blog index page. This is matched with Blog#base_url to determine which Blog
66
- # is supposed to handle this URL
63
+ # blog index page.
67
64
  def blog_base_url
68
65
  url_for(:controller => '/articles').gsub(%r{/$},'')
69
66
  end
@@ -132,12 +132,6 @@ module Admin::BaseHelper
132
132
  controller.controller_name =~ /profiles/ ? "current right" : "right"
133
133
  end
134
134
 
135
-
136
- def t_textarea(object_name, method, options)
137
- return ckeditor_textarea(object_name, method, options) if current_user.editor == 'visual'
138
- text_area(object_name, method, options)
139
- end
140
-
141
135
  def alternate_editor
142
136
  return 'visual' if current_user.editor == 'simple'
143
137
  return 'simple'
@@ -221,4 +215,20 @@ module Admin::BaseHelper
221
215
  return "<tr><td colspan=#{cols} class='paginate'>#{will_paginate(collection)}</td></tr>"
222
216
  end
223
217
  end
218
+
219
+ def show_thumbnail_for_editor(image)
220
+ thumb = "#{RAILS_ROOT}/public/files/thumb_#{image.filename}"
221
+ picture = "#{this_blog.base_url}/files/#{image.filename}"
222
+
223
+ image.create_thumbnail unless File.exists? thumb
224
+
225
+ # If something went wrong with thumbnail generation, we just display a place holder
226
+ thumbnail = (File.exists? thumb) ? "#{this_blog.base_url}/files/thumb_#{image.filename}" : "#{this_blog.base_url}/images/thumb_blank.jpg"
227
+
228
+ picture = "<img class='tumb' src='#{thumbnail}' "
229
+ picture << "alt='#{this_blog.base_url}/files/#{image.filename}' "
230
+ picture << " onclick=\"edInsertImageFromCarousel('article_body_and_extended', '#{this_blog.base_url}/files/#{image.filename}');\" />"
231
+ return picture
232
+ end
233
+
224
234
  end
@@ -1,2 +1,8 @@
1
1
  module Admin::ResourcesHelper
2
+ def show_thumbnail(image)
3
+ image.create_thumbnail unless File.exists? "#{RAILS_ROOT}/public/files/thumb_#{image.filename}"
4
+
5
+ "<img class='tumb' src='#{this_blog.base_url}/files/thumb_#{image.filename}' alt='#{this_blog.base_url}/files/#{image.filename}' />"
6
+ end
7
+
2
8
  end
@@ -136,6 +136,10 @@ module ApplicationHelper
136
136
  end
137
137
  end
138
138
 
139
+ def javascript_include_lang
140
+ javascript_include_tag "lang/#{Localization.lang.to_s}" if File.exists? File.join(RAILS_ROOT, 'public', 'lang', Localization.lang.to_s)
141
+ end
142
+
139
143
  def page_header
140
144
  page_header_includes = contents.collect { |c| c.whiteboard }.collect do |w|
141
145
  w.select {|k,v| k =~ /^page_header_/}.collect do |(k,v)|
@@ -157,15 +161,10 @@ module ApplicationHelper
157
161
  <link rel="EditURI" type="application/rsd+xml" title="RSD" href="#{ url_for :controller => '/xml', :action => 'rsd' }" />
158
162
  <link rel="alternate" type="application/atom+xml" title="Atom" href="#{ feed_atom }" />
159
163
  <link rel="alternate" type="application/rss+xml" title="RSS" href="#{ feed_rss }" />
160
- #{ stylesheet_link_tag 'coderay.css', :media => 'all' }
161
- #{ stylesheet_link_tag 'user-styles.css', :media => 'all' }
162
- #{ javascript_include_tag "lang/" + Localization.lang.to_s }
163
- #{ javascript_include_tag "cookies" }
164
+ #{ javascript_include_tag 'cookies', 'prototype', 'effects', 'builder', 'typo', :cache => true }
165
+ #{ stylesheet_link_tag 'coderay', 'user-styles', :cache => true }
166
+ #{ javascript_include_lang }
164
167
  #{ javascript_tag "window._token = '#{form_authenticity_token}'"}
165
- #{ javascript_include_tag "prototype" }
166
- #{ javascript_include_tag "effects" }
167
- #{ javascript_include_tag "builder" }
168
- #{ javascript_include_tag "typo" }
169
168
  #{ page_header_includes.join("\n") }
170
169
  <script type="text/javascript">#{ @content_for_script }</script>
171
170
  #{ google_analytics }
@@ -156,7 +156,7 @@ class Article < Content
156
156
  end
157
157
  end
158
158
 
159
- def permalink_url(anchor=nil, only_path=true)
159
+ def permalink_url(anchor=nil, only_path=false)
160
160
  @cached_permalink_url ||= {}
161
161
 
162
162
  @cached_permalink_url["#{anchor}#{only_path}"] ||= \
@@ -181,7 +181,7 @@ class Article < Content
181
181
  end
182
182
 
183
183
  def trackback_url
184
- blog.url_for("trackbacks?article_id=#{self.id}", :only_path => true)
184
+ blog.url_for("trackbacks?article_id=#{self.id}", :only_path => false)
185
185
  end
186
186
 
187
187
  def permalink_by_format(format=nil)
@@ -197,11 +197,11 @@ class Article < Content
197
197
  end
198
198
 
199
199
  def comment_url
200
- blog.url_for("comments?article_id=#{self.id}", :only_path => true)
200
+ blog.url_for("comments?article_id=#{self.id}", :only_path => false)
201
201
  end
202
202
 
203
203
  def preview_comment_url
204
- blog.url_for("comments/preview?article_id=#{self.id}", :only_path => true)
204
+ blog.url_for("comments/preview?article_id=#{self.id}", :only_path => false)
205
205
  end
206
206
 
207
207
  def feed_url(format = :rss20)
@@ -219,9 +219,9 @@ class Article < Content
219
219
 
220
220
  def html_urls
221
221
  urls = Array.new
222
- html.gsub(/<a [^>]*>/) do |tag|
223
- if(tag =~ /href="([^"]+)"/)
224
- urls.push($1)
222
+ html.gsub(/<a\s+[^>]*>/) do |tag|
223
+ if(tag =~ /\bhref=(["']?)([^ >"]+)\1/)
224
+ urls.push($2)
225
225
  end
226
226
  end
227
227
 
@@ -451,9 +451,7 @@ class Article < Content
451
451
  end
452
452
 
453
453
  def rss_comments(xml)
454
- iri = permalink_url
455
- uri = Addressable::URI.parse(iri).normalize
456
- xml.comments(uri + "#comments")
454
+ xml.comments(normalized_permalink_url + "#comments")
457
455
  end
458
456
 
459
457
  def link_to_author?
data/app/models/blog.rb CHANGED
@@ -4,17 +4,24 @@ class BlogRequest
4
4
  attr_accessor :protocol, :host_with_port, :path, :symbolized_path_parameters, :relative_url_root
5
5
 
6
6
  def initialize(root)
7
- @protocol = @host_with_port = @path = ''
7
+ unless root =~ /(https?):\/\/([^\/]*)(.*)/
8
+ raise "Invalid root argument: #{root}"
9
+ end
10
+ @protocol = $1
11
+ @host_with_port = $2
12
+ @relative_url_root = $3.gsub(%r{/$},'')
13
+ @path = ''
8
14
  @symbolized_path_parameters = {}
9
- @relative_url_root = root.gsub(%r{/$},'')
10
15
  end
11
16
  end
12
17
 
13
- # The Blog class represents one blog. It stores most configuration settings
14
- # and is linked to most of the assorted content classes via has_many.
18
+ # The Blog class represents the one and only blog. It stores most
19
+ # configuration settings and is linked to most of the assorted content
20
+ # classes via has_many.
21
+ #
22
+ # Once upon a time, there were plans to make typo handle multiple blogs,
23
+ # but it never happened and typo is now firmly single-blog.
15
24
  #
16
- # Typo decides which Blog object to use by searching for a Blog base_url that
17
- # matches the base_url computed for each request.
18
25
  class Blog < ActiveRecord::Base
19
26
  include ConfigManager
20
27
  extend ActiveSupport::Memoizable
@@ -98,14 +105,8 @@ class Blog < ActiveRecord::Base
98
105
  end
99
106
  end
100
107
 
101
- # Find the Blog that matches a specific base URL. If no Blog object is found
102
- # that matches, then grab the default blog. If *that* fails, then create a new
103
- # Blog. The last case should only be used when Typo is first installed.
104
- def self.find_blog(base_url)
105
- Blog.default || Blog.create
106
- end
107
-
108
- # The default Blog. This is the lowest-numbered blog, almost always id==1.
108
+ # The default Blog. This is the lowest-numbered blog, almost always
109
+ # id==1. This should be the only blog as well.
109
110
  def self.default
110
111
  find(:first, :order => 'id')
111
112
  rescue
@@ -145,30 +146,31 @@ class Blog < ActiveRecord::Base
145
146
  # without needing a controller handy, so we can produce URLs from within models
146
147
  # where appropriate.
147
148
  #
148
- # It also uses our new RouteCache, so repeated URL generation requests should be
149
- # fast, as they bypass all of Rails' route logic.
149
+ # It also caches the result in the RouteCache, so repeated URL generation
150
+ # requests should be fast, as they bypass all of Rails' route logic.
150
151
  def url_for(options = {}, extra_params = {})
152
+ @request ||= BlogRequest.new(self.base_url)
151
153
  case options
152
154
  when String
153
- url_generated = ''
154
- url_generated = self.base_url if extra_params[:only_path]
155
+ if extra_params[:only_path]
156
+ url_generated = @request.relative_url_root
157
+ else
158
+ url_generated = self.base_url
159
+ end
155
160
  url_generated += "/#{options}" # They asked for 'url_for "/some/path"', so return it unedited.
156
161
  url_generated += "##{extra_params[:anchor]}" if extra_params[:anchor]
157
162
  url_generated
158
163
  when Hash
159
164
  unless RouteCache[options]
160
- options.reverse_merge!(:only_path => true, :controller => '',
165
+ options.reverse_merge!(:only_path => false, :controller => '',
161
166
  :action => 'permalink')
162
- # In Rails > 2.2 the rewrite method use
163
- # ActionController::Base.relative_url_root instead of
164
- # @request.relative_url_root
167
+ @url ||= ActionController::UrlRewriter.new(@request, {})
165
168
  if ActionController::Base.relative_url_root.nil?
166
169
  old_relative_url = nil
167
170
  else
168
171
  old_relative_url = ActionController::Base.relative_url_root.dup
169
172
  end
170
- ActionController::Base.relative_url_root = self.base_url
171
- @url ||= ActionController::UrlRewriter.new(BlogRequest.new(self.base_url), {})
173
+ ActionController::Base.relative_url_root = @request.relative_url_root
172
174
  RouteCache[options] = @url.rewrite(options)
173
175
  ActionController::Base.relative_url_root = old_relative_url
174
176
  end
@@ -70,7 +70,7 @@ class Content < ActiveRecord::Base
70
70
  end
71
71
 
72
72
  class << self
73
- # Quite a bit of this isn't needed anymore.
73
+ # FIXME: Quite a bit of this isn't needed anymore.
74
74
  def content_fields(*attribs)
75
75
  @@content_fields[self] = ((@@content_fields[self]||[]) + attribs).uniq
76
76
  @@html_map[self] = nil
@@ -268,7 +268,7 @@ class Content < ActiveRecord::Base
268
268
  end
269
269
 
270
270
  def blog
271
- Blog.default
271
+ @blog ||= Blog.default
272
272
  end
273
273
 
274
274
  def publish!
@@ -318,8 +318,7 @@ class Content < ActiveRecord::Base
318
318
  rss_groupings(xml)
319
319
  rss_enclosure(xml)
320
320
  rss_trackback(xml)
321
- # TODO: Perhaps permalink_url should produce valid URI's instead of IRI's
322
- xml.link Addressable::URI.parse(permalink_url).normalize
321
+ xml.link normalized_permalink_url
323
322
  end
324
323
  end
325
324
 
@@ -327,13 +326,16 @@ class Content < ActiveRecord::Base
327
326
  end
328
327
 
329
328
  def rss_description(xml)
330
- if respond_to?(:user) && self.user && self.user.name
331
- rss_desc = "<hr /><p><small>#{_('Original article writen by')} #{self.user.name} #{_('and published on')} <a href='#{blog.base_url}'>#{blog.blog_name}</a> | <a href='#{self.permalink_url}'>#{_('direct link to this article')}</a> | #{_('If you are reading this article elsewhere than')} <a href='#{blog.base_url}'>#{blog.blog_name}</a>, #{_('it has been illegally reproduced and without proper authorization')}.</small></p>"
332
- else
333
- rss_desc = ""
334
- end
335
329
  post = html(blog.show_extended_on_rss ? :all : :body)
336
- xml.description(blog.rss_description ? post + rss_desc : post)
330
+ if blog.rss_description
331
+ if respond_to?(:user) && self.user && self.user.name
332
+ rss_desc = "<hr /><p><small>#{_('Original article writen by')} #{self.user.name} #{_('and published on')} <a href='#{blog.base_url}'>#{blog.blog_name}</a> | <a href='#{self.permalink_url}'>#{_('direct link to this article')}</a> | #{_('If you are reading this article elsewhere than')} <a href='#{blog.base_url}'>#{blog.blog_name}</a>, #{_('it has been illegally reproduced and without proper authorization')}.</small></p>"
333
+ else
334
+ rss_desc = ""
335
+ end
336
+ post = post + rss_desc
337
+ end
338
+ xml.description(post)
337
339
  end
338
340
 
339
341
  def rss_groupings(xml)
@@ -354,6 +356,11 @@ class Content < ActiveRecord::Base
354
356
  def atom_content(entry)
355
357
  entry.content(html(:all), :type => 'html')
356
358
  end
359
+
360
+ # TODO: Perhaps permalink_url should produce valid URI's instead of IRI's
361
+ def normalized_permalink_url
362
+ @normalized_permalink_url ||= Addressable::URI.parse(permalink_url).normalize
363
+ end
357
364
  end
358
365
 
359
366
  class Object
@@ -35,7 +35,7 @@ class Feedback < Content
35
35
  article
36
36
  end
37
37
 
38
- def permalink_url(anchor=:ignored, only_path=true)
38
+ def permalink_url(anchor=:ignored, only_path=false)
39
39
  article.permalink_url("#{self.class.to_s.downcase}-#{id}",only_path)
40
40
  end
41
41
 
data/app/models/page.rb CHANGED
@@ -16,7 +16,7 @@ class Page < Content
16
16
  eval(list_function.join('.'))
17
17
  end
18
18
 
19
- def permalink_url(anchor=nil, only_path=true)
19
+ def permalink_url(anchor=nil, only_path=false)
20
20
  blog.url_for(
21
21
  :controller => '/articles',
22
22
  :action => 'view_page',