parlement 0.5 → 0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 }
|