aboutsummaryrefslogtreecommitdiff
blob: 1f30599d42721ca494eed11fec4ae65e1ede7dc3 (plain)
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