# 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 . class AgendaItem < ActiveRecord::Base hobo_model # Don't put anything above this fields do title :string discussion :string body :markdown rejected :boolean, :default => false poll :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 attr_readonly :poll # --- 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 ': '") end end end end