optimized status monitor
[opensuse:build-service.git] / src / webui / app / controllers / project_controller.rb
1 class ProjectController < ApplicationController 
2   model :project, :package, :result
3
4   before_filter :check_parameter_project, :except =>
5     [ :list_all, :list_public, :list_my, :new, :save_new, :save, :index, :refresh_monitor,
6       :toggle_watch ]
7
8   def list_all
9     projectlist = Project.find(:all).each_entry.sort do |a,b|  
10       a.name.downcase <=> b.name.downcase
11     end
12
13     @project_pages, @projects = paginate_collection( projectlist )
14   end
15
16   def list_public
17     logger.debug "inside list_public"
18     projectlist = Project.find(:all).each_entry.sort do |a,b|  
19       a.name.downcase <=> b.name.downcase 
20     end
21
22     projectlist.reject! do |p|
23       p.name.to_s =~ /^home:/
24     end
25     
26     @project_pages, @projects = paginate_collection( projectlist )
27   end
28
29   def list_my
30     @projects = Project.find(:all).each_entry
31     logger.debug "Have this session login: #{session[:login]}"
32     @user ||= Person.find( :login => session[:login] )
33     if @user.has_element? :watchlist
34       #extract a list of project names and sort them case insensitive
35       @watchlist = @user.watchlist.each_project.map {|p| p.name }.sort {|a,b| a.downcase <=> b.downcase }
36     end
37   end
38
39   def remove_watched_project
40     project = params[:project]
41     @user ||= Person.find( session[:login] )
42     logger.debug "removing watched project '#{project}' from user '#@user'"
43     @user.remove_watched_project project
44     @user.save
45
46     @watchlist = @user.watchlist if @user.has_element? :watchlist
47
48     render :partial => 'watch_list'
49   end
50
51   def new
52     @project_name = params[:project]
53     if @project_name =~ /home:(.*)/
54       @project_title = "#$1's Home Project" 
55     else
56       @project_title = ""
57     end
58   end
59
60   def show
61     begin
62       @project = Project.find( params[:project] )
63     rescue ActiveXML::Transport::NotFoundError
64       # create home project if none is there
65       logger.debug "caught Transport::NotFoundError in ProjectController#show"
66       home_project = "home:" + session[:login]
67       if params[:project] == home_project
68         flash[:note] = "Home project doesn't exist yet. You can create it now by entering some" +
69           " descriptive data and press the 'Create Project' button."
70         redirect_to :action => :new, :project => home_project
71       else
72         logger.debug "Project does not exist"
73         flash[:error] = "Project #{params[:project]} doesn't exist."
74         redirect_to :action => :list_public
75       end
76       return
77     end
78
79     #@project_name parameter needed for _watch_link partial
80     @project_name = @project.name
81
82     tmp = Hash.new
83     @project.each_repository do |repo|
84       repo.each_arch do |arch|
85         tmp[arch.to_s] = 1
86       end
87     end
88
89     @arch_list = tmp.keys.sort
90
91     @packstatus = Packstatus.find( params[:project], :command => 'summaryonly' )
92   end
93
94   def save_new
95     logger.debug( "save_new" )
96   
97     if !valid_project_name?( params[:name] )
98       flash[:error] = "Invalid project name '#{params[:name]}'."
99       redirect_to :action => "new"
100     else
101       #store project
102       @project = Project.new( :name => params[:name] )
103
104       @project.title.data.text = params[:title]
105       @project.description.data.text = params[:description]
106       @project.add_person :userid => session[:login], :role => 'maintainer'
107
108       if @project.save
109         flash[:note] = "Project '#{@project}' was created successfully"
110       else
111         flash[:error] = "Failed to save project '#{@project}'"
112       end
113
114       redirect_to :action => 'show', :project => params[:name]
115     end
116   end
117
118   def edit
119     @project = Project.find( params[:project] )
120   end
121
122   def trigger_rebuild
123     @project = Project.find( params[:project] )
124     if @project.save
125       flash[:note] = "Triggered rebuild"
126     else
127       flash[:error] = "Failed to trigger rebuild"
128     end
129     redirect_to :action => 'show', :project => params[:project]
130   end
131
132   def save
133     @project = Project.find( params[:project] )
134
135     if ( !params[:title] )
136       flash[:error] = "Title must not be empty"
137       redirect_to :action => 'edit', :project => params[:project]
138       return
139     end
140
141     @project.title.data.text = params[:title]
142     @project.description.data.text = params[:description]
143
144     if @project.save
145       flash[:note] = "Project '#{@project}' was saved successfully"
146     else
147       flash[:error] = "Failed to save project '#{@project}'"
148     end
149
150     redirect_to :action => 'show', :project => @project
151   end
152
153   def add_target_simple
154     @project = params[:project]
155   end
156
157   def add_target
158     @platforms = Platform.find( :all ).each_entry.map {|p| p.name.to_s}
159
160     #TODO: don't hardcode
161     @priority_namespaces = %{
162       Mandriva
163       SUSE
164       Fedora
165       Debian
166     }
167
168     def @priority_namespaces.include_ns?(projname)
169       nslist = projname.split(/:/)
170       return false if nslist.length != 2
171       return false unless self.include? nslist[0]
172       return true
173     end
174     
175     @platforms.sort! do |a,b|
176       if @priority_namespaces.include_ns? a
177         if @priority_namespaces.include_ns? b
178           a.downcase <=> b.downcase
179         else
180           -1
181         end
182       else
183         if @priority_namespaces.include_ns? b
184           1
185         else
186           a.downcase <=> b.downcase
187         end
188       end
189     end
190
191     @project = Project.find( params[:project] )
192     @targetname = params[:targetname]
193     @platform = params[:platform]
194   end
195
196   def save_target
197     @project = Project.find( params[:project] )
198     platform = params[:platform]
199     arch = params[:arch]
200     targetname = params[:targetname]
201     targetname = "standard" if not targetname or targetname.empty?
202
203     if targetname =~ /\s/
204       flash[:error] = "Target name may not contain spaces"
205       redirect_to :action => :add_target, :project => @project, :targetname => targetname, :platform => platform
206       return
207     end
208
209     @project.add_target :targetname => targetname, :platform => platform,
210       :arch => arch
211
212     if @project.save
213       flash[:note] = "Target '#{platform}' was added successfully"
214     else
215       flash[:error] = "Failed to add target '#{platform}'"
216     end
217
218     redirect_to :action => :show, :project => @project
219   end
220
221   def remove_target
222     if not params[:target]
223       flash[:error] = "Target removal failed, no target selected!"
224       redirect_to :action => :show, :project => params[:project]
225     end
226
227     @project = Project.find( params[:project] )
228     @project.remove_target params[:target]
229
230     if @project.save
231       flash[:note] = "Target '#{params[:target]}' was removed"
232     else
233       flash[:error] = "Failed to remove target '#{params[:target]}'"
234     end
235
236     redirect_to :action => :show, :project => @project
237   end
238
239   def add_person
240     @project = Project.find( params[:project] )
241   end
242
243   def save_person
244     if not params[:userid]
245       flash[:error] = "Login missing"
246       redirect_to :action => :add_person, :project => params[:project], :role => params[:role]
247       return
248     end
249
250     begin
251       user = Person.find( :login => params[:userid] )
252     rescue ActiveXML::NotFoundError
253       flash[:error] = "Unknown user with id '#{params[:userid]}'"
254       redirect_to :action => :add_person, :project => params[:project], :role => params[:role]
255       return
256     end
257     
258     logger.debug "found user: #{user.inspect}"
259     
260     @project = Project.find( params[:project] )
261     @project.add_person( :userid => params[:userid], :role => params[:role] )
262
263     if @project.save
264       flash[:note] = "added user #{params[:userid]}"
265     else
266       flash[:error] = "Failed to add user '#{params[:userid]}'"
267     end
268
269     redirect_to :action => :show, :project => @project
270   end
271
272   def remove_person
273     if not params[:userid]
274       flash[:note] = "User removal aborted, no user id given!"
275       redirect_to :action => :show, :project => params[:project]
276       return
277     end
278     @project = Project.find( params[:project] )
279     @project.remove_persons( :userid => params[:userid], :role => params[:role] )
280
281     if @project.save
282       flash[:note] = "removed user #{params[:userid]}"
283     else
284       flash[:error] = "Failed to remove user '#{params[:userid]}'"
285     end
286
287     redirect_to :action => :show, :project => params[:project]
288   end
289
290   def monitor
291     @project = params[:project] 
292     @packstatus = Packstatus.find( :project => @project )
293
294     if not @packstatus.has_element? :packstatuslist
295       @packstatus_unavailable = true
296       return  
297     end
298
299     @repohash = Hash.new
300     @statushash = Hash.new
301
302     @packstatus.each_packstatuslist do |psl|
303       repo = psl.repository
304       arch = psl.arch
305
306       @repohash[repo] ||= Array.new
307       @repohash[repo] << arch
308
309       @statushash[repo] ||= Hash.new
310       @statushash[repo][arch] = Hash.new
311       rah = @statushash[repo][arch]
312
313       psl.each_packstatus do |ps|
314         rah[ps.name] = ps.status
315       end
316     end
317
318     @packagenames = Array.new
319     @packstatus.packstatuslist.each_packstatus do |ps|
320       @packagenames << ps.name
321     end
322     
323     #session[:monitor_project] = @project
324     #session[:monitor_repohash] = @repohash
325     #session[:monitor_packnames] = @packagenames
326   end
327
328   def refresh_monitor
329     render :nothing unless session[:monitor_project] and
330                            session[:monitor_repohash] and
331                            session[:monitor_packnames]
332
333     @project = session[:monitor_project]
334     @repohash = session[:monitor_repohash]
335     @packnames = session[:monitor_packnames]
336
337     @packstatus = Packstatus.find( :project => @project )
338     
339     @status = Hash.new
340     @packnames.each do |pack|
341       @repohash.each do |repo,archlist|
342         archlist.each do |arch|
343           @status["#{pack}:#{repo}:#{arch}"] = @packstatus.status_for( pack, repo, arch )
344         end
345       end
346     end
347
348     render :layout => false
349   end
350
351   def toggle_watch
352     unless session[:login]
353       render :nothing => true
354       return
355     end
356    
357     @user = Person.find( :login => session[:login] ) unless @user
358     @project_name = params[:project]
359     
360     if @user.watches? @project_name
361       @user.remove_watched_project @project_name
362     else
363       @user.add_watched_project @project_name
364     end
365
366     @user.save
367
368     render :partial => "watch_link"
369   end
370
371   private
372
373   #filters
374   
375   def check_parameter_project
376     if ( !params[:project] )
377       flash[:error] = "Missing parameter 'project'"
378       redirect_to :action => :list_public
379     elsif !valid_project_name?( params[:project] )
380       flash[:error] = "Invalid project name '#{params[:project]}'"
381       redirect_to :action => :list_public
382     end
383   end
384
385   def paginate_collection(collection, options = {})
386     options[:page] = options[:page] || params[:page] || 1
387     default_options = {:per_page => 20, :page => 1}
388     options = default_options.merge options
389     
390     pages = Paginator.new self, collection.size, options[:per_page], options[:page]
391     first = pages.current.offset
392     last = [first + options[:per_page], collection.size].min
393     slice = collection[first...last]
394     return [pages, slice]
395   end
396
397 end