1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
# Gentoo Council Web App - to help Gentoo Council do their job better
# Copyright (C) 2011 Joachim Filip Bartosik
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, version 3 of the License
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class AgendaItem < ActiveRecord::Base
hobo_model # Don't put anything above this
fields do
title :string
discussion :string
body :markdown
rejected :boolean, :default => false
timelimits :text
discussion_time :string
timestamps
end
belongs_to :user, :creator => true
belongs_to :agenda
has_many :voting_options
validate :timelimits_entered_properly
# --- Permissions --- #
def create_permitted?
return false if acting_user.guest?
return false if user != acting_user
true
end
def update_permitted?
return false if discussion_time_changed?
return false if agenda._?.state == 'old'
return false if user_changed?
return true if acting_user.council_member?
return true if acting_user.administrator?
return false unless agenda.nil?
return true if acting_user == user
false
end
def destroy_permitted?
acting_user.administrator?
end
def view_permitted?(field)
true
end
# Not deduced properly
def edit_permitted?(field)
return false if field == :rejected && !agenda.nil?
return false if field == :agenda && rejected?
return false if agenda._?.state == 'old'
return false if field == :user
return true if acting_user.administrator?
return true if acting_user.council_member?
return false unless agenda.nil?
return acting_user == user if [nil, :title, :discussion, :body].include?(field)
end
def update_voting_options(new_descriptions)
old_descriptions = voting_options.*.description
(old_descriptions - new_descriptions).each do |description|
option = VotingOption.agenda_item_id_is(id).description_is(description).first
option.destroy
end
(new_descriptions - old_descriptions ).each do |description|
VotingOption.create! :agenda_item => self, :description => description
end
end
protected
# Updated discussion time for a single agenda item
# protected because we want to call it only from
# AgendaItem.update_discussion_times
# or similar methods in children classes (if there will be any)
def update_discussion_time
link_regexp = /^(https?:\/\/)?archives.gentoo.org\/([a-zA-Z-]+)\/(msg_[a-fA-F0-9]+.xml)$/
uri_match = link_regexp.match(discussion)
return unless uri_match
group = uri_match[2]
msg = uri_match[3]
message_info = get_message(group, msg)
first_date = Time.parse message_info[:date]
last_date = first_date
to_visit = []
visited = Set.new([msg])
to_visit += message_info[:links]
until to_visit.empty?
msg = to_visit.pop()
next if visited.include? msg
visited.add msg
message_info = get_message(group, msg)
current_date = Time.parse message_info[:date]
first_date = current_date if first_date > current_date
last_date = current_date if last_date < current_date
to_visit += message_info[:links]
end
duration = ((last_date - first_date) / 1.day).floor
first_date = first_date.strftime '%Y.%m.%d'
last_date = last_date.strftime '%Y.%m.%d'
self.discussion_time = "From #{first_date} to #{last_date}, #{duration} full days"
self.save!
end
def get_message(group, msg)
Net::HTTP.start("archives.gentoo.org") { |http|
resp = http.get("/#{group}/#{msg}?passthru=1")
doc = REXML::Document.new(resp.body)
table = REXML::XPath.match(doc, '//table/tr[th=\'Replies:\']/../tr')
in_replies = false
reply_links = []
table.each do |row|
th = REXML::XPath.first(row, "th")
if th
in_replies = (th.text == 'Replies:')
else
next unless in_replies
reply = REXML::XPath.first(row, "ti/uri")
reply_link = reply.attribute(:link).to_s
reply_links.push(reply_link)
end
end
date = resp.body.match(/\<\!--X-Date: (.*) --\>/)[1]
{:date => date, :links => reply_links}
}
end
def timelimits_entered_properly
regexp = /^\d+:\d+( .*)?$/
for line in timelimits.split("\n")
unless line.match regexp
errors.add(:timelimits, "Line '#{line}' doensn't match '<minutes>:<seconds> <message>'")
end
end
end
end
|