Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 71
- Log:
Start of upgrade to Typo 4.0.0, the latest stable release since
2.6.0. Note test/mocks/themes/azure changes from a file to a
directory, so the file has been removed in this revision and
the directory will be added in the next revision.
- Author:
- adh
- Date:
- Mon Aug 07 22:18:11 +0100 2006
- Size:
- 6846 Bytes
1 | require 'uri' |
2 | require 'net/http' |
3 | |
4 | class Article < Content |
5 | include TypoGuid |
6 | |
7 | content_fields :body, :extended |
8 | |
9 | has_many :pings, :dependent => true, :order => "created_at ASC" |
10 | has_many :comments, :dependent => true, :order => "created_at ASC" |
11 | has_many :trackbacks, :dependent => true, :order => "created_at ASC" |
12 | has_many :resources, :order => "created_at DESC", |
13 | :class_name => "Resource", :foreign_key => 'article_id' |
14 | has_and_belongs_to_many :categories, :foreign_key => 'article_id' |
15 | has_and_belongs_to_many :tags, :foreign_key => 'article_id' |
16 | belongs_to :user |
17 | has_many :triggers, :as => :pending_item |
18 | |
19 | after_destroy :fix_resources |
20 | |
21 | def stripped_title |
22 | self.title.gsub(/<[^>]*>/,'').to_url |
23 | end |
24 | |
25 | def location(anchor=nil, only_path=true) |
26 | blog.article_url(self, only_path, anchor) |
27 | end |
28 | |
29 | def html_urls |
30 | urls = Array.new |
31 | (body_html.to_s + extended_html.to_s).gsub(/<a [^>]*>/) do |tag| |
32 | if(tag =~ /href="([^"]+)"/) |
33 | urls.push($1) |
34 | end |
35 | end |
36 | |
37 | urls |
38 | end |
39 | |
40 | def really_send_pings(serverurl = blog.server_url, articleurl = location(nil, false)) |
41 | return unless blog.send_outbound_pings |
42 | |
43 | weblogupdatesping_urls = blog.ping_urls.gsub(/ +/,'').split(/[\n\r]+/) |
44 | pingback_or_trackback_urls = self.html_urls |
45 | |
46 | ping_urls = weblogupdatesping_urls + pingback_or_trackback_urls |
47 | |
48 | ping_urls.uniq.each do |url| |
49 | begin |
50 | unless pings.collect { |p| p.url }.include?(url.strip) |
51 | ping = pings.build("url" => url) |
52 | |
53 | if weblogupdatesping_urls.include?(url) |
54 | ping.send_weblogupdatesping(serverurl, articleurl) |
55 | else pingback_or_trackback_urls.include?(url) |
56 | ping.send_pingback_or_trackback(articleurl) |
57 | end |
58 | end |
59 | rescue |
60 | # in case the remote server doesn't respond or gives an error, |
61 | # we should throw an xmlrpc error here. |
62 | end |
63 | end |
64 | end |
65 | |
66 | def send_pings |
67 | state.send_pings(self) |
68 | end |
69 | |
70 | def next |
71 | Article.find(:first, :conditions => ['published_at > ?', published_at], |
72 | :order => 'published_at asc') |
73 | end |
74 | |
75 | def previous |
76 | Article.find(:first, :conditions => ['published_at < ?', published_at], |
77 | :order => 'published_at desc') |
78 | end |
79 | |
80 | # Count articles on a certain date |
81 | def self.count_by_date(year, month = nil, day = nil, limit = nil) |
82 | from, to = self.time_delta(year, month, day) |
83 | Article.count(["published_at BETWEEN ? AND ? AND published = ?", |
84 | from, to, true]) |
85 | end |
86 | |
87 | # Find all articles on a certain date |
88 | def self.find_all_by_date(year, month = nil, day = nil) |
89 | from, to = self.time_delta(year, month, day) |
90 | Article.find_published(:all, :conditions => ["published_at BETWEEN ? AND ?", |
91 | from, to]) |
92 | end |
93 | |
94 | # Find one article on a certain date |
95 | |
96 | def self.find_by_date(year, month, day) |
97 | find_all_by_date(year, month, day).first |
98 | end |
99 | |
100 | # Finds one article which was posted on a certain date and matches the supplied dashed-title |
101 | def self.find_by_permalink(year, month, day, title) |
102 | from, to = self.time_delta(year, month, day) |
103 | find_published(:first, |
104 | :conditions => ['permalink = ? AND ' + |
105 | 'published_at BETWEEN ? AND ?', |
106 | title, from, to ]) |
107 | end |
108 | |
109 | # Fulltext searches the body of published articles |
110 | def self.search(query) |
111 | if !query.to_s.strip.empty? |
112 | tokens = query.split.collect {|c| "%#{c.downcase}%"} |
113 | find_published(:all, |
114 | :conditions => [(["(LOWER(body) LIKE ? OR LOWER(extended) LIKE ? OR LOWER(title) LIKE ?)"] * tokens.size).join(" AND "), *tokens.collect { |token| [token] * 3 }.flatten]) |
115 | else |
116 | [] |
117 | end |
118 | end |
119 | |
120 | def keywords_to_tags |
121 | Article.transaction do |
122 | tags.clear |
123 | keywords.to_s.scan(/((['"]).*?\2|[\.\w]+)/).collect do |x| |
124 | x.first.tr("\"'", '') |
125 | end.uniq.each do |tagword| |
126 | tags << Tag.get(tagword) |
127 | end |
128 | end |
129 | end |
130 | |
131 | def interested_users |
132 | User.find_boolean(:all, :notify_on_new_articles) |
133 | end |
134 | |
135 | def notify_user_via_email(controller, user) |
136 | if user.notify_via_email? |
137 | EmailNotify.send_article(controller, self, user) |
138 | end |
139 | end |
140 | |
141 | def notify_user_via_jabber(controller, user) |
142 | if user.notify_via_jabber? |
143 | JabberNotify.send_message(user, "New post", |
144 | "A new message was posted to #{blog.blog_name}", |
145 | content.body_html) |
146 | end |
147 | end |
148 | |
149 | def comments_closed? |
150 | if self.allow_comments? |
151 | if !self.blog.sp_article_auto_close.zero? and self.created_at.to_i < self.blog.sp_article_auto_close.days.ago.to_i |
152 | return true |
153 | else |
154 | return false |
155 | end |
156 | else |
157 | return true |
158 | end |
159 | end |
160 | |
161 | protected |
162 | |
163 | before_create :set_defaults, :create_guid, :add_notifications |
164 | before_save :set_published_at |
165 | after_save :keywords_to_tags |
166 | |
167 | def correct_counts |
168 | self.comments_count = self.comments_count |
169 | self.trackbacks_count = self.trackbacks_count |
170 | end |
171 | |
172 | def set_published_at |
173 | if self.published and self[:published_at].nil? |
174 | self[:published_at] = self.created_at || Time.now |
175 | end |
176 | end |
177 | |
178 | def set_defaults |
179 | if self.attributes.include?("permalink") and self.permalink.blank? |
180 | self.permalink = self.stripped_title |
181 | end |
182 | correct_counts |
183 | if blog && self.allow_comments.nil? |
184 | self.allow_comments = blog.default_allow_comments |
185 | end |
186 | |
187 | if blog && self.allow_pings.nil? |
188 | self.allow_pings = blog.default_allow_pings |
189 | end |
190 | |
191 | true |
192 | end |
193 | |
194 | def add_notifications |
195 | # Grr, how do I do :conditions => 'notify_on_new_articles = true' when on MySQL boolean DB tables |
196 | # are integers, Postgres booleans are booleans, and sqlite is basically just a string? |
197 | # |
198 | # I'm punting for now and doing the test in Ruby. Feel free to rewrite. |
199 | |
200 | self.notify_users = User.find_boolean(:all, :notify_on_new_articles) |
201 | self.notify_users << self.user if (self.user.notify_watch_my_articles? rescue false) |
202 | self.notify_users.uniq! |
203 | end |
204 | |
205 | def default_text_filter_config_key |
206 | 'text_filter' |
207 | end |
208 | |
209 | def self.time_delta(year, month = nil, day = nil) |
210 | from = Time.mktime(year, month || 1, day || 1) |
211 | |
212 | to = from.next_year |
213 | to = from.next_month unless month.blank? |
214 | to = from + 1.day unless day.blank? |
215 | to = to - 1 # pull off 1 second so we don't overlap onto the next day |
216 | return [from, to] |
217 | end |
218 | |
219 | def find_published(what = :all, options = {}) |
220 | options[:include] ||= [] |
221 | options[:include] += [:user] |
222 | super(what, options) |
223 | end |
224 | |
225 | validates_uniqueness_of :guid |
226 | validates_presence_of :title |
227 | |
228 | private |
229 | |
230 | def fix_resources |
231 | Resource.find(:all, :conditions => "article_id = #{id}").each do |fu| |
232 | fu.article_id = nil |
233 | fu.save |
234 | end |
235 | end |
236 | end |