parlement 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGES +26 -0
  2. data/README +2 -1
  3. data/app/controllers/account_controller.rb +27 -18
  4. data/app/controllers/application.rb +1 -3
  5. data/app/controllers/elt_controller.rb +92 -42
  6. data/app/helpers/elt_helper.rb +7 -18
  7. data/app/models/elt.rb +76 -22
  8. data/app/models/mail.rb +13 -10
  9. data/app/models/mail_notify.rb +11 -27
  10. data/app/models/person.rb +1 -1
  11. data/app/views/account/_login.rhtml +14 -9
  12. data/app/views/account/_show.rhtml +23 -9
  13. data/app/views/elt/_choice.rhtml +32 -0
  14. data/app/views/elt/_elt.rhtml +90 -78
  15. data/app/views/elt/_list.rhtml +83 -50
  16. data/app/views/elt/_listByDate.rhtml +60 -0
  17. data/app/views/elt/_listByVote.rhtml +71 -0
  18. data/app/views/elt/choices.rhtml +29 -0
  19. data/app/views/elt/new.rhtml +11 -26
  20. data/app/views/elt/rss.rxml +14 -12
  21. data/app/views/elt/show.rhtml +23 -29
  22. data/app/views/elt/vote_rss.rxml +40 -0
  23. data/app/views/layouts/top.rhtml +5 -13
  24. data/config/environment.rb +3 -1
  25. data/config/routes.rb +4 -0
  26. data/db/development_structure.sql +5 -2
  27. data/db/migrate/002_nested_set.rb +22 -0
  28. data/db/migrate/003_elt_children_count.rb +12 -0
  29. data/public/images/ParlementLogo.png +0 -0
  30. data/public/images/indicator.gif +0 -0
  31. data/public/javascripts/behaviour.js +254 -0
  32. data/public/javascripts/mybehaviour.js +96 -0
  33. data/public/javascripts/slider.js +188 -163
  34. data/test/fixtures/elts.yml +19 -0
  35. data/test/fixtures/mail/mail_ruby +4 -0
  36. data/test/fixtures/mail/mail_rubyChild +1 -1
  37. data/test/fixtures/mail/mail_rubyChild2 +1 -1
  38. data/test/functional/account_controller_test.rb +24 -0
  39. data/test/functional/elt_controller_test.rb +64 -4
  40. data/test/unit/elt_test.rb +28 -4
  41. data/test/unit/mail_notify_test.rb +7 -5
  42. data/test/unit/mail_test.rb +1 -1
  43. data/vendor/plugins/google_analytics/README +19 -0
  44. data/vendor/plugins/google_analytics/Rakefile +22 -0
  45. data/vendor/plugins/google_analytics/init.rb +3 -0
  46. data/vendor/plugins/google_analytics/lib/rubaidh/google_analytics.rb +70 -0
  47. data/vendor/plugins/google_analytics/test/google_analytics_test.rb +8 -0
  48. data/vendor/plugins/output_compression/README +4 -0
  49. data/vendor/plugins/output_compression/Rakefile +22 -0
  50. data/vendor/plugins/output_compression/init.rb +2 -0
  51. data/vendor/plugins/output_compression/lib/output_compression.rb +66 -0
  52. data/vendor/plugins/output_compression/tasks/output_compression_tasks.rake +4 -0
  53. data/vendor/plugins/output_compression/test/output_compression_test.rb +8 -0
  54. metadata +32 -4
  55. data/public/images/smile.svg +0 -257
  56. data/public/javascripts/borders.js +0 -687
data/CHANGES CHANGED
@@ -1,5 +1,31 @@
1
1
  - parlement changelog
2
2
 
3
+ == Version 0.6
4
+
5
+ Voting using V and Λ buttons (picturing -1 and +1 values, down and up).
6
+ Clicking on an existing vote resets it (equivalent to a 0 vote).
7
+
8
+ Votes recorded and replicated as mails. Elements also listed by their approval
9
+ (rss feed available).
10
+
11
+ * elements are now acts_as_nested_set AND acts_as_tree
12
+ * list by date, dynamic and managing all sub elements
13
+ * rss now manages _all_ sub elements
14
+ * compress_output
15
+ * google analytics plugin
16
+ * visual_effect queues
17
+ * close or open elements and their sub elements
18
+ * optimisations
19
+ * voting on the web page
20
+ * logging in and out changes appropriately +1 and -1 votes
21
+ * element id now generated from element subject
22
+ * element body now cached
23
+ * some spam tests when creating a new element
24
+ * list by vote
25
+ * possibility to see individual votes when clicking on a vote result
26
+ * Correcting a painful "null character" mishandling when mail is quoted printable
27
+
28
+
3
29
  == Version 0.5
