-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcomment.rb
236 lines (219 loc) · 9.14 KB
/
comment.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
require 'classifier-reborn'
require 'pony'
require 'kramdown'
require 'htmlentities'
require 'yaml'
require_relative './commentauthor.rb'
module Ursprung
class Comment
attr_accessor :author
attr_accessor :body
# important for trackbacks:
attr_accessor :title
attr_accessor :date
attr_accessor :id
attr_accessor :replyToComment
attr_accessor :replyToEntry
attr_accessor :type
attr_accessor :status # can be moderate or approved
attr_accessor :subscribe
attr_accessor :validTrackback
def initialize(*args)
case args.length
when 1
initializeFromID(args[0])
when 2
# creating comment from hash
params = args[0]
return if params[:tel] && params[:tel] != "" # the honeypot
commentAuthor = CommentAuthor.new
commentAuthor.name = params[:name].strip
commentAuthor.name = "Anonymous" if commentAuthor.name == ""
commentAuthor.mail = params[:mail].strip
commentAuthor.url = params[:url].strip
begin
self.replyToComment = params[:replyToComment].empty? ? nil : params[:replyToComment]
rescue
# this can happen if we are getting a track/pingback
self.replyToComment = nil
end
self.replyToEntry = params[:entryId]
if self.entry.moderate == "closed"
return
end
self.body = HTMLEntities.new.encode(params[:body])
self.author = commentAuthor
self.id = params[:id]
self.status = "approved"
self.status = "moderate" if self.isSpam? || self.entry.moderate == "moderated"
self.subscribe = 1 if params[:subscribe] != nil
self.type = params[:type]
if self.type == "trackback"
name = getPingbackData()
if name
if self.body == ""
# it is a pingback, which needs to use the additional data
commentAuthor.name = name
self.author = commentAuthor
end
self.save()
self.validTrackback = true
else
self.validTrackback = false
end
else
self.save()
self.validTrackback = true
end
end
end
def initializeFromID(id)
db = Database.new
commentData = db.getCommentData(id)
self.id = id
self.body = commentData["body"]
self.date = commentData["date"]
self.title = commentData["date"]
self.replyToComment = commentData["replyToComment"]
self.replyToEntry = commentData["replyToEntry"]
self.type = commentData["type"]
self.status = commentData["status"]
self.subscribe = commentData["subscribe"]
commentAuthor = CommentAuthor.new
commentAuthor.name = commentData["name"]
commentAuthor.mail = commentData["mail"]
commentAuthor.url = commentData["url"]
self.author = commentAuthor
end
def save()
db = Database.new
if self.id == nil
# it is a new comment
db.addComment(self)
Ursprung::pool.process {
mailOwner()
if (self.status == "approved")
mailSubscribers()
end
}
else
db.editComment(self)
end
db.invalidateCache(self)
end
def delete()
db = Database.new
db.deleteComment(self)
db.invalidateCache(self)
end
def spam()
self.train "spam"
end
def ham()
self.train "ham"
self.status = "approved"
end
def train(category)
db = Database.new
bayes = db.getOption("spamFilter")
if bayes == nil
bayes = ClassifierReborn::Bayes.new "Spam", "Ham"
# we add some minimal initial training data, because if there is none in one of the categories it always returns "ham"
bayes.train "spam", "casino gold viagra"
bayes.train "ham", "a valid comment"
else
bayes = YAML.load(bayes)
end
[self.body, self.author.name, self.author.mail, self.author.url].each do |commentPart|
begin
bayes.train category, commentPart
rescue => error
warn "Could not learn as #{category}: #{error}"
end
end
db.setOption("spamFilter", bayes.to_yaml)
end
def isSpam?()
bayes = Database.new.getOption("spamFilter")
return true if bayes == nil # everything might be spam if we have no initialized filter
begin
return (YAML.load(bayes).classify "#{self.author.name} #{self.author.mail} #{self.author.url} #{self.body}") == "Spam"
rescue NoMethodError => nme
# added to not die on trackbacks here
return true
end
end
def entry()
return Entry.new(self.replyToEntry)
end
def mailOwner()
db = Database.new
begin
entry = self.entry
Pony.mail(:to => db.getAdminMail,
:from => db.getOption("fromMail"),
:subject => "#{db.getOption("blogTitle")}: #{self.author.name} commented on #{entry.title}",
:body => "He wrote: #{self.format}\n\nLink: #{Ursprung::baseUrl}#{entry.link}"
)
rescue Errno::ECONNREFUSED => e
warn "Error mailing owner: #{e}"
end
end
def mailSubscribers()
db = Database.new
fromMail = db.getOption("fromMail")
if fromMail && fromMail != ""
blogTitle = db.getOption("blogTitle")
mailDelivered = []
entry = self.entry
db.getCommentsForEntry(self.replyToEntry).each do |comment|
if comment.subscribe && comment.author.mail && comment.author.mail != "" && comment != self && ! mailDelivered.include?(comment.author.mail) && comment.author.mail != db.getAdminMail
begin
cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').send(:encrypt)
cipher.key = Digest::SHA256.digest(db.getOption("secret"))
encrypted = cipher.update(comment.author.mail) << cipher.final
Pony.mail(:to => comment.author.mail,
:from => fromMail,
:subject => "#{blogTitle}: #{self.author.name} commented on #{Entry.new(self.replyToEntry).title}",
# TODO: Use a template (with url_for) for this
:body => "He wrote: #{self.format}\n\nLink: #{Ursprung::baseUrl}#{entry.link}\n\nUnsubscribe: #{Ursprung::baseUrl}subscriptions/#{URI.escape(encrypted)}"
)
mailDelivered.push(comment.author.mail)
rescue Errno::ECONNREFUSED => e
warn "Error mailing subscribers: #{e}"
end
end
end
end
end
# If a valid link exists, gather the data to format the pingback. Else return false
def getPingbackData()
uri = URI.parse(self.author.url)
response = HTTP.get(uri).to_s
doc = Oga.parse_html(response)
title = doc.css('title').first.text
doc.css("a").map do |link|
if (href = link.attr("href").value) && href.match(/#{self.entry.link()}.*/)
return title
end
end.compact
return false
end
def avatar()
if self.author.mail
return "http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(self.author.mail.downcase)}?d=mm&s=40"
else
return nil
end
end
def format()
return Kramdown::Document.new( self.body.gsub(
/>>([0-9]*)/,
'<a class="commentReference" href="#c\1">>>\1</a> '
),
:auto_ids => false,
:hard_wrap => true
).to_html
end
end
end