X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/392c382ddaf8ea4c0c4b6655c7f508de73274d12..0a6ca2aada7bc0706fd1e41c1002cd6aa375c3a1:/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 c169be2704..09419216b5 100644 --- a/apps/workbench/app/controllers/application_controller.rb +++ b/apps/workbench/app/controllers/application_controller.rb @@ -1,12 +1,18 @@ class ApplicationController < ActionController::Base + include ArvadosApiClientHelper + include ApplicationHelper + respond_to :html, :json, :js protect_from_forgery + + ERROR_ACTIONS = [:render_error, :render_not_found] + around_filter :thread_clear - around_filter :thread_with_mandatory_api_token, :except => [:render_exception, :render_not_found] + around_filter :thread_with_mandatory_api_token, except: ERROR_ACTIONS around_filter :thread_with_optional_api_token - before_filter :find_object_by_uuid, :except => [:index, :render_exception, :render_not_found] - before_filter :check_user_agreements, :except => [:render_exception, :render_not_found] - before_filter :check_user_notifications, :except => [:render_exception, :render_not_found] + before_filter :check_user_agreements, except: ERROR_ACTIONS + before_filter :check_user_notifications, except: ERROR_ACTIONS + before_filter :find_object_by_uuid, except: [:index] + ERROR_ACTIONS theme :select_theme begin @@ -30,6 +36,7 @@ class ApplicationController < ActionController::Base end def render_error(opts) + opts = {status: 500}.merge opts respond_to do |f| # json must come before html here, so it gets used as the # default format when js is requested by the client. This lets @@ -57,20 +64,46 @@ class ApplicationController < ActionController::Base self.render_error status: 404 end - def index + def find_objects_for_index + @limit ||= 200 if params[:limit] - limit = params[:limit].to_i - else - limit = 200 + @limit = params[:limit].to_i end + @offset ||= 0 if params[:offset] - offset = params[:offset].to_i - else - offset = 0 + @offset = params[:offset].to_i + end + + @filters ||= [] + if params[:filters] + filters = params[:filters] + if filters.is_a? String + filters = Oj.load filters + end + @filters += filters + end + + @objects ||= model_class + @objects = @objects.filter(@filters).limit(@limit).offset(@offset) + end + + helper_method :next_page_offset + def next_page_offset + if @objects.respond_to?(:result_offset) and + @objects.respond_to?(:result_limit) and + @objects.respond_to?(:items_available) + next_offset = @objects.result_offset + @objects.result_limit + if next_offset < @objects.items_available + next_offset + else + nil + end end + end - @objects ||= model_class.limit(limit).offset(offset).all + def index + find_objects_for_index if !@objects respond_to do |f| f.json { render json: @objects } f.html { render } @@ -83,7 +116,7 @@ class ApplicationController < ActionController::Base return render_not_found("object not found") end respond_to do |f| - f.json { render json: @object } + f.json { render json: @object.attributes.merge(href: url_for(@object)) } f.html { if request.method == 'GET' render @@ -95,6 +128,28 @@ class ApplicationController < ActionController::Base end end + def choose + params[:limit] ||= 20 + find_objects_for_index if !@objects + respond_to do |f| + if params[:partial] + f.json { + render json: { + content: render_to_string(partial: "choose_rows.html", + formats: [:html], + locals: { + multiple: params[:multiple] + }), + next_page_href: @next_page_href + } + } + end + f.js { + render partial: 'choose', locals: {multiple: params[:multiple]} + } + end + end + def render_content if !@object return render_not_found("object not found") @@ -106,13 +161,21 @@ class ApplicationController < ActionController::Base end def update - updates = params[@object.class.to_s.underscore.singularize.to_sym] - updates.keys.each do |attr| - if @object.send(attr).is_a? Hash and updates[attr].is_a? String - updates[attr] = Oj.load updates[attr] + @updates ||= params[@object.resource_param_name.to_sym] + @updates.keys.each do |attr| + if @object.send(attr).is_a? Hash + if @updates[attr].is_a? String + @updates[attr] = Oj.load @updates[attr] + end + if params[:merge] || params["merge_#{attr}".to_sym] + # Merge provided Hash with current Hash, instead of + # replacing. + @updates[attr] = @object.send(attr).with_indifferent_access. + deep_merge(@updates[attr].with_indifferent_access) + end end end - if @object.update_attributes updates + if @object.update_attributes @updates show else self.render_error status: 422 @@ -120,16 +183,12 @@ class ApplicationController < ActionController::Base end def create - @object ||= model_class.new params[model_class.to_s.underscore.singularize] + @new_resource_attrs ||= params[model_class.to_s.underscore.singularize] + @new_resource_attrs ||= {} + @new_resource_attrs.reject! { |k,v| k.to_s == 'uuid' } + @object ||= model_class.new @new_resource_attrs @object.save! - - respond_to do |f| - f.json { render json: @object } - f.html { - redirect_to(params[:return_to] || @object) - } - f.js { render } - end + show end def destroy @@ -170,17 +229,61 @@ class ApplicationController < ActionController::Base end def show_pane_list - %w(Attributes Metadata JSON API) + %w(Attributes Advanced) end protected - + + def redirect_to_login + respond_to do |f| + f.html { + if request.method == 'GET' + redirect_to arvados_api_client.arvados_login_url(return_to: request.url) + else + flash[:error] = "Either you are not logged in, or your session has timed out. I can't automatically log you in and re-attempt this request." + redirect_to :back + end + } + f.json { + @errors = ['You do not seem to be logged in. You did not supply an API token with this request, and your session (if any) has timed out.'] + self.render_error status: 422 + } + end + false # For convenience to return from callbacks + end + + def using_specific_api_token(api_token) + start_values = {} + [:arvados_api_token, :user].each do |key| + start_values[key] = Thread.current[key] + end + Thread.current[:arvados_api_token] = api_token + Thread.current[:user] = nil + begin + yield + ensure + start_values.each_key { |key| Thread.current[key] = start_values[key] } + end + end + def find_object_by_uuid if params[:id] and params[:id].match /\D/ params[:uuid] = params.delete :id end - if params[:uuid].is_a? String - @object = model_class.find(params[:uuid]) + if not model_class + @object = nil + elsif params[:uuid].is_a? String + if params[:uuid].empty? + @object = nil + else + if (model_class != Link and + resource_class_for_uuid(params[:uuid]) == Link) + @name_link = Link.find(params[:uuid]) + @object = model_class.find(@name_link.head_uuid) + else + @object = model_class.find(params[:uuid]) + end + end else @object = model_class.where(uuid: params[:uuid]).first end @@ -233,20 +336,7 @@ class ApplicationController < ActionController::Base end if try_redirect_to_login unless login_optional - respond_to do |f| - f.html { - if request.method == 'GET' - redirect_to $arvados_api_client.arvados_login_url(return_to: request.url) - else - flash[:error] = "Either you are not logged in, or your session has timed out. I can't automatically log you in and re-attempt this request." - redirect_to :back - end - } - f.json { - @errors = ['You do not seem to be logged in. You did not supply an API token with this request, and your session (if any) has timed out.'] - self.render_error status: 422 - } - end + redirect_to_login else # login is optional for this route so go on to the regular controller Thread.current[:arvados_api_token] = nil @@ -272,7 +362,7 @@ class ApplicationController < ActionController::Base yield else # We skipped thread_with_mandatory_api_token. Use the optional version. - thread_with_api_token(true) do + thread_with_api_token(true) do yield end end @@ -325,7 +415,7 @@ class ApplicationController < ActionController::Base @@notification_tests = [] @@notification_tests.push lambda { |controller, current_user| - AuthorizedKey.limit(1).where(authorized_user_uuid: current_user.uuid).each do + AuthorizedKey.limit(1).where(authorized_user_uuid: current_user.uuid).each do return nil end return lambda { |view| @@ -365,7 +455,7 @@ class ApplicationController < ActionController::Base @notifications = [] if current_user - @showallalerts = false + @showallalerts = false @@notification_tests.each do |t| a = t.call(self, current_user) if a @@ -379,4 +469,30 @@ class ApplicationController < ActionController::Base @notification_count = '' end end + + helper_method :my_folders + def my_folders + return @my_folders if @my_folders + @my_folders = [] + root_of = {} + Group.filter([['group_class','=','folder']]).each do |g| + root_of[g.uuid] = g.owner_uuid + @my_folders << g + end + done = false + while not done + done = true + root_of = root_of.each_with_object({}) do |(child, parent), h| + if root_of[parent] + h[child] = root_of[parent] + done = false + else + h[child] = parent + end + end + end + @my_folders = @my_folders.select do |g| + root_of[g.uuid] == current_user.uuid + end + end end