4
30
 
5
31
  Voting. Mails containing -1, 0 or +1 trigger a vote
data/README CHANGED
@@ -69,9 +69,10 @@ Parameters
69
69
  >> 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
70
70
  >> elts.each{|e|print e[:elt], ' ', e[:parent], ' '; puts Elt.update_all("parent_id='#{e[:parent]}'", "id='#{e[:elt]}'")}; puts elts.size
71
71
 
72
- # To get duplicate messages
72
+ # To get and remove duplicate messages
73
73
  >> messages=Mail.find_by_sql "select message from mails group by message having count(message) > 1"; puts messages.length
74
74
  >> 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
75
+ >> 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
75
76
 
76
77
  # To get all existing votes
77
78
  elts=Elt.find(:all, :conditions => ["body LIKE '%%+1%%' OR body LIKE '%%0%%' OR body LIKE '%%-1%%'"]); puts elts.size
@@ -7,7 +7,7 @@ class AccountController < UserController
7
7
 
8
8
  def login
9
9
  # Cleaning up
10
- @session[:person] = @session[:user] = nil
10
+ session[:person] = session[:user] = nil
11
11
 
12
12
  login = @params[:person][:name]
13
13
  email = @params[:person][:email]
@@ -27,7 +27,7 @@ class AccountController < UserController
27
27
  logger.info "person: "+@person.to_s
28
28
  logger.info "person.id: "+@person.id.to_s
29
29
  flash.now[:notice] = "Pseudo created"
30
- @session[:person] = @person
30
+ session[:person] = @person
31
31
  else
32
32
  flash.now[:error] = 'Error creating account'
33
33
  end
@@ -38,12 +38,12 @@ class AccountController < UserController
38
38
  end
39
39
  end
40
40
 
41
- # Second we record the password or try to authenticate
42
41
  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?
46
- @session[:person] = @person
46
+ session[:person] = @person
47
47
  else
48
48
  flash.now[:error] = "This pseudo is protected with a password"
49
49
  end
@@ -61,8 +61,8 @@ class AccountController < UserController
61
61
  if @user.save
62
62
  flash['notice 2'] = 'Password recorded'
63
63
 
64
- @session[:person] = @person
65
- @session[:user] = @user
64
+ session[:person] = @person
65
+ session[:user] = @user
66
66
  end
67
67
  end
68
68
  rescue
@@ -71,8 +71,8 @@ class AccountController < UserController
71
71
 
72
72
  elsif User.authenticate(login, password)
73
73
  # There is a password protecting this pseudo
74
- @session[:person] = @person
75
- @session[:user] = @user
74
+ session[:person] = @person
75
+ session[:user] = @user
76
76
 
77
77
  elsif not email.empty?
78
78
  begin
@@ -82,8 +82,8 @@ class AccountController < UserController
82
82
  @user.security_token = nil
83
83
  if @user.save
84
84
  flash.now['notice 2'] = 'Password successfully modified!'
85
- @session[:person] = @person
86
- @session[:user] = @user
85
+ session[:person] = @person
86
+ session[:user] = @user
87
87
  end
88
88
  end
89
89
  end
@@ -96,7 +96,7 @@ class AccountController < UserController
96
96
 
97
97
  # Third we record the email or send a check_key for a password reset
98
98
  if not email.empty?
99
- if @session[:person]
99
+ if session[:person]
100
100
  if email == @person.email
101
101
  flash.now['notice 3'] = "Email already recorded and verified"
102
102
  else
@@ -114,15 +114,16 @@ class AccountController < UserController
114
114
  end
115
115
  end
116
116
 
