parlement 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +26 -0
- data/README +2 -1
- data/app/controllers/account_controller.rb +27 -18
- data/app/controllers/application.rb +1 -3
- data/app/controllers/elt_controller.rb +92 -42
- data/app/helpers/elt_helper.rb +7 -18
- data/app/models/elt.rb +76 -22
- data/app/models/mail.rb +13 -10
- data/app/models/mail_notify.rb +11 -27
- data/app/models/person.rb +1 -1
- data/app/views/account/_login.rhtml +14 -9
- data/app/views/account/_show.rhtml +23 -9
- data/app/views/elt/_choice.rhtml +32 -0
- data/app/views/elt/_elt.rhtml +90 -78
- data/app/views/elt/_list.rhtml +83 -50
- data/app/views/elt/_listByDate.rhtml +60 -0
- data/app/views/elt/_listByVote.rhtml +71 -0
- data/app/views/elt/choices.rhtml +29 -0
- data/app/views/elt/new.rhtml +11 -26
- data/app/views/elt/rss.rxml +14 -12
- data/app/views/elt/show.rhtml +23 -29
- data/app/views/elt/vote_rss.rxml +40 -0
- data/app/views/layouts/top.rhtml +5 -13
- data/config/environment.rb +3 -1
- data/config/routes.rb +4 -0
- data/db/development_structure.sql +5 -2
- data/db/migrate/002_nested_set.rb +22 -0
- data/db/migrate/003_elt_children_count.rb +12 -0
- data/public/images/ParlementLogo.png +0 -0
- data/public/images/indicator.gif +0 -0
- data/public/javascripts/behaviour.js +254 -0
- data/public/javascripts/mybehaviour.js +96 -0
- data/public/javascripts/slider.js +188 -163
- data/test/fixtures/elts.yml +19 -0
- data/test/fixtures/mail/mail_ruby +4 -0
- data/test/fixtures/mail/mail_rubyChild +1 -1
- data/test/fixtures/mail/mail_rubyChild2 +1 -1
- data/test/functional/account_controller_test.rb +24 -0
- data/test/functional/elt_controller_test.rb +64 -4
- data/test/unit/elt_test.rb +28 -4
- data/test/unit/mail_notify_test.rb +7 -5
- data/test/unit/mail_test.rb +1 -1
- data/vendor/plugins/google_analytics/README +19 -0
- data/vendor/plugins/google_analytics/Rakefile +22 -0
- data/vendor/plugins/google_analytics/init.rb +3 -0
- data/vendor/plugins/google_analytics/lib/rubaidh/google_analytics.rb +70 -0
- data/vendor/plugins/google_analytics/test/google_analytics_test.rb +8 -0
- data/vendor/plugins/output_compression/README +4 -0
- data/vendor/plugins/output_compression/Rakefile +22 -0
- data/vendor/plugins/output_compression/init.rb +2 -0
- data/vendor/plugins/output_compression/lib/output_compression.rb +66 -0
- data/vendor/plugins/output_compression/tasks/output_compression_tasks.rake +4 -0
- data/vendor/plugins/output_compression/test/output_compression_test.rb +8 -0
- metadata +32 -4
- data/public/images/smile.svg +0 -257
- 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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
65
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
86
|
-
|
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
|
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 => {
|
118
|
-
|
117
|
+
render :partial => 'show', :locals => {
|
118
|
+
:divId => params[:divId], :choices => getAllVotes }
|
119
119
|
end
|
120
120
|
|
121
121
|
|
122
122
|
def logout
|
123
|
-
|
124
|
-
|
125
|
-
render :partial => '
|
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
|
-
|
136
|
-
|
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
|
-
|
7
|
+
|
8
|
+
def index
|
8
9
|
params[:id] = params[:id].gsub(/.html/, '')
|
9
|
-
|
10
|
-
|
10
|
+
show
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
+
def show
|
13
14
|
params[:id] = params[:id].gsub(/.html/, '')
|
14
|
-
|
15
|
-
@title = @elt.subject
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
31
|
+
def list
|
32
|
+
@elt = Elt.find(params[:id]) if @elt == nil
|
27
33
|
render :partial => '/elt/list', :locals => { :elt => @elt }
|
28
|
-
|
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
|
-
|
46
|
+
def rss
|
31
47
|
params[:id] = params[:id].gsub(/.rss/, '')
|
32
48
|
@headers["Content-Type"] = "text/xml; charset=utf-8"
|
33
|
-
|
34
|
-
|
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
|
-
|
38
|
-
|
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
|
-
|
68
|
+
end
|
52
69
|
|
53
|
-
|
70
|
+
def preview
|
54
71
|
render :inline => h(format(params[:elt][:body]))
|
55
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
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
|
|
data/app/helpers/elt_helper.rb
CHANGED
@@ -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
|
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
|
-
|
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|
|
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
|
-
|
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.
|
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.
|
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
|
-
|
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
|
data/app/models/mail_notify.rb
CHANGED
@@ -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
|
-
|
13
|
-
|
14
|
-
|
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
|
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
|
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'] =
|
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]
|
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..
|
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 }
|