merged cont.
[opensuse:yast-rest-service.git] / webservice / app / models / basesystem.rb
1 #--
2 # Webyast Webclient framework
3 #
4 # Copyright (C) 2009, 2010 Novell, Inc. 
5 #   This library is free software; you can redistribute it and/or modify
6 # it only under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation. 
8 #
9 #   This library is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
12 # details. 
13 #
14 #   You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software 
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #++
18
19
20 # = Base system model
21 # Provides access to basic system settings module queue. Provides and updates
22 # if base system settings is already done.
23 require "yast/config_file"
24 require "exceptions"
25 class Basesystem < BaseModel::Base
26
27   # steps needed by base system
28   attr_accessor   :steps
29   # Flag if base system configuration is  finished
30   attr_accessor   :finish
31   attr_accessor   :done
32
33   # path to file which defines module queue
34   BASESYSTEM_CONF = :basesystem
35   BASESYSTEM_CONF_VENDOR        = File.join(Paths::CONFIG,"vendor","basesystem.yml")
36   # path to file which store module then is next in queue or END_STRING if all steps is done
37   FINISH_FILE = File.join(Paths::VAR,"basesystem","finish")
38   FINISH_STR = "FINISH"
39
40   def initialize(options={})
41    @finish = false
42    super options
43   end
44
45   def load_from_session(session)
46     @session = session
47     @steps = @session[:wizard_steps].try(:split,",")
48     self
49   end
50
51   def initialized
52     !(current.blank?)
53   end
54
55   # find basesystem status of backend and properly set session for that
56   #
57   # Note:: See first argument, which is additional to ordinary find method
58   def self.find(session,*args)
59     bs = self.load_from_file
60     if bs.steps.empty? or bs.finish
61       session[:wizard_current] = FINISH_STEP
62     else
63       Rails.logger.debug "Basesystem steps: #{bs.steps.inspect}"
64       decoded_steps = bs.steps.collect { |step| step.respond_to?(:action) ? "#{step.controller}:#{step.action}" : "#{step.controller}"}
65       session[:wizard_steps] = decoded_steps.join(",")
66       session[:wizard_current] =
67         decoded_steps.find(lambda{decoded_steps.first}) do |s|
68           s.include? bs.done
69         end
70     end
71     bs.load_from_session session
72     bs
73   end
74
75   #stores to system Basesystem settings
76   def save
77     str = @finish ? FINISH_STR : done
78     File.open(FINISH_FILE,"w") do |io|
79       io.write str
80     end
81     YastCache.reset("basesystem:find")
82   end
83   
84   # return:: controller which should be next in basesystem sequence
85   # or controlpanel if basesystem is finished
86   # 
87   # require to be basesystem initialized otherwise throw exception
88   def next_step
89     if current == @steps.last
90       self.current_step = FINISH_STEP
91       load(:finish => true, :steps => []) #persistent store, that basesystem finish
92       save #TODO check return value
93       return :controller => "controlpanel"
94     else
95       self.current_step = @steps[@steps.index(current)+1]
96       load(:finish => false,  :steps => [], :done => self.current_step[:controller]) #store advantage in setup
97       save #TODO check return value
98       ret = redirect_hash
99       raise "Invalid configuration. Missing controller required in First boot sequence. 
100         Possible typo or plugin is not installed." unless 
101           ActionController::Routing.possible_controllers.include? ret[:controller]
102       return ret
103     end
104   end
105
106   def current_step
107     redirect_hash
108   end
109
110   def back_step
111     self.current_step = @steps[@steps.index(current)-1] unless first_step?
112     redirect_hash
113   end
114
115   # Gets steps which follow after current one
116   # return:: array of hashes with keys :controller and :action, if basesystem finish return empty array
117   def following_steps
118     return [] if (!initialized || completed?)
119     ret = @steps.slice @steps.index(current)+1,@steps.size
120     ret = ret.collect { |step|
121       arr = step.split(":")
122       { :controller => arr[0], :action => arr[1]||"index"}
123     }
124   end
125
126   def first_step?
127     !(@steps.blank?) && current == @steps.first
128   end
129
130   def last_step?
131     !(@steps.blank?) && current == @steps.last
132   end
133
134   def completed?
135     current == FINISH_STEP
136   end
137
138   def in_process?
139     @steps && !(completed?)
140   end
141
142   private
143   FINISH_STEP = "FINISH"
144
145   def current_step=(val)
146     @session[:wizard_current] = val
147   end
148
149   def redirect_hash
150     arr = current.split(":")
151     { :controller => arr[0], :action => arr[1]||"index"}
152   end
153
154   def current
155     @session[:wizard_current]
156   end
157
158   def self.load_from_file
159     YastCache.fetch("basesystem:find") {
160       base = Basesystem.new
161       basesystem_conf   = BASESYSTEM_CONF
162       basesystem_conf   = BASESYSTEM_CONF_VENDOR if File.exists? BASESYSTEM_CONF_VENDOR
163       Rails.logger.info "Reading config file: #{basesystem_conf}"
164       config = YaST::ConfigFile.new(basesystem_conf)
165       if File.exist?(config.path)
166         begin
167           base.steps = config["steps"] || []
168         rescue Exception => e
169           raise CorruptedFileException.new(config.path)
170         end
171         if File.exist?(FINISH_FILE)
172           begin
173             base.done = IO.read(FINISH_FILE)
174           rescue Exception => e
175             raise CorruptedFileException.new(FINISH_FILE)
176           end
177           base.done = FINISH_STR if base.done.blank? #backward compatibility, when touch indicate finished bs
178           if base.done == FINISH_STR
179             base.finish = true
180           end
181         else
182           if base.steps.empty? #empty step definition
183             base.finish = true
184           else
185             base.done = base.steps.first["controller"]
186           end
187         end
188       else
189         base.steps = []
190         base.finish = true
191       end
192       base
193     }
194   end
195
196 end