117
- render :partial => 'show', :locals => { :divId => params[:divId] }
118
- #render :partial => 'show', :locals => { :divId => 'test' }
117
+ render :partial => 'show', :locals => {
118
+ :divId => params[:divId], :choices => getAllVotes }
119
119
  end
120
120
 
121
121
 
122
122
  def logout
123
- @session[:person] = @person = nil
124
- @session[:user] = @user = nil
125
- render :partial => 'login', :locals => { :divId => params[:divId] }
123
+ session[:person] = @person = nil
124
+ session[:user] = @user = nil
125
+ render :partial => 'show', :locals => {
126
+ :divId => params[:divId], :choices => getAllVotes }
126
127
  end
127
128
 
128
129
  def check_key
@@ -132,8 +133,8 @@ class AccountController < UserController
132
133
  @person.email = @user.email
133
134
  @person.save
134
135
  flash.now[:notice] = "Email #{@person.email} verified."
135
- @session[:person] = @person
136
- @session[:user] = @user
136
+ session[:person] = @person
137
+ session[:user] = @user
137
138
  render :text => "<h1>Email verified!</h1> \
138
139
  <br/> \
139
140
  <a href='#{url_for :controller => 'elt', :action => 'show', :id => nil }'>\
@@ -183,5 +184,13 @@ class AccountController < UserController
183
184
  logger.error e
184
185
  end
185
186
  end
187
+
188
+ def getAllVotes
189
+ return if !params[:divId]
190
+ elt = Elt.find params[:divId].gsub(/author_/, '')
191
+ Choice.find_all_by_person_id((session[:person] ? session[:person].id : nil),
192
+ :include => 'elt',
193
+ :conditions => "elts.lft >= '#{elt.lft}' AND elts.rgt <= '#{elt.rgt}'")
194
+ end
186
195
  end
187
196
 
@@ -9,9 +9,7 @@ class ApplicationController < ActionController::Base
9
9
 
10
10
  before_filter :set_charset
11
11
  after_filter :fix_unicode_for_safari
12
-
13
- include LiveTree
14
- helper LiveTreeHelper
12
+ after_filter :compress_output
15
13
 
16
14
  # automatically and transparently fixes utf-8 bug
17
15
  # with Safari when using xmlhttp
@@ -4,73 +4,123 @@
4
4
  # An element is just the name for a poll/message/issue
5
5
  #
6
6
  class EltController < ApplicationController
7
- def index
7
+
8
+ def index
8
9
  params[:id] = params[:id].gsub(/.html/, '')
9
- show
10
- end
10
+ show
11
+ end
11
12
 
12
- def show
13
+ def show
13
14
  params[:id] = params[:id].gsub(/.html/, '')
14
- @elt = Elt.find(params[:id])
15
- @title = @elt.subject+' (parlement)'
15
+ @elt = Elt.find(params[:id])
16
+ @title = @elt.subject
17
+ @title += " (parlement)" if !@title.downcase.include? "parlement"
18
+ if request.env['REQUEST_URI'].match '.dyndns'
19
+ headers["Status"] = "301 Moved Permanently"
20
+ redirect_to request.env['REQUEST_URI'].gsub(/.dyndns/, '')
21
+ end
16
22
  render :layout => 'top'
17
23
 
18
24
  # TODO
19
- rescue ActiveRecord::RecordNotFound => e
20
- flash[:error] = "Element '#{params[:id]}' does not exist"
21
- headers["Status"] = "301 Moved Permanently"
22
- redirect_to '/'
23
- end
25
+ rescue ActiveRecord::RecordNotFound => e
26
+ flash[:error] = "Element '#{params[:id]}' does not exist"
27
+ headers["Status"] = "301 Moved Permanently"
28
+ redirect_to '/'
29
+ end
24
30
 
25
- def list
26
- @elt = Elt.find(params[:id]) if @elt == nil
31
+ def list
32
+ @elt = Elt.find(params[:id]) if @elt == nil
27
33
  render :partial => '/elt/list', :locals => { :elt => @elt }
28
- end
34
+ end
35
+
36
+ def listByDate
37
+ @elt = Elt.find params[:id] unless @elt
38
+ render :partial => 'listByDate'
39
+ end
40
+
41
+ def listByVote
42
+ @elt = Elt.find params[:id] unless @elt
43
+ render :partial => 'listByVote'
44
+ end
29
45
 
