[webui] don't crash on source access protected packages
[opensuse:packman-build-service.git] / src / webui / app / models / package.rb
1 class Package < ActiveXML::Base
2    
3   belongs_to :project
4
5   handles_xml_element 'package'
6
7   #cache variables
8   attr_accessor :linkinfo
9
10   attr_accessor :bf_updated
11   attr_accessor :pf_updated
12   attr_accessor :df_updated
13   attr_accessor :uf_updated
14
15   def initialize(*args)
16     super(*args)
17     @bf_updated = false
18     @pf_updated = false
19     @df_updated = false
20     @uf_updated = false
21   end
22
23   def to_s
24     name.to_s
25   end
26
27   def save_file( opt = {} )
28     file = opt[:file]
29     logger.debug "storing file: #{file.inspect}, filename: #{opt[:filename]}, comment: #{opt[:comment]}"
30
31     put_opt = Hash.new
32     put_opt[:package] = self.name
33     put_opt[:project] = @init_options[:project]
34     put_opt[:filename] = opt[:filename]
35     put_opt[:comment] = opt[:comment]
36     put_opt[:expand] = "1" if opt[:expand]
37
38     fc = FrontendCompat.new
39     fc.put_file file.read, put_opt
40     true
41   end
42
43   def remove_file( name, expand = nil )
44     delete_opt = Hash.new
45     delete_opt[:package] = self.name
46     delete_opt[:project] = @init_options[:project]
47     delete_opt[:filename] = name
48     delete_opt[:expand] = "1" if expand
49
50     begin
51        FrontendCompat.new.delete_file delete_opt
52        true
53     rescue ActiveXML::Transport::NotFoundError
54        false
55     end 
56   end
57
58   def add_person( opt={} )
59     return false unless opt[:userid] and opt[:role]
60     logger.debug "adding person '#{opt[:userid]}', role '#{opt[:role]}' to package #{self.name}"
61
62     #add the new person
63     add_element 'person', 'userid' => opt[:userid], 'role' => opt[:role]
64   end
65
66   #removes persons based on attributes
67   def remove_persons( opt={} )
68     xpath="//person"
69     if not opt.empty?
70       opt_arr = []
71       opt.each do |k,v|
72         opt_arr << "@#{k}='#{v}'"
73       end
74       xpath += "[#{opt_arr.join ' and '}]"
75     end
76     logger.debug "removing persons using xpath '#{xpath}'"
77     data.find(xpath).each {|e| e.remove! }
78   end
79
80
81   def set_url( new_url )
82     logger.debug "set url #{new_url} for package #{self.name} (project #{self.project})"
83     add_element 'url' unless has_element? :url
84     url.text = new_url
85     save
86   end
87
88
89   def remove_url
90     logger.debug "remove url from package #{self.name} (project #{self.project})"
91     data.find('//url').each { |e| e.remove! }
92     save
93   end
94
95   def bugowner
96     b = all_persons("bugowner")
97     return b.first if b
98     return nil
99   end
100
101   def linking_packages
102     opt = Hash.new
103     opt[:project] = self.project
104     opt[:package] = self.name
105     opt[:cmd] = "showlinked"
106     fc = FrontendCompat.new
107     answer = fc.do_post nil, opt
108
109     doc = XML::Parser.string(answer).parse
110     result = []
111     doc.find("/collection/package").each do |e|
112       hash = {}
113       hash[:project] = e.attributes["project"]
114       hash[:package] = e.attributes["name"]
115       result.push( hash )
116     end
117
118     return result
119   end
120
121   def all_persons( role )
122     ret = Array.new
123     each_person do |p|
124       if p.role == role
125         ret << p.userid.to_s
126       end
127     end
128     return ret
129   end
130
131   def all_groups( role )
132     ret = Array.new
133     each_group do |p|
134       if p.role == role
135         ret << p.groupid.to_s
136       end
137     end
138     return ret
139   end
140
141   def is_maintainer? userid
142     has_element? "person[@role='maintainer' and @userid = '#{userid}']"
143   end
144
145   def free_directory
146     # just free current revision cache
147     Directory.free_cache( :project => project, :package => name, :expand => nil )
148     Directory.free_cache( :project => project, :package => name, :expand => "1" )
149   end
150
151   def linkinfo
152     unless @linkinfo
153       begin
154         link = Directory.find_cached( :project => project, :package => name)
155         @linkinfo = link.linkinfo if link.has_element? 'linkinfo'
156       rescue ActiveXML::Transport::NotFoundError
157       end
158     end
159     @linkinfo
160   end
161
162   def linked_to
163     return [linkinfo.project, linkinfo.package] if linkinfo
164     return []
165   end
166
167   def self.current_rev(project, package )
168     Directory.free_cache( :project => project, :package => package )
169     dir = Directory.find_cached( :project => project, :package => package )
170     return nil unless dir
171     return nil unless dir.has_attribute? :rev
172     return dir.rev
173   end
174
175   def commit( rev = nil )
176     if rev and rev.to_i < 0
177       # going backward from not yet known current revision, find out ...
178       r = Package.current_rev(project, name).to_i + rev.to_i + 1
179       rev = r.to_s
180       return nil if rev.to_i < 1
181     end
182     rev = Package.current_rev(project, name) unless rev
183
184     path = "/source/#{CGI.escape(project)}/#{CGI.escape(name)}/_history?rev=#{CGI.escape(rev)}"
185
186     frontend = ActiveXML::Config::transport_for( :package )
187     begin
188       answer = frontend.direct_http URI(path), :method => "GET"
189     rescue
190       return nil
191     end
192
193     c = {}
194     doc = XML::Parser.string(answer).parse.root
195     doc.find("/revisionlist/revision").each do |s|
196          c[:revision]= s.attributes["rev"]
197          c[:user]    = s.find_first("user").content
198          c[:version] = s.find_first("version").content
199          c[:time]    = s.find_first("time").content
200          c[:srcmd5]  = s.find_first("srcmd5").content
201          if comment=s.find_first("comment")
202            c[:comment] = comment.content
203          end
204     end
205
206     return nil unless [:revision]
207     return c
208   end
209
210   def files( rev = nil, expand = nil )
211     # files whose name ends in the following extensions should not be editable
212     no_edit_ext = %w{ .bz2 .dll .exe .gem .gif .gz .jar .jpeg .jpg .lzma .ogg .pdf .pk3 .png .ps .rpm .svgz .tar .taz .tb2 .tbz .tbz2 .tgz .tlz .txz .xpm .xz .z .zip }
213     files = []
214     p = {}
215     p[:project] = project
216     p[:package] = name
217     p[:expand]  = "1"     if expand == "true"
218     p[:rev]     = rev     if rev
219     dir = Directory.find_cached(p)
220     return files unless dir
221     @linkinfo = dir.linkinfo if dir.has_element? 'linkinfo'
222     dir.each_entry do |entry|
223       file = Hash[*[:name, :size, :mtime, :md5].map {|x| [x, entry.send(x.to_s)]}.flatten]
224       file[:ext] = Pathname.new(file[:name]).extname
225       file[:editable] = ((not no_edit_ext.include?( file[:ext].downcase )) and not file[:name].match(/^_service:/) and file[:size].to_i < 2**20)  # max. 1 MB
226       file[:srcmd5] = dir.srcmd5
227       files << file
228     end
229     return files
230   end
231
232 end
233