parlement 0.9 → 0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGES +20 -1
  2. data/MEMORY +51 -0
  3. data/README +11 -38
  4. data/Rakefile +2 -2
  5. data/app/controllers/account_controller.rb +83 -50
  6. data/app/controllers/application.rb +3 -0
  7. data/app/controllers/elt_controller.rb +14 -3
  8. data/app/controllers/subscriber_controller.rb +25 -9
  9. data/app/helpers/elt_helper.rb +1 -1
  10. data/app/models/elt.rb +23 -13
  11. data/app/models/mail.rb +37 -17
  12. data/app/models/mail_notify.rb +6 -5
  13. data/app/models/person.rb +6 -5
  14. data/app/models/person_mail.rb +4 -0
  15. data/app/models/person_notify.rb +13 -0
  16. data/app/models/subscription.rb +4 -0
  17. data/app/views/account/_login.rhtml +9 -12
  18. data/app/views/account/_show.rhtml +35 -16
  19. data/app/views/elt/_elt.rhtml +8 -20
  20. data/app/views/elt/_listByVote.rhtml +9 -9
  21. data/app/views/elt/show.rhtml +6 -33
  22. data/app/views/layouts/top.rhtml +6 -0
  23. data/app/views/person_notify/setEmail.rhtml +24 -0
  24. data/app/views/subscriber/_list.rhtml +18 -0
  25. data/config/environment.rb +6 -4
  26. data/config/environments/development.rb +2 -0
  27. data/db/ROOT/parlement/{news → News}/Version_01.txt +0 -0
  28. data/db/ROOT/parlement/{news → News}/Version_02.txt +0 -0
  29. data/db/ROOT/parlement/{news → News}/Version_03.txt +0 -0
  30. data/db/ROOT/parlement/{news → News}/Version_04.txt +0 -0
  31. data/db/ROOT/parlement/{news → News}/Version_05.txt +0 -0
  32. data/db/ROOT/parlement/{news → News}/Version_06.txt +0 -0
  33. data/db/ROOT/parlement/{news → News}/Version_07.txt +0 -0
  34. data/db/ROOT/parlement/{news → News}/Version_08.txt +0 -0
  35. data/db/ROOT/parlement/{security → Security}/anonymity.txt +0 -0
  36. data/db/ROOT/parlement.txt +1 -1
  37. data/db/development_structure.sql +49 -34
  38. data/db/migrate/003_elt_children_count.rb +1 -1
  39. data/db/migrate/005_filter_mail.rb +22 -0
  40. data/public/javascripts/mybehaviour.js +10 -2
  41. data/public/stylesheets/default.css +21 -15
  42. data/test/unit/choice_test.rb +1 -1
  43. data/test/unit/elt_test.rb +1 -1
  44. data/test/unit/mail_notify_test.rb +24 -8
  45. data/test/unit/mail_test.rb +61 -6
  46. data/test/unit/{notifier_test.rb → person_notify_test.rb} +2 -2
  47. data/test/unit/person_test.rb +1 -1
  48. data/test/unit/subscriber_test.rb +12 -12
  49. metadata +24 -20
  50. data/app/models/notifier.rb +0 -13
  51. data/app/views/notifier/changeEmail.rhtml +0 -10
  52. data/public/images/comments.gif +0 -0
data/CHANGES CHANGED
@@ -1,9 +1,28 @@
1
1
  - parlement changelog
2
2
 