30
- def rss
46
+ def rss
31
47
  params[:id] = params[:id].gsub(/.rss/, '')
32
48
  @headers["Content-Type"] = "text/xml; charset=utf-8"
33
- @elt = Elt.find(params[:id]) if @elt == nil
34
- end
49
+ @elt = Elt.find(params[:id]) if @elt == nil
50
+ end
51
+
52
+ def vote_rss
53
+ params[:id] = params[:id].gsub(/.rss/, '')
54
+ @headers["Content-Type"] = "text/xml; charset=utf-8"
55
+ @elt = Elt.find(params[:id]) if @elt == nil
56
+ end
35
57
 
36
58
  # Used to initialise the elt, its subject mainly
37
- def new
38
- @elt = Elt.new
59
+ def new
60
+ @elt = Elt.new
39
61
  @elt.parent = Elt.find(params[:id])
40
- @elt.position = 0
41
- @elt.person = Person.find_by_name(cookies[:person])
42
- @elt.build_person if @elt.person == nil
43
-
44
- @person = @elt.person
45
62
 
46
63
  if @elt.parent.subject.include? 'Re: '
47
64
  @elt.subject = @elt.parent.subject
48
65
  else
49
66
  @elt.subject = 'Re: '+@elt.parent.subject
50
67
  end
51
- end
68
+ end
52
69
 
53
- def preview
70
+ def preview
54
71
  render :inline => h(format(params[:elt][:body]))
55
- end
56
-
57
- def create
58
- @elt = Elt.new(params[:elt])
72
+ end
59
73
 
74
+ def create
75
+ @elt = Elt.new(params[:elt])
60
76
  @elt.person = @session[:person]
61
77
 
62
- if params[:submit] == 'preview' or @elt.save
63
- render :partial => '/elt/elt', :locals => { :elt => @elt, :eltTop => false }
64
- else
65
- flash[:notice] = 'Error'
66
- render :controller => 'elt', :action => 'new'
67
- end
68
- end
69
-
70
- def raw_elt
71
- @mail = Elt.find(params[:id]).mail
72
- #@elt = TMail::Mail.parse(Elt.find(params[:id]).mail.id)
78
+ if @elt.subject.match(/([<>\/]|href)/) then
79
+ logger.error "SPAM! '#{@elt.subject}'"
80
+ logger.error "SPAM! '#{@elt.body}'"
81
+ flash[:error] = 'Sorry, to fight spam "<" ">" or "href" are forbidden in the subject!'
82
+ headers["Status"] = "404 Post considered as spam"
83
+ render :controller => 'elt', :action => 'new', :status => 404
84
+ elsif params[:submit] == "preview" or (@elt.publish and @elt.parent.add_child(@elt)) then
85
+ headers["Status"] = "201 Created"
86
+ render :partial => '/elt/elt', :status => 201, :locals => { :elt => @elt, :eltTop => false }
87
+ else
88
+ flash[:notice] = 'Error'
89
+ render :controller => 'elt', :action => 'new'
90
+ end
91
+ end
92
+
93
+ def raw_elt
94
+ @mail = Elt.find(params[:id]).mail
95
+ #@elt = TMail::Mail.parse(Elt.find(params[:id]).mail.id)
73
96
  render :inline => "<pre><%= @mail.file %></pre>", :layout => 'top'
74
- end
97
+ end
98
+
99
+ def vote
100
+ @elt = Elt.find params[:id]
101
+ vote = @elt.children.build
102
+ vote.person = session[:person]
103
+ vote.subject = @elt.subject
104
+ vote.subject = 'Re: '+vote.subject if vote.subject and !vote.subject.include? 'Re: '
105
+ vote.body = params[:choice][:value]
106
+
107
+ choice = Choice.find_by_elt_id_and_person_id @elt.id, (session[:person] ? session[:person].id : nil)
108
+
109
+ if choice and choice.value == vote.body.to_i then
110
+ logger.info "#{(session[:person] ? session[:person].name : 'null')} voting 0"
111
+ vote.body = "0"
112
+ else
113
+ logger.info "#{(session[:person] ? session[:person].name : 'null')} voting #{params[:choice][:value]}"
114
+ end
115
+
116
+ vote.publish
117
+ @elt.add_child vote
118
+
119
+ render :partial => '/elt/choice', :locals => { :elt => @elt }
120
+ end
121
+
122
+ def choices
123
+ @elt = Elt.find params[:id]
124
+ end
75
125
  end
