Fix creating union of answers. Array has append, Hash has merge, so use it properly
[opensuse:yast-rest-service.git] / plugins / software / app / controllers / patches_controller.rb
1 #--
2 # Copyright (c) 2009-2010 Novell, Inc.
3
4 # All Rights Reserved.
5
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of version 2 of the GNU General Public License
8 # as published by the Free Software Foundation.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, contact Novell, Inc.
17
18 # To contact Novell about this file by physical or electronic mail,
19 # you may find current contact information at www.novell.com
20 #++
21
22 require 'singleton'
23
24 class PatchesController < ApplicationController
25
26    before_filter :login_required
27
28    # always check permissions and cache expiration
29    # even if the result is already created and cached
30    before_filter :check_read_permissions, :only => [:index, :show]
31    before_filter :check_cache_status, :only => :index
32
33    # cache 'index' method result
34    caches_action :index
35
36   private
37
38   def check_read_permissions
39     permission_check "org.opensuse.yast.system.patches.read"
40   end
41
42   # check whether the cached result is still valid
43   def check_cache_status
44  #cache contain string as it is only object supported by all caching backends
45     cache_timestamp = Rails.cache.read('patches:timestamp').to_i
46
47     if cache_timestamp.nil?
48         # this is the first run, the cache is not initialized yet, just return
49         Rails.cache.write('patches:timestamp', Time.now.to_i.to_s)
50     # the cache expires after 5 minutes, repository metadata
51     # or RPM database update invalidates the cache immediately
52     # (new patches might be applicable)
53     elsif cache_timestamp < 15.minutes.ago.to_i || cache_timestamp < Patch.mtime.to_i
54         logger.debug "#### Patch cache expired"
55         expire_action :action => :index, :format => params["format"]
56         Rails.cache.write('patches:timestamp', Time.now.to_i.to_s)
57     end
58   end
59
60   def collect_done_patches
61     done = []
62
63     BackgroundManager.instance.done.each do |k,v|
64       if k.match(/^packagekit_install_(.*)/)
65         patch_id = $1
66         if BackgroundManager.instance.process_finished? k
67           Rails.logger.debug "Patch installation request #{patch_id} is done"
68           ret = BackgroundManager.instance.get_value k
69
70           # check for exception
71           if ret.is_a? StandardError
72             raise ret
73           end
74
75           # e.g.: 'suse-build-key;1.0-907.30;noarch;@System'
76           attrs = patch_id.split(';')
77
78           done << Patch.new(:resolvable_id => attrs[1],
79                            :name => attrs[0],
80                            :arch => attrs[2],
81                            :repo => attrs[3],
82                            :installed => true)
83         end
84       end
85     end
86
87     return done
88   end
89
90         def check_running_install
91     BackgroundManager.instance.running.each do |k,v|
92       if k.match(/^packagekit_install_(.*)/)
93         patch_id = $1
94                                 status = BackgroundManager.instance.get_progress
95                                 raise InstallInProgressException.new status
96                         end
97                 end
98         end
99
100   public
101
102   # GET /patch_updates
103   # GET /patch_updates.xml
104   def index
105                 check_running_install
106     # note: permission check was performed in :before_filter
107     bgr = params['background']
108     Rails.logger.info "Reading patches in background" if bgr
109
110     @patches = Patch.find(:available, {:background => bgr})
111                 @patches << collect_done_patches #report also which patches is installed
112     respond_to do |format|
113       format.xml { render  :xml => @patches.to_xml( :root => "patches", :dasherize => false ) }
114       format.json { render :json => @patches.to_json( :root => "patches", :dasherize => false ) }
115     end
116
117     # do not cache the background progress status
118     # (expire the cache in the next request)
119     if bgr && @patches.first.class == BackgroundStatus
120       Rails.cache.write('patches:timestamp', Time.at(0))
121     end
122   end
123
124   # GET /patch_updates/1
125   # GET /patch_updates/1.xml
126   def show
127     @patch_update = Patch.find(params[:id])
128     if @patch_update.nil?
129       logger.error "Patch: #{params[:id]} not found."
130       render ErrorResult.error(404, 1, "Patch: #{params[:id]} not found.") and return
131     end
132   end
133
134   # PUT /patch_updates/1
135   # PUT /patch_updates/1.xml
136   def update
137     permission_check "org.opensuse.yast.system.patches.install"
138     @patch_update = Patch.find(params[:id])
139     if @patch_update.blank?
140       logger.error "Patch: #{params[:id]} not found."
141       render ErrorResult.error(404, 1, "Patch: #{params[:id]} not found.") and return
142     end
143     unless @patch_update.install
144       render ErrorResult.error(404, 2, "packagekit error") and return
145     end
146     render :show
147   end
148
149   # POST /patch_updates/
150   def create
151     permission_check "org.opensuse.yast.system.patches.install"
152     @patch_update = Patch.find(params[:patches][:resolvable_id].to_s)
153
154 #    bgr = params['background']
155 #    bgr = true
156 #    Rails.logger.info "Installing patch #{params[:patches][:resolvable_id]} in background" if bgr
157
158     #Patch for Bug 560701 - [build 24.1] webYaST appears to crash after installing webclient patch
159     #Packagekit returns empty string if the patch is allready installed.
160     if @patch_update.is_a?(Array) && @patch_update.empty?
161        logger.error "Patch is allready installed or not found #{@patch_update.inspect}"
162        render ErrorResult.error(404, 1, "Patch is not required.") and return
163     end
164
165     if @patch_update.blank?
166       logger.error "Patch: #{params[:patches][:resolvable_id]} not found."
167       render ErrorResult.error(404, 1, "Patch: #{params[:patches][:resolvable_id]} not found.") and return
168     end
169
170     res = @patch_update.install(true)
171
172     if (res.is_a? BackgroundStatus)
173       logger.debug "received background status: #{res.inspect}"
174       respond_to do |format|
175         format.xml { render  :xml => res.to_xml( :root => "status", :dasherize => false ) }
176         format.json { render :json => res.to_json( :root => "status", :dasherize => false ) }
177       end
178
179       return
180     end
181
182 #    unless error
183 #      render ErrorResult.error(404, 2, "packagekit error") and return
184 #    end
185     render :show
186   end
187
188
189 end