3
+ == Version 0.10
4
+
5
+ Democratically moderated mails.
6
+
7
+ Elements are displayed on the web page or sent by mail when they reach a user
8
+ chosen voting threshold.
9
+
10
+ * one element threads are not automatically displayed anymore
11
+ * better spam fighting
12
+ * unsubscribe now also works when user is subscribed on a parent elt
13
+ * correcting a badly managed reply_to in mails
14
+ * setEmail and setPassword
15
+ * small threads automatically displayed (SUB_THREAD_LENGTH = 5)
16
+ * colored logs
17
+ * persistent cookies for authentication
18
+ * fighting the bacon spammer :-(
19
+ * easier rss auto discovery (html/head/link)
20
+ * moderated mails
21
+
3
22
  == Version 0.9
4
23
 
5
24
  Improved look, particularly the voting and writing part. Long posts and lists
6
- now truncated. Permanent login. Positioned elements. Search form (though
25
+ now truncated. Permanent login. Positioned elements. Search form (through
7
26
  google).
8
27
 
9
28
  * now asking to choose a pseudo
data/MEMORY ADDED
@@ -0,0 +1,51 @@
1
+ What is below is just for future personal reference...
2
+
3
+ http://www.ajaxchat.org/chat/
4
+
5
+
6
+ # Here is my console code to reset threads from their original mails:
7
+ >> elts=Mail.find_all.select{|m|m.file and mail=TMail::Mail.parse(m.file) and reply=mail.in_reply_to and mailObject=Mail.find_by_message(reply) and mailObject.elt.id!=m.elt.parent_id}.collect{|m| {:elt=>m.elt.id, :parent=>Mail.find_by_message(TMail::Mail.parse(m.file).in_reply_to).elt.id}}; puts elts.size
8
+ >> elts.each{|e|print e[:elt], ' ', e[:parent], ' '; puts Elt.update_all("parent_id='#{e[:parent]}'", "id='#{e[:elt]}'")}; puts elts.size
9
+
10
+ # To get and remove duplicate messages
11
+ >> messages=Mail.find_by_sql "select message from mails group by message having count(message) > 1"; puts messages.length
12
+ >> messages.each{ |m| mail=Mail.find_all_by_message m.message; mail.each{|m| print m.elt.id, ' ', m.elt.subject, ' ', m.elt.children.size; puts } }; puts messages.length
13
+ >> messages.each{ |m| mail=Mail.find_all_by_message m.message; mail.each_index{|i| m=mail[i]; print i, ' ', m.elt.id, ' ', m.elt.subject, ' ', m.elt.children.size; m.elt.destroy if i>0 and m.elt.children.size==0; puts } }; puts messages.length
14
+
15
+ # To get all existing votes
16
+ elts=Elt.find(:all, :conditions => ["body LIKE '%%+1%%' OR body LIKE '%%0%%' OR body LIKE '%%-1%%'"]); puts elts.size
17
+ elts.each { |e| print '(', Regexp.last_match(1), ')' if e.body =~ /^\s*(-1|0|\+1)(\s*|$)/ }; puts; puts elts.size
18
+ elts.each { |e| e.vote(Regexp.last_match(1), e.person) if e.body =~ /^\s*(-1|0|\+1)(\s*|$)/ }; puts; puts elts.size
19
+
20
+
21
+ UPDATE elts SET elts_count = (SELECT COUNT(*) FROM elts e2 WHERE e2.parent_id = elts.id);
22
+
23
+ # To reconstruct the nested tree set
24
+ def construction(e, counter)
25
+ e.lft = counter
26
+ counter += 1
27
+ e.children.each { |c|
28
+ counter = construction(c, counter)
29
+ }
30
+ e.rgt = counter
31
+ counter += 1
32
+ e.save
33
+ counter
34
+ end
35
+ e=Elt.find('ROOT')
36
+ construction(e, 0)
37
+
38
+ UPDATE elts SET lft = NULL, rgt = NULL;
39
+ ALTER TABLE elts ADD CONSTRAINT elts_unique_lft UNIQUE (lft);
40
+ ALTER TABLE elts ADD CONSTRAINT elts_unique_rgt UNIQUE (rgt);
41
+
42
+ SELECT * FROM person_mails;
43
+ INSERT INTO person_mails (person_id, mail_id, created_on) VALUES ('first', 'aGaGwUHxCr25c5aaVnmTrI', now());
44
+
45
+ select id from mails;
46
+ select count(*) from mails;
47
+ select * from people;
48
+ select * from subscriptions;
49
+ select * from person_mails;
50
+ \dt
51
+
data/README CHANGED
@@ -5,10 +5,11 @@
5
5
  | .__/ \__,_|_| |_|\___|_| |_| |_|\___|_| |_|\__|
6
6
  |_|
7
7
 
8
- I use debian, here are the commands I use to setup my machine for parlement:
8
+ On debian, here are the commands used to setup the parlement machine:
9
9
  # apt-get install postgresql
10
10
  # sudo su - postgres
11
- # createuser /your_login/
11
+ ~ createuser /your_login/
12
+ ~ exit
12
13
  # apt-get install ruby
13
14
  # apt-get install libpgsql-ruby
14
15
  # apt-get install irb
@@ -22,6 +23,7 @@ You need to install "ruby gems":http://docs.rubygems.org
22
23
  And then:
23
24
  # gem install rails
24
25
  # gem install redcloth
26
+ # gem install term-ansicolor
25
27
 
26
28
  Only if you expect to develop and do any release:
27
29
  # gem install meta_project
@@ -40,54 +42,25 @@ filtering tool), define this kind of rule:
40
42
  * ^TO parlement|leparlement.org
41
43
  | /home/manu/parlement/trunk/script/runner 'Mailman.receive STDIN.read'
42
44
 
43
-
44
45
  Once you have everything set up (ruby, postgresql, redcloth, irb), you can
45
46
  initialise and launch parlement this way:
46
47
 
47
- Go into the right folder
48
- ~ cd parlement/trunk
49
-
50
- Create the db
51
- ~ psql -q template1 -f db/schema.sql
52
-
53
- Populate the db
54
- ~ ruby lib/data_import.rb
55
-
56
- Migrate the db to its last version
57
- ~ rake migrate
58
-
59
- Launch the developement web server
60
- ~ ruby ./script/server
48
+ ~ svn checkout svn://rubyforge.org/var/svn/parlement # Get the code source
49
+ ~ cd parlement/trunk # Go into the right folder
50
+ ~ createdb parlement_development # Create database
51
+ ~ psql -q template1 -f db/schema.sql # Initiate the db schema
52
+ ~ rake migrate # Get the db to its last version
53
+ ~ ruby lib/data_import.rb # Populate the db
54
+ ~ ruby ./script/server # Launch the server
61
55
 
62
56
  Now you can go to http://localhost:3000 with your browser.
63
57
 
64
58
  You can check that everything works all right on your machine with the testing suite:
65
59
  ~ rake
66
60
 
67
-
68
61
  __ __ _
69
62
  \ \ / /__| | ___ ___ _ __ ___ ___
70
63
  \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \
71
64
  \ V V / __/ | (_| (_) | | | | | | __/
72
65
  \_/\_/ \___|_|\___\___/|_| |_| |_|\___|
73
-
74
-
75
-
76
-
77
-
78
- What is below is just for future personal reference...
79
-
80
-
81
- # Here is my console code to reset threads from their original mails:
82
- >> elts=Mail.find_all.select{|m|m.file and mail=TMail::Mail.parse(m.file) and reply=mail.in_reply_to and mailObject=Mail.find_by_message(reply) and mailObject.elt.id!=m.elt.parent_id}.collect{|m| {:elt=>m.elt.id, :parent=>Mail.find_by_message(TMail::Mail.parse(m.file).in_reply_to).elt.id}}; puts elts.size
83
- >> elts.each{|e|print e[:elt], ' ', e[:parent], ' '; puts Elt.update_all("parent_id='#{e[:parent]}'", "id='#{e[:elt]}'")}; puts elts.size
84
-
85
- # To get and remove duplicate messages
86
- >> messages=Mail.find_by_sql "select message from mails group by message having count(message) > 1"; puts messages.length
87
- >> messages.each{ |m| mail=Mail.find_all_by_message m.message; mail.each{|m| print m.elt.id, ' ', m.elt.subject, ' ', m.elt.children.size; puts } }; puts messages.length
88
- >> messages.each{ |m| mail=Mail.find_all_by_message m.message; mail.each_index{|i| m=mail[i]; print i, ' ', m.elt.id, ' ', m.elt.subject, ' ', m.elt.children.size; m.elt.destroy if i>0 and m.elt.children.size==0; puts } }; puts messages.length
89
66
 
90
- # To get all existing votes
91
- elts=Elt.find(:all, :conditions => ["body LIKE '%%+1%%' OR body LIKE '%%0%%' OR body LIKE '%%-1%%'"]); puts elts.size
92
- elts.each { |e| print '(', Regexp.last_match(1), ')' if e.body =~ /^\s*(-1|0|\+1)(\s*|$)/ }; puts; puts elts.size
93
- elts.each { |e| e.vote(Regexp.last_match(1), e.person) if e.body =~ /^\s*(-1|0|\+1)(\s*|$)/ }; puts; puts elts.size
data/Rakefile CHANGED
@@ -56,7 +56,7 @@ spec = Gem::Specification.new do |s|
56
56
  EOF
57
57
  s.files = PKG_FILES
58
58
  s.require_path = 'lib'
59
- s.autorequire = 'rails redcloth'
59
+ s.autorequire = 'rails redcloth term-ansicolor'
60
60
  s.has_rdoc = false
61
61
  s.requirements << 'none'
62
62
  s.test_files = Dir.glob('test/unit/*')
@@ -72,7 +72,7 @@ EOF
72
72
  #s.signing_key = File.join(ENV['CERT_DIR'], 'gem-private_key.pem')
73
73
  #s.cert_chain = [File.join(ENV['CERT_DIR'], 'gem-public_cert.pem')]
74
74
  #end
75
- s.add_dependency('rails')
75
+ s.add_dependency('rails redcloth term-ansicolor')
76
76
  end
77
77
 
78
78
  desc "Build Gem"
@@ -1,4 +1,4 @@
1
- #
1
+ #
2
2
  # This class manages users inscription, login and logout
3
3
  #
4
4
  class AccountController < UserController
@@ -25,7 +25,7 @@ class AccountController < UserController
25
25
  Person.transaction(@person) do
26
26
  @person = Person.new :id => login.gsub(/\s/, '_'), :name => login
27
27
  if @person.save
28
- logger.info "person.id: #{@person.id}, name: #{@person.name}"
28
+ logger.info yellow { bold { "Person: #{@person.name}, id: #{@person.id}" } }
29
29
  flash.now[:notice] = "Pseudo created"
30
30
  session[:person] = @person
31
31
  else
@@ -34,12 +34,12 @@ class AccountController < UserController
34
34
  end
35
35
  rescue Exception => e
36
36
  flash.now[:error] = 'Error creating account'
37
- logger.error e
37
+ logger.error red { e }
38
38
  end
39
39
  end
40
40
 
41
+ # We record the password or try to authenticate
41
42
  if @person and @person.errors.empty?
42
- # Second we record the password or try to authenticate
43
43
  if password.empty?
44
44
  if not @user or not @user.salted_password \
45
45
  or @user.salted_password.empty?
@@ -48,42 +48,28 @@ class AccountController < UserController
48
48
  flash.now[:error] = "This pseudo is protected with a password"
49
49
  end
50
50
  elsif not @user
51
- @user = User.new()
52
- begin
53
- User.transaction(@user) do
54
- @user.login = login
55
- @user.change_password(password)
56
- # To make sure even a non email protected user can use a password
57
- @user.email = login+'@nomailyet'
58
- # This is a hack, to make sure this user can login even if he
59
- # didn't verify his email
60
- @user.verified = true
61
- if @user.save
62
- flash['notice 2'] = 'Password recorded'
63
-
64
- session[:person] = @person
65
- session[:user] = @user
66
- end
67
- end
68
- rescue
69
- flash.now[:error] = 'Error with password'
70
- end
71
-
51
+ # Record password
52
+ session[:person] = @person
53
+ mngPassword
72
54
  elsif User.authenticate(login, password)
73
- # There is a password protecting this pseudo
55
+ logger.info yellow { bold { "#{@person.name} logged in" } }
56
+ # Authenticate
74
57
  session[:person] = @person
75
58
  session[:user] = @user
76
-
77
- elsif not email.empty?
59
+ elsif email and not email.empty?
60
+ # There is a check key, used to change the password
78
61
  begin
79
62
  User.transaction(@user) do
80
63
  if User.authenticate_by_token(@user.id, email)
81
64
  @user.change_password(password)
82
65
  @user.security_token = nil
83
66
  if @user.save
67
+ logger.info yellow { "Person: #{@person.name} changed its password" }
84
68
  flash.now['notice 2'] = 'Password successfully modified!'
85
69
  session[:person] = @person
86
70
  session[:user] = @user
71
+ else
72
+ @user.errors.each_full { |msg| logger.error msg }
87
73
  end
88
74
  end
89
75
  end
@@ -94,45 +80,50 @@ class AccountController < UserController
94
80
  flash.now[:error] = "Wrong password"
95
81
  end
96
82
 
97
- # Third we record the email or send a check_key for a password reset
98
- if not email.empty?
83
+ # Record the email or send a check_key for a password reset
84
+ if email and not email.empty?
99
85
  if session[:person]
100
86
  if email == @person.email
101
87
  flash.now['notice 3'] = "Email already recorded and verified"
102
88
  else
103
- signup
89
+ mngEmail
104
90
  end
105
-
106
91
  elsif email == @person.email
107
92
  # User protected by password and with the same email as entered
108
93
  key = @user.generate_security_token
109
94
  url = url_for(:action => 'check_key')
110
95
  url += "?user[id]=#{@user.id}&key=#{key}"
111
96
  UserNotify::deliver_forgot_password(@user, url)
112
- flash.now['notice 3'] = "Email with a check key sent to "+email
97
+ flash.now['notice 3'] = "Email with a check key sent to #{email}"
113
98
  end
114
99
  end
115
100
  end
116
101
 
117
102
  # Record cookies for re authentication
118
103
  if session[:person]
119
- cookies[:person_name] = session[:person].name
120
- cookies[:salted_password] = @user.salted_password if @user
104
+ cookies[:person_name] = { :value => session[:person].name, :expires => 3.years.from_now }
105
+ cookies[:salted_password] = { :value => @user.salted_password, :expires => 3.years.from_now } if @user
121
106
  end
122
107
 
108
+ # To make sure the logout knows which elt's choices to update
109
+ @elt = Elt.find(params[:elt]) if params[:elt]
110
+
123
111
  render :partial => 'show',
124
- :locals => { :divId => params[:divId], :choices => getAllVotes },
112
+ :locals => { :choices => getAllVotes },
125
113
  :status => (session[:person] ? 200 : 403)
126
114
  end
127
115
 
128
116
  def logout
117
+ logger.info yellow { bold { "Bye bye" } }
129
118
  # Cleaning up
130
119
  session[:person] = @person = session[:user] = @user = nil
131
120
  cookies.delete :person_name
132
121
  cookies.delete :salted_password
133
122
 
134
- render :partial => 'show', :locals => {
135
- :divId => params[:divId], :choices => getAllVotes }
123
+ # To make sure the logout knows which elt's choices to update
124
+ @elt = Elt.find(params[:elt]) if params[:elt]
125
+
126
+ render :partial => 'show', :locals => { :choices => getAllVotes }
136
127
  end
137
128
 
138
129
  def check_key
@@ -158,10 +149,26 @@ class AccountController < UserController
158
149
  end
159
150
  end
160
151
 
152
+ def setPassword
153
+ logger.info yellow { "Person #{session[:person].name} sets/changes his password" } if session[:person]
154
+ @person = session[:person]
155
+ @user = session[:user]
156
+ mngPassword
157
+ render :partial => 'show'
158
+ end
159
+
160
+ def setEmail
161
+ logger.info yellow { "Person #{session[:person].name} set his email to #{params[:person][:email]}" } if session[:person]
162
+ @person = session[:person]
163
+ @user = session[:user]
164
+ mngEmail
165
+ render :partial => 'show'
166
+ end
167
+
161
168
  def setAvatar
162
169
  return render(:text => "Not logged in", :status => 403) \
163
170
  unless session[:person]
164
- logger.info "Setting up an avatar for person #{session[:person].name}"
171
+ logger.info yellow { "Setting up an avatar for person #{session[:person].name}" }
165
172
 
166
173
  @elt = Elt.find_by_id 'people'
167
174
  if !@elt
@@ -192,8 +199,34 @@ class AccountController < UserController
192
199
 
193
200
  protected
194
201
 
202
+ def mngPassword
203
+ if @person and password = @params[:user][:password] and !password.empty?
204
+ @user = @person.user || User.new()
205
+ begin
206
+ User.transaction(@user) do
207
+ @user.login = @person.name
208
+ # To make sure even a non email protected user can use a password
209
+ @user.email ||= @person.name+'@nomailyet'
210
+ # This is a hack, to make sure this user can login even if he
211
+ # didn't verify his email
212
+ @user.verified = true
213
+ @user.change_password(password)
214
+ if @user.save
215
+ logger.info yellow { "Password changed" }
216
+ flash['notice 2'] = 'Password recorded'
217
+ session[:user] = @user
218
+ else
219
+ @user.errors.each_full { |msg| logger.error msg }
220
+ end
221
+ end
222
+ rescue
223
+ flash.now[:error] = 'Error with password'
224
+ end
225
+ end
226
+ end
227
+
195
228
  # Mostly copied from the login engine
196
- def signup
229
+ def mngEmail
197
230
  if @person and not @user
198
231
  @user = User.new
199
232
  @user.login = @person.name
@@ -207,31 +240,31 @@ class AccountController < UserController
207
240
  end
208
241
  if @user.save
209
242
  key = @user.generate_security_token
210
- #url = url_for(:action => 'home', 'user[id]' => @user.id, :key => key)
211
- url = url_for(:action => 'check_key')
212
- url += "?user[id]=#{@user.id}&key=#{key}"
243
+ url = url_for(:action => 'check_key', 'user[id]' => @user.id, :key => key)
244
+ #url = url_for(:action => 'check_key')
245
+ #url += "?user[id]=#{@user.id}&key=#{key}"
213
246
  #flash[:notice] = 'Signup successful!'
214
- flash.now['notice 3'] = 'Confirmation email sent to '+@user.email
215
247
  if LoginEngine.config(:use_email_notification)
216
- UserNotify.deliver_signup(@user, params[:user][:password], url)
217
- flash['notice 4'] = ' Please check your registered email account to verify your account registration.'
248
+ PersonNotify.deliver_setEmail(@person, url)
249
+ flash.now['notice 3'] = "Confirmation email sent to #{@user.email}"
218
250
  end
219
251
  #redirect_to :action => 'login'
220
252
  end
221
253
  end
222
254
  rescue Exception => e
223
255
  flash.now[:notice] = nil
256
+ flash.now['notice 2'] = nil
257
+ flash.now['notice 3'] = nil
224
258
  flash.now[:warning] = 'Error creating account: confirmation email not sent'
225
- logger.error e
259
+ e.backtrace.each { |m| logger.error m }
226
260
  end
227
261
  end
228
262
 
229
263
  def getAllVotes
230
- return if !params[:divId]
231
- elt = Elt.find params[:divId].gsub(/author_/, '')
264
+ return unless @elt
232
265
  Choice.find_all_by_person_id((session[:person] ? session[:person].id : nil),
233
266
  :include => 'elt',
234
- :conditions => "elts.lft >= '#{elt.lft}' AND elts.rgt <= '#{elt.rgt}'")
267
+ :conditions => "elts.lft >= '#{@elt.lft}' AND elts.rgt <= '#{@elt.rgt}'")
235
268
  end
236
269
  end
237
270
 
@@ -2,9 +2,11 @@
2
2
  # Likewese will all the methods added be available for all controllers.
3
3
 
4
4
  require 'login_engine'
5
+ require 'term/ansicolor'
5
6
 
6
7
  class ApplicationController < ActionController::Base
7
8
  include LoginEngine
9
+ include Term::ANSIColor
8
10
  model :user
9
11
 
10
12
  before_filter :set_charset
@@ -32,6 +34,7 @@ class ApplicationController < ActionController::Base
32
34
  ((!person.user and !cookies[:salted_password]) \
33
35
  or (person.user \
34
36
  and person.user.salted_password == cookies[:salted_password]))
37
+ logger.info yellow { bold { "#{person.name} is back" } }
35
38
  session[:person] = person
36
39
  session[:user] = person.user
37
40
  end
@@ -66,10 +66,13 @@ class EltController < ApplicationController
66
66
  @elt = Elt.new(params[:elt])
67
67
  @elt.person = @session[:person]
68
68
 
69
- if @elt.subject.match(/([<>\/]|href)/) then
70
- logger.error "SPAM! '#{@elt.subject}'"
69
+ if @elt.subject =~ /([<>\/]|href)/ \
70
+ or @elt.body =~ /(.*([<>\/]|href).*){3}/ \
71
+ or @elt.body =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i \
72
+ or @elt.body =~ /([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,}.*){3}/i
73
+ logger.error red { underline { "SPAM! '#{@elt.subject}'" } }
71
74
  logger.error "SPAM! '#{@elt.body}'"
72
- flash[:error] = 'Sorry, to fight spam "<" ">" or "href" are forbidden in the subject!'
75
+ flash[:error] = 'Sorry, to fight spam "<" ">" or "href" are forbidden in the subject, and there can not be more than 3 links in the body, you also can\'t input one simple email or more than 3 emails!'
73
76
  headers["Status"] = "404 Post considered as spam"
74
77
  render :controller => 'elt', :action => 'new', :status => 404
75
78
  elsif params[:submit] == "preview" or (@elt.publish and @elt.parent.add_child(@elt)) then
@@ -89,6 +92,14 @@ class EltController < ApplicationController
89
92
 
90
93
  def vote
91
94
  @elt = Elt.find params[:id]
95
+ unless params[:choice][:value] =~ /^\s*(-1|0|\+1)(\s|$)/ then
96
+ logger.error red { underline { "SPAM! through the vote" } }
97
+ logger.error params[:choice][:value]
98
+ flash[:error] = 'Sorry, you can only vote here!'
99
+ render :partial => '/elt/choice', :locals => { :elt => @elt }
100
+ return
101
+ end
102
+
92
103
  vote = @elt.children.build
93
104
  vote.person = session[:person]
94
105
  vote.subject = @elt.subject
@@ -1,21 +1,37 @@
1
+ #
2
+ # Mailing list management
3
+ #
4
+ # This is to add or remove subscribers
5
+ #
1
6
  class SubscriberController < ApplicationController
2
-
3
7
  def subscribe
4
- @elt = Elt.find(params[:id])
8
+ @elt = Elt.find params[:id]
5
9
 
6
10
  if @session[:person]
7
11
  if @elt.subscribers.include?(@session[:person])
8
- @elt.subscribers.delete(@session[:person])
9
- logger.info "Unsubscribed #{@session[:person].name} from #{@elt.subject}..."
10
- render :inline => "Unsubscribed..."
12
+ Subscription.find_by_person_id_and_elt_id(@session[:person].id, @elt.id).destroy
13
+ logger.info yellow { "User #{@session[:person].name} unsubscribed from #{@elt.subject}..." }
14
+ elsif @elt.all_recipients.include?(@session[:person])
15
+ elt2 = @elt
16
+ elt2 = elt2.parent until elt2.subscribers.include?(@session[:person])
17
+ Subscription.find_by_person_id_and_elt_id(@session[:person].id, elt2.id).destroy
18
+ logger.info yellow { "User #{@session[:person].name} unsubscribed from #{elt2.subject}..." }
11
19
  else
12
- @elt.subscribers << @session[:person]
13
- logger.info "Subscribed #{@session[:person].name} to #{@elt.subject}..."
14
- render :inline => "Subscribed..."
20
+ if cookies[:filter]
21
+ filter = cookies[:filter].to_i - 1
22
+ filter = nil unless filter >= 0
23
+ else
24
+ filter = 0
25
+ end
26
+ @elt.subscriptions.create :person => @session[:person], :filter => filter
27
+ logger.info yellow { "User #{@session[:person].name} subscribed to #{@elt.id} with filter #{filter}..." }
15
28
  end
16
29
  else
17
30
  puts "Not logged in!"
18
- render :inline => "First you need to login... it's easy, type a pseudo with at least 3 characters. Then ok. Then subscribe"
31
+ #render :inline => "First you need to login... it's easy, type a pseudo with at least 3 characters. Then OK"
32
+ flash.now[:error] = 'First you need to login!'
19
33
  end
34
+ render :partial => 'list'
20
35
  end
21
36
  end
37
+
@@ -66,7 +66,7 @@ module EltHelper
66
66
  and elt.subject != elt.parent.subject \
67
67
  and elt.parent.subject \
68
68
  and elt.subject.downcase != elt.parent.subject.downcase \
69
- and not elt.subject.sub(/(Re|r�f|re|sv|aw):\s*/, '') == elt.parent.subject
69
+ and not elt.subject.sub(/(Re|RE|r�f|re|sv|aw):\s*/, '') == elt.parent.subject
70
70
  end
71
71
  end
72
72
 
data/app/models/elt.rb CHANGED
@@ -16,12 +16,14 @@
16
16
  # normal characters are used)
17
17
  #
18
18
  class Elt < ActiveRecord::Base
19
- has_one :mail, :dependent => true
20
19
  belongs_to :person
20
+ has_one :mail, :dependent => :destroy
21
+
22
+ has_many :choices, :dependent => :destroy, :order => "choices.created_on"
21
23
  has_many :voters, :through => :choices, :source => :person
22
- has_many :choices, :dependent => true, :order => "choices.created_on"
23
- has_many :attachments, :dependent => true
24
- has_and_belongs_to_many :subscribers, :class_name => "Person", :join_table => "subscribers"
24
+ has_many :attachments, :dependent => :destroy
25
+ has_many :subscriptions, :dependent => :destroy
26
+ has_many :subscribers, :through => :subscriptions, :source => :person
25
27
 
26
28
  acts_as_nested_set :order => "position is not null, position, created_on"
27
29
  acts_as_tree :order => "position is not null, position, created_on", :counter_cache => true
@@ -35,11 +37,20 @@ class Elt < ActiveRecord::Base
35
37
  end
36
38
  end
37
39
 
40
+ def all_subscriptions
41
+ if parent
42
+ (subscriptions + parent.all_subscriptions).uniq
43
+ else
44
+ subscriptions
45
+ end
46
+ end
47
+
38
48
  def vote(value = 1, person = self.person)
39
49
  logger.info "#{person.name if person} vote #{value} on #{subject} #{self.choices}"
40
50
  choices.each{ |c| c.destroy if c.person == person }
41
51
  choice = choices.build :value => value, :person => person
42
52
  choice.save!
53
+ mail.publish if mail
43
54
  end
44
55
 
45
56
  # Get the vote results
@@ -54,10 +65,10 @@ class Elt < ActiveRecord::Base
54
65
  def publish
55
66
  logger.info "Publish #{subject}"
56
67
 
68
+ self.position = Regexp.last_match(1) if body =~ /^\s*position:\s*(\d+(\.\d+)?)(\s|$)/
69
+
57
70
  build_mail(:elt => self) unless mail
58
71
  mail.publish
59
-
60
- self.position = Regexp.last_match(1) if body =~ /^\s*position:\s*(\d+(\.\d+)?)(\s|$)/
61
72
  save!
62
73
 
63
74
  parent.vote Regexp.last_match(1), person if body =~ /^\s*(-1|0|\+1)(\s|$)/
@@ -73,15 +84,14 @@ class Elt < ActiveRecord::Base
73
84
  def save
74
85
  if new_record?
75
86
  # Let's generate a nice looking id
76
- self.id = new_id = subject.gsub(/\[[\w-]*\]/, '').strip \
77
- .gsub(/\s/, '_').gsub(/[^\w]+/, '').gsub(/_+/, '_') \
78
- .gsub(/(^_|_$)/, '') \
79
- if subject
87
+ self.id = new_id =
88
+ subject.gsub(/\[[\w-]*\]/, '').strip \
89
+ .gsub(/\s/, '_').gsub(/[^\w]+/, '') \
90
+ .gsub(/_+/, '_').gsub(/(^_|_$)/, '') if subject
80
91
  self.id ||= "elt"
81
92
 
82
- discrim = 0
83
- self.id = "#{new_id}_#{discrim}" \
84
- while discrim += 1 and self.class.find_by_id self.id
93
+ i = 0
94
+ self.id = "#{new_id}_#{i+=1}" while self.class.find_by_id self.id
85
95
  end
86
96
 
87
97
  super