76
126
 
@@ -9,6 +9,7 @@ module EltHelper
9
9
  # /italic/
10
10
  # - listElement
11
11
  # 1. numbered list
12
+ # chat log lines become list elements
12
13
  # short lines to which are added a break
13
14
  text = auto_link data \
14
15
  .gsub(/^\b(.*:)$(\n)^>\s/, '\\1<br/>\\2\\2> ') \
@@ -17,9 +18,11 @@ module EltHelper
17
18
  .gsub(/(\s+)\/([\w\s]*)\//, '\\1_\\2_') \
18
19
  .gsub(/^-\s/, '* ') \
19
20
  .gsub(/^\d+[\.-]\s+/, '# ') \
21
+ .gsub(/^(\d\d:\d\d\s)/, '* \\1') \
20
22
  .gsub(/^\b(.{2,50})$(\n)\b/, '\\1<br/>\\2') \
21
23
  if data != nil
22
24
 
25
+ #hard_breaks = true
23
26
  textiled = text.blank? ? "" : RedCloth.new(text)
24
27
  begin
25
28
  textiled = textiled.to_html if !textiled.blank?
@@ -28,28 +31,13 @@ module EltHelper
28
31
  textiled = textiled.gsub(/[->\[]/, ' ')
29
32
  textiled = textiled.to_html
30
33
  end
31
- if ! textiled.match(/[.\s]<p>/) then
34
+ if ! textiled.match(/[.\s]<p>/) and textiled.size < 200 then
32
35
  # Remove any leading and finishing <p> </p> as they are not required
33
36
  if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
34
37
  if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
35
38
  end
36
39
 
37
40
  textiled
38
-
39
- # in reply to:\n>
40
- # .gsub(/(:)(\n)(^>\s)/, '\\1\\2\\2\\3') \
41
- # ^here: data
42
- # .gsub(/^(\w*):\s/, ' \\1: ') \
43
-
44
- # hard_breaks = false
45
- # auto_link textilize_without_paragraph(data \
46
- # .gsub(/\&\#8211\;/, '* ') \
47
- # .gsub(/^-\s/, '* ') \
48
- # .gsub(/[^\n]\n^>/, '') \
49
- # .gsub(/^\d+[ \.-]+/, '# ') \
50
- # # ).gsub(/(.{65,182})<br\s\/>/, \
51
- # # ).gsub(/([\r\n\<\>=\w\d\s.\:;,$*?!\-����������\"\&#;()\/]{65,182})<br\s\/>([^>])/,
52
- # ) if data != nil
53
41
  end
54
42
 
55
43
  #
@@ -60,10 +48,11 @@ module EltHelper
60
48
  #
61
49
  def displayTitle? elt
62
50
  #elt.id and elt.subject.reverse.index(elt.parent.subject.reverse) != 0
63
- elt.id and elt.parent and !elt.subject.empty? \
51
+ elt.id and elt.parent and elt.subject and !elt.subject.empty? \
64
52
  and elt.subject != elt.parent.subject \
53
+ and elt.parent.subject \
65
54
  and elt.subject.downcase != elt.parent.subject.downcase \
66
- and not elt.subject =~ /^((\[[\w]*\] )*(r�f|re|sv|aw)*(.)*:[ \t]*)+(#{Regexp.escape(elt.parent.subject)})/
55
+ and not elt.subject.sub(/(Re|r�f|re|sv|aw):\s*/, '') == elt.parent.subject
67
56
  end
68
57
  end
69
58
 
data/app/models/elt.rb CHANGED
@@ -7,7 +7,8 @@
7
7
  class Elt < ActiveRecord::Base
8
8
  usesguid
9
9
 
10
- acts_as_tree :order => "position is not null, position, created_on"
10
+ acts_as_nested_set :order => "position is not null, position, created_on"
11
+ acts_as_tree :order => "position is not null, position, created_on", :counter_cache => true
11
12
 
12
13
  has_one :mail, :dependent => true
13
14
  has_many :attachments, :dependent => true
@@ -16,14 +17,9 @@ class Elt < ActiveRecord::Base
16
17
 
17
18
  has_and_belongs_to_many :subscribers, :class_name => "Person", :join_table => "subscribers"
18
19
 
19
- has_many :choices
20
+ has_many :choices, :dependent => true, :order => "choices.created_on"
20
21
  has_many :voters, :through => :choices, :source => :person
21
22
 
22
- # for live_tree
23
- def name
24
- subject
25
- end
26
-
27
23
  # Just a quick method to get all subscribers as a simple list
28
24
  def all_recipients
29
25
  if parent
@@ -33,36 +29,94 @@ class Elt < ActiveRecord::Base
33
29
  end
34
30
  end
35
31
 
36
- alias_method :simple_save, :save
37
-
38
- # Save, publish and vote this elt
39
- def save
40
- publish
41
- simple_save
42
- vote
43
- end
44
-
45
32
  def vote(value = 1, person = self.person)
46
33
  logger.info "#{person.name if person} vote #{value} on #{subject} #{self.choices}"
47
- choices.each{ |c| logger.info c if c.person == person; c.destroy if c.person == person }
34
+ choices.each{ |c| c.destroy if c.person == person }
48
35
  choice = choices.build :value => value, :person => person
49
36
  choice.save!
50
37
  end
51
38
 
52
39
  # Get the vote results
53
40
  def result(electoralList = nil)
54
- (Choice.count("elt_id = '#{self.id}' AND value = 1") \
55
- - \
56
- Choice.count("elt_id = '#{self.id}' AND value = -1"))
41
+ #(Choice.count("elt_id = '#{self.id}' AND value = 1") \
42
+ # - \
43
+ # Choice.count("elt_id = '#{self.id}' AND value = -1"))
44
+ Choice.sum(:value, :conditions => "elt_id = '#{self.id}'")
57
45
  end
58
46
 
59
- private
60
-
61
47
  # Mail this elt to all subscribers
62
48
  def publish
63
49
  logger.info "Publish #{subject}"
50
+
64
51
  build_mail(:elt => self) unless mail
65
52
  mail.publish
53
+ save!
54
+
55
+ parent.vote Regexp.last_match(1), person if body =~ /^\s*(-1|0|\+1)(\s|$)/
56
+ if self.body.gsub(/(-1|0|\+1)/, '').strip.empty?
57
+ # Hide simple votes
58
+ vote -1
59
+ else
60
+ vote if person
61
+ end
62
+ true
63
+ end
64
+
65
+ def save
66
+ if new_record? and subject and not subject.empty?
67
+ # Let's generate a nice looking id
68
+ self.id = new_id = subject.gsub(/\[[\w-]*\]/, '').strip.gsub(/[\s\?\&\#\\\/:]+/, '_')
69
+
70
+ discrim = 0
71
+ self.id = "#{new_id}_#{discrim}" while discrim += 1 and self.class.find_by_id self.id
72
+ end
73
+
74
+ super
75
+ end
76
+
77
+ #
78
+ # ___________________________________________________________________
79
+ # | Root |
80
+ # | ____________________________ ____________________________ |
81
+ # | | Child 1 | | Child 2 | |
82
+ # | | __________ _________ | | __________ _________ | |
83
+ # | | | C 1.1 | | C 1.2 | | | | C 2.1 | | C 2.2 | | |
84
+ # 1 2 3_________4 5________6 7 8 9_________10 11_______12 13 14
85
+ # | |___________________________| |___________________________| |
86
+ # |___________________________________________________________________|
87
+ #
88
+ def move(destination)
89
+ return if self[right_col_name].nil? || self[left_col_name].nil? \
90
+ || destination[right_col_name].nil? || destination[left_col_name].nil? \
91
+ || (self[left_col_name] < destination[left_col_name] && destination[right_col_name] < self[right_col_name])
92
+
93
+ dif = self[right_col_name] - self[left_col_name] + 1
94
+ moveBy = destination[right_col_name] - self[left_col_name]
95
+
96
+ self.class.transaction {
97
+ # Take out of range this very node
98
+ self.class.update_all( "#{left_col_name} = -#{left_col_name}, #{right_col_name} = -#{right_col_name}",
99
+ "#{scope_condition} AND #{self[left_col_name]} <= #{left_col_name} AND #{right_col_name} <= #{self[right_col_name]}" )
100
+
101
+ # Shift intermediary elements to the left
102
+ self.class.update_all( "#{left_col_name} = (#{left_col_name} - #{dif})",
103
+ "#{scope_condition} AND #{self[right_col_name]} < #{left_col_name} AND #{left_col_name} < #{destination[right_col_name]}" )
104
+ self.class.update_all( "#{right_col_name} = (#{right_col_name} - #{dif})",
105
+ "#{scope_condition} AND #{self[right_col_name]} < #{right_col_name} AND #{right_col_name} < #{destination[right_col_name]}" )
106
+
107
+ # Shift intermediary elements to the right
108
+ self.class.update_all( "#{left_col_name} = (#{left_col_name} + #{dif})",
109
+ "#{scope_condition} AND #{destination[right_col_name]} < #{left_col_name} AND #{left_col_name} < #{self[left_col_name]}" )
110
+ self.class.update_all( "#{right_col_name} = (#{right_col_name} + #{dif})",
111
+ "#{scope_condition} AND #{destination[right_col_name]} <= #{right_col_name} AND #{right_col_name} < #{self[left_col_name]}" )
112
+
113
+ # Puts back this element where it should be
114
+ self.class.update_all( "#{left_col_name} = -#{left_col_name} + #{moveBy}, #{right_col_name} = -#{right_col_name} + #{moveBy}",
115
+ "#{scope_condition} AND #{self[left_col_name]} <= -#{left_col_name} AND #{right_col_name} <= -#{self[right_col_name]}" )
116
+
117
+ self.parent = destination
118
+ self.save!
119
+ }
66
120
  end
67
121
  end
68
122
 
data/app/models/mail.rb CHANGED
@@ -103,7 +103,9 @@ class Mail < ActiveRecord::Base
103
103
  rescue ActiveRecord::RecordNotFound
104
104
  elt.build_parent :parent_id => 'mail', :subject => parentId, :body => ''
105
105
  elt.parent.id = parentId
106
- elt.parent.save!
106
+ elt.parent.publish
107
+ elt.save
108
+ elt.parent.parent.add_child elt.parent
107
109
  end
108
110
 
109
111
  mngAttachment(mail) if mail
@@ -111,16 +113,10 @@ class Mail < ActiveRecord::Base
111
113
  self.message = mail.message_id
112
114
  self.mail_parents = mail.references
113
115
  self.file = mail.encoded
114
- elt.save!
115
-
116
- if elt.body =~ /^\s*(-1|0|\+1)(\s*|$)/ then
117
- #print '(', $`, ': ', Regexp.last_match(1), ')'
118
- #puts
119
- elt.parent.vote Regexp.last_match(1)
120
- end
116
+ elt.publish
117
+ elt.parent.add_child elt
121
118
  end
122
119
 
123
-
124
120
  """ _ _ _ _
125
121
  _ __ _ _| |__ | (_)___| |__
126
122
  | '_ \| | | | '_ \| | / __| '_ \
@@ -201,7 +197,14 @@ class Mail < ActiveRecord::Base
201
197
  if attachment.content_type == 'text/plain'
202
198
  charset = attachment.type_param 'charset'
203
199
  if charset and !charset.empty?
204
- elt.body += Iconv.new(charset, 'utf-8').iconv(attachment.body)
200
+ if attachment.transfer_encoding == 'quoted-printable'
201
+ # Here to correct a null character which can occur in some mails
202
+ # It looks like ==0 or ^@ !!!
203
+ # Otherwise the elt can not be saved in the db :(
204
+ elt.body += Iconv.new(charset, 'utf-8').iconv(attachment.body).gsub(/\0/, '')
205
+ else
206
+ elt.body += Iconv.new(charset, 'utf-8').iconv(attachment.body)
207
+ end
205
208
  else
206
209
  elt.body += attachment.body
207
210
  end
@@ -9,40 +9,24 @@ class MailNotify < ActionMailer::Base
9
9
  logger.info "Create a mail for publication"
10
10
  subject elt.subject
11
11
 
12
- recipients (mailing_list(elt.parent).subject.blank? ? '' : mailing_list(elt.parent).subject ) \
13
- + ' <' \
14
- + mailing_list(elt.parent).id + '@' + ActionMailer::Base.server_settings[:domain] \
15
- + '>'
12
+ ml = mailing_list(elt.parent)
13
+
14
+ recipients (ml.subject.blank? ? '' : ml.subject ) \
15
+ + " <#{ml.id}@#{ActionMailer::Base.server_settings[:domain]}>"
16
16
 
17
17
  from ((elt.person and elt.person.name) ? elt.person.name : ANONYMOUS_POSTER) \
18
- + ' <' \
18
+ + " <" \
19
19
  + ((elt.person and elt.person.email) \
20
- ? elt.person.email : ANONYMOUS_POSTER + '@' + ActionMailer::Base.server_settings[:domain]) \
21
- + '> '
20
+ ? elt.person.email : "#{ANONYMOUS_POSTER}@#{ActionMailer::Base.server_settings[:domain]}") \
21
+ + ">"
22
22
 
23
23
  # Try to render the element as html
24
- body(:elt => elt)
25
-
26
- #content_type 'multipart/alternative'
27
- #part "text/html" do |a|
28
- # a.body = render(:template => "/home/manu/develop/parlement/trunk/app/views/mail_notify/publish.text.html.rhtml",
29
- # :locals => { :elt => elt })
30
- #end
31
- #part "text/plain" do |a|
32
- # a.body = render(:template => "mail_notify/publish.text.plain",
33
- # :locals => { :elt => elt })
34
- #end
35
- # :body => email_builder.render(:file => "mail_notify/publish.text.html.rhtml")
36
- #attachment :content_type => "text/html",
37
- # :body => email_builder.render(:file => "mail_notify/publish.text.html.rhtml")
38
- #attachment :content_type => "text/plain",
39
- # :body => email_builder.render(:file => "mail_notify/publish.text.plain.rhtml")
40
-
24
+ body :elt => elt
41
25
 
42
26
  # This is the essential of a mailing list, you reply to the mailing list,
43
27
  # where every body sends their mail.
44
28
  # This very mail can be a mailing list all by itself...
45
- @headers['Reply-to'] = mailing_list(elt).id + '@' + ActionMailer::Base.server_settings[:domain]
29
+ @headers['Reply-to'] = "#{ml.id}@#{ActionMailer::Base.server_settings[:domain]}"
46
30
 
47
31
  @headers['In-Reply-To'] = elt.parent.mail.message \
48
32
  if elt.parent and elt.parent.mail and elt.parent.mail.message
@@ -56,7 +40,7 @@ class MailNotify < ActionMailer::Base
56
40
  @headers['references'] << parentMsg.message if parentMsg.message
57
41
  end
58
42
 
59
- @headers['X-Mailer'] = ActionMailer::Base.server_settings[:domain] + " v" + PARLEMENT_VERSION
43
+ @headers['X-Mailer'] = "#{ActionMailer::Base.server_settings[:domain]} v#{PARLEMENT_VERSION}"
60
44
 
61
45
  logger.info "Mail created"
62
46
  end
@@ -70,7 +54,7 @@ class MailNotify < ActionMailer::Base
70
54
  # generated ids
71
55
  #
72
56
  def mailing_list(elt)
73
- if (elt.id.size > 21 and elt.parent_id != 'ROOT') then
57
+ if (elt.id.size > 21 and elt.parent_id != 'ROOT' and !elt.subject.match 'Re: ') then
74
58
  mailing_list elt.parent
75
59
  else
76
60
  elt
data/app/models/person.rb CHANGED
@@ -6,7 +6,7 @@ class Person < ActiveRecord::Base
6
6
  has_many :issues, :through => :choices, :source => :elt
7
7
 
8
8
  validates_presence_of :name, :on => :create
9
- validates_length_of :name, :within => 3..40, :on => :create
9
+ validates_length_of :name, :within => 3..80, :on => :create
10
10
  validates_uniqueness_of :name, :on => :create
11
11
  validates_uniqueness_of :email, :on => :create,
12
12
  :if => Proc.new { |p| p.email and p.email.length > 0 }