X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/d6d7788c4e6b1d3da88833329b326fd7a3891503..a3222e35cda68c8e48a17921c33ac37ecb5c3bac:/apps/workbench/app/controllers/application_controller.rb diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb index df57e9e71f..d2f4ed44b2 100644 --- a/apps/workbench/app/controllers/application_controller.rb +++ b/apps/workbench/app/controllers/application_controller.rb @@ -12,7 +12,9 @@ class ApplicationController < ActionController::Base # Methods that don't require login should # skip_around_filter :require_thread_api_token around_filter :require_thread_api_token, except: ERROR_ACTIONS + before_filter :accept_uuid_as_id_param, except: ERROR_ACTIONS before_filter :check_user_agreements, except: ERROR_ACTIONS + before_filter :check_user_profile, except: ERROR_ACTIONS before_filter :check_user_notifications, except: ERROR_ACTIONS before_filter :load_filters_and_paging_params, except: ERROR_ACTIONS before_filter :find_object_by_uuid, except: [:index, :choose] + ERROR_ACTIONS @@ -60,22 +62,31 @@ class ApplicationController < ActionController::Base else @errors = [e.to_s] end - # If the user has an active session, and the API server is available, - # make user information available on the error page. + # Make user information available on the error page, falling back to the + # session cache if the API server is unavailable. begin load_api_token(session[:arvados_api_token]) rescue ArvadosApiClient::ApiError - load_api_token(nil) + unless session[:user].nil? + begin + Thread.current[:user] = User.new(session[:user]) + rescue ArvadosApiClient::ApiError + # This can happen if User's columns are unavailable. Nothing to do. + end + end end - # Preload projects trees for the template. If that fails, set empty + # Preload projects trees for the template. If that's not doable, set empty # trees so error page rendering can proceed. (It's easier to rescue the # exception here than in a template.) - begin - build_project_trees - rescue ArvadosApiClient::ApiError - @my_project_tree ||= [] - @shared_project_tree ||= [] + unless current_user.nil? + begin + build_project_trees + rescue ArvadosApiClient::ApiError + # Fall back to the default-setting code later. + end end + @my_project_tree ||= [] + @shared_project_tree ||= [] render_error(err_opts) end @@ -88,6 +99,9 @@ class ApplicationController < ActionController::Base end def load_filters_and_paging_params + @order = params[:order] || 'created_at desc' + @order = [@order] unless @order.is_a? Array + @limit ||= 200 if params[:limit] @limit = params[:limit].to_i @@ -127,10 +141,8 @@ class ApplicationController < ActionController::Base respond_to do |f| f.json { render json: @objects } f.html { - if params['tab_pane'] - comparable = self.respond_to? :compare - render(partial: 'show_' + params['tab_pane'].downcase, - locals: { comparable: comparable, objects: @objects }) + if params[:tab_pane] + render_pane params[:tab_pane] else render end @@ -139,6 +151,23 @@ class ApplicationController < ActionController::Base end end + helper_method :render_pane + def render_pane tab_pane, opts={} + render_opts = { + partial: 'show_' + tab_pane.downcase, + locals: { + comparable: self.respond_to?(:compare), + objects: @objects, + tab_pane: tab_pane + }.merge(opts[:locals] || {}) + } + if opts[:to_string] + render_to_string render_opts + else + render render_opts + end + end + def index find_objects_for_index if !@objects render_index @@ -173,12 +202,16 @@ class ApplicationController < ActionController::Base return render_not_found("object not found") end respond_to do |f| - f.json { render json: @object.attributes.merge(href: url_for(@object)) } + f.json do + extra_attrs = { href: url_for(action: :show, id: @object) } + @object.textile_attributes.each do |textile_attr| + extra_attrs.merge!({ "#{textile_attr}Textile" => view_context.render_content_from_database(@object.attributes[textile_attr]) }) + end + render json: @object.attributes.merge(extra_attrs) + end f.html { if params['tab_pane'] - comparable = self.respond_to? :compare - render(partial: 'show_' + params['tab_pane'].downcase, - locals: { comparable: comparable, objects: @objects }) + render_pane params['tab_pane'] elsif request.method.in? ['GET', 'HEAD'] render else @@ -247,7 +280,7 @@ class ApplicationController < ActionController::Base @object ||= model_class.new @new_resource_attrs, params["options"] if @object.save respond_to do |f| - f.json { render json: @object.attributes.merge(href: url_for(@object)) } + f.json { render json: @object.attributes.merge(href: url_for(action: :show, id: @object)) } f.html { redirect_to @object } @@ -349,10 +382,14 @@ class ApplicationController < ActionController::Base end end - def find_object_by_uuid + + def accept_uuid_as_id_param if params[:id] and params[:id].match /\D/ params[:uuid] = params.delete :id end + end + + def find_object_by_uuid begin if not model_class @object = nil @@ -388,9 +425,6 @@ class ApplicationController < ActionController::Base Thread.current[:arvados_api_token] = new_token if new_token.nil? Thread.current[:user] = nil - elsif (new_token == session[:arvados_api_token]) and - session[:user].andand[:is_active] - Thread.current[:user] = User.new(session[:user]) else Thread.current[:user] = User.current end @@ -408,6 +442,10 @@ class ApplicationController < ActionController::Base false # We may redirect to login, or not, based on the current action. else session[:arvados_api_token] = params[:api_token] + # If we later have trouble contacting the API server, we still want + # to be able to render basic user information in the UI--see + # render_exception above. We store that in the session here. This is + # not intended to be used as a general-purpose cache. See #2891. session[:user] = { uuid: user.uuid, email: user.email, @@ -417,6 +455,7 @@ class ApplicationController < ActionController::Base is_admin: user.is_admin, prefs: user.prefs } + if !request.format.json? and request.method.in? ['GET', 'HEAD'] # Repeat this request with api_token in the (new) session # cookie instead of the query string. This prevents API @@ -461,7 +500,7 @@ class ApplicationController < ActionController::Base end end - # Reroute this request if an API token is unavailable. + # Redirect to login/welcome if client provided expired API token (or none at all) def require_thread_api_token if Thread.current[:arvados_api_token] yield @@ -472,7 +511,7 @@ class ApplicationController < ActionController::Base session.delete :arvados_api_token redirect_to_login else - render 'users/welcome' + redirect_to welcome_users_path(return_to: request.fullpath) end end @@ -483,19 +522,22 @@ class ApplicationController < ActionController::Base end end + helper_method :unsigned_user_agreements + def unsigned_user_agreements + @signed_ua_uuids ||= UserAgreement.signatures.map &:head_uuid + @unsigned_user_agreements ||= UserAgreement.all.map do |ua| + if not @signed_ua_uuids.index ua.uuid + Collection.find(ua.uuid) + end + end.compact + end + def check_user_agreements if current_user && !current_user.is_active if not current_user.is_invited - return render 'users/inactive' + return redirect_to inactive_users_path(return_to: request.fullpath) end - signatures = UserAgreement.signatures - @signed_ua_uuids = UserAgreement.signatures.map &:head_uuid - @required_user_agreements = UserAgreement.all.map do |ua| - if not @signed_ua_uuids.index ua.uuid - Collection.find(ua.uuid) - end - end.compact - if @required_user_agreements.empty? + if unsigned_user_agreements.empty? # No agreements to sign. Perhaps we just need to ask? current_user.activate if !current_user.is_active @@ -504,12 +546,47 @@ class ApplicationController < ActionController::Base end end if !current_user.is_active - render 'user_agreements/index' + redirect_to user_agreements_path(return_to: request.fullpath) end end true end + def check_user_profile + if request.method.downcase != 'get' || params[:partial] || + params[:tab_pane] || params[:action_method] || + params[:action] == 'setup_popup' + return true + end + + if missing_required_profile? + redirect_to profile_user_path(current_user.uuid, return_to: request.fullpath) + end + true + end + + helper_method :missing_required_profile? + def missing_required_profile? + missing_required = false + + profile_config = Rails.configuration.user_profile_form_fields + if current_user && profile_config + current_user_profile = current_user.prefs[:profile] + profile_config.kind_of?(Array) && profile_config.andand.each do |entry| + if entry['required'] + if !current_user_profile || + !current_user_profile[entry['key'].to_sym] || + current_user_profile[entry['key'].to_sym].empty? + missing_required = true + break + end + end + end + end + + missing_required + end + def select_theme return Rails.configuration.arvados_theme end @@ -525,15 +602,6 @@ class ApplicationController < ActionController::Base } } - #@@notification_tests.push lambda { |controller, current_user| - # Job.limit(1).where(created_by: current_user.uuid).each do - # return nil - # end - # return lambda { |view| - # view.render partial: 'notifications/jobs_notification' - # } - #} - @@notification_tests.push lambda { |controller, current_user| Collection.limit(1).where(created_by: current_user.uuid).each do return nil @@ -558,7 +626,7 @@ class ApplicationController < ActionController::Base @notification_count = 0 @notifications = [] - if current_user + if current_user.andand.is_active @showallalerts = false @@notification_tests.each do |t| a = t.call(self, current_user) @@ -577,7 +645,7 @@ class ApplicationController < ActionController::Base helper_method :all_projects def all_projects @all_projects ||= Group. - filter([['group_class','in',['project','folder']]]).order('name') + filter([['group_class','=','project']]).order('name') end helper_method :my_projects @@ -688,7 +756,7 @@ class ApplicationController < ActionController::Base crumbs = [] current = @name_link || @object while current - if current.is_a?(Group) and current.group_class.in?(['project','folder']) + if current.is_a?(Group) and current.group_class == 'project' crumbs.prepend current end if current.is_a? Link @@ -702,7 +770,7 @@ class ApplicationController < ActionController::Base helper_method :current_project_uuid def current_project_uuid - if @object.is_a? Group and @object.group_class.in?(['project','folder']) + if @object.is_a? Group and @object.group_class == 'project' @object.uuid elsif @name_link.andand.tail_uuid @name_link.tail_uuid