Merge branch 'master' into 4025-move-project-button-label
[arvados.git] / apps / workbench / app / controllers / application_controller.rb
index 8883e820aae4bcf925c2f55d7d63169bdd191cbb..0313111ab9e1f34e75b530b396846111fcc9f568 100644 (file)
@@ -14,10 +14,10 @@ class ApplicationController < ActionController::Base
   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: [:update_profile] + 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
+  before_filter :find_object_by_uuid, except: [:create, :index, :choose] + ERROR_ACTIONS
   theme :select_theme
 
   begin
@@ -128,6 +128,8 @@ class ApplicationController < ActionController::Base
           end
         end
       end
+      # After this, params[:filters] can be trusted to be an array of arrays:
+      params[:filters] = filters
       @filters += filters
     end
   end
@@ -202,10 +204,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_markup(@object.attributes[textile_attr]) })
+        end
+        render json: @object.attributes.merge(extra_attrs)
+      end
       f.html {
         if params['tab_pane']
-          render_pane params['tab_pane']
+          render_pane(if params['tab_pane'].is_a? Hash then params['tab_pane']["name"] else params['tab_pane'] end)
         elsif request.method.in? ['GET', 'HEAD']
           render
         else
@@ -218,10 +226,10 @@ class ApplicationController < ActionController::Base
 
   def choose
     params[:limit] ||= 40
-    find_objects_for_index if !@objects
     respond_to do |f|
       if params[:partial]
         f.json {
+          find_objects_for_index if !@objects
           render json: {
             content: render_to_string(partial: "choose_rows.html",
                                       formats: [:html]),
@@ -230,6 +238,7 @@ class ApplicationController < ActionController::Base
         }
       end
       f.js {
+        find_objects_for_index if !@objects
         render partial: 'choose', locals: {multiple: params[:multiple]}
       }
     end
@@ -274,7 +283,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
         }
@@ -436,6 +445,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,
@@ -501,7 +514,7 @@ class ApplicationController < ActionController::Base
       session.delete :arvados_api_token
       redirect_to_login
     else
-      redirect_to welcome_users_path, return_to: request.fullpath
+      redirect_to welcome_users_path(return_to: request.fullpath)
     end
   end
 
@@ -512,19 +525,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 redirect_to inactive_users_path, return_to: request.fullpath
+        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
@@ -533,7 +549,7 @@ class ApplicationController < ActionController::Base
         end
       end
       if !current_user.is_active
-        redirect_to user_agreements_path, return_to: request.fullpath
+        redirect_to user_agreements_path(return_to: request.fullpath)
       end
     end
     true
@@ -547,7 +563,7 @@ class ApplicationController < ActionController::Base
     end
 
     if missing_required_profile?
-      render 'users/profile'
+      redirect_to profile_user_path(current_user.uuid, return_to: request.fullpath)
     end
     true
   end
@@ -589,15 +605,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
@@ -622,7 +629,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)
@@ -685,6 +692,50 @@ class ApplicationController < ActionController::Base
     end.reverse
   end
 
+  helper_method :running_pipelines
+  def running_pipelines
+    pi = PipelineInstance.order(["started_at asc", "created_at asc"]).filter([["state", "in", ["RunningOnServer", "RunningOnClient"]]])
+    jobs = {}
+    pi.each do |pl|
+      pl.components.each do |k,v|
+        if v.is_a? Hash and v[:job]
+          jobs[v[:job][:uuid]] = {}
+        end
+      end
+    end
+
+    if jobs.keys.any?
+      Job.filter([["uuid", "in", jobs.keys]]).each do |j|
+        jobs[j[:uuid]] = j
+      end
+
+      pi.each do |pl|
+        pl.components.each do |k,v|
+          if v.is_a? Hash and v[:job]
+            v[:job] = jobs[v[:job][:uuid]]
+          end
+        end
+      end
+    end
+
+    pi
+  end
+
+  helper_method :finished_pipelines
+  def finished_pipelines lim
+    PipelineInstance.limit(lim).order(["finished_at desc"]).filter([["state", "in", ["Complete", "Failed", "Paused"]], ["finished_at", "!=", nil]])
+  end
+
+  helper_method :recent_collections
+  def recent_collections lim
+    c = Collection.limit(lim).order(["modified_at desc"]).filter([["owner_uuid", "is_a", "arvados#group"]])
+    own = {}
+    Group.filter([["uuid", "in", c.map(&:owner_uuid)]]).each do |g|
+      own[g[:uuid]] = g
+    end
+    {collections: c, owners: own}
+  end
+
   helper_method :my_project_tree
   def my_project_tree
     build_project_trees
@@ -732,7 +783,7 @@ class ApplicationController < ActionController::Base
     @my_project_tree =
       sorted_paths.call buildtree.call(children_of, 'me')
     @shared_project_tree =
-      sorted_paths.call({'Shared with me' =>
+      sorted_paths.call({'Projects shared with me' =>
                           buildtree.call(children_of, false)})
   end