Merge branch 'master' into 3296-user-profile
[arvados.git] / apps / workbench / app / controllers / application_controller.rb
index ea460912df44b828fd4f369170400215bdab38d5..222888085d9e3bb95973f2a2865c3efbb569b7f5 100644 (file)
@@ -12,8 +12,11 @@ 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: [:update_profile] + 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
   theme :select_theme
 
@@ -86,7 +89,10 @@ class ApplicationController < ActionController::Base
     end
   end
 
-  def find_objects_for_index
+  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
@@ -102,10 +108,22 @@ class ApplicationController < ActionController::Base
       filters = params[:filters]
       if filters.is_a? String
         filters = Oj.load filters
+      elsif filters.is_a? Array
+        filters = filters.collect do |filter|
+          if filter.is_a? String
+            # Accept filters[]=["foo","=","bar"]
+            Oj.load filter
+          else
+            # Accept filters=[["foo","=","bar"]]
+            filter
+          end
+        end
       end
       @filters += filters
     end
+  end
 
+  def find_objects_for_index
     @objects ||= model_class
     @objects = @objects.filter(@filters).limit(@limit).offset(@offset)
   end
@@ -114,10 +132,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
@@ -126,6 +142,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
@@ -148,6 +181,13 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  helper_method :next_page_href
+  def next_page_href with_params={}
+    if next_page_offset
+      url_for with_params.merge(offset: next_page_offset)
+    end
+  end
+
   def show
     if !@object
       return render_not_found("object not found")
@@ -156,9 +196,7 @@ class ApplicationController < ActionController::Base
       f.json { render json: @object.attributes.merge(href: url_for(@object)) }
       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
@@ -171,26 +209,14 @@ class ApplicationController < ActionController::Base
 
   def choose
     params[:limit] ||= 40
-    if !@objects
-      if params[:project_uuid] and !params[:project_uuid].empty?
-        # We want the chooser to show objects of the controllers's model_class
-        # type within a specific project specified by project_uuid, so fetch the
-        # project and request the contents of the project filtered on the
-        # controllers's model_class kind.
-        @objects = Group.find(params[:project_uuid]).contents({:filters => [['uuid', 'is_a', "arvados\##{ArvadosApiClient.class_kind(model_class)}"]]})
-      end
-      find_objects_for_index if !@objects
-    end
+    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
+                                      formats: [:html]),
+            next_page_href: next_page_href(partial: params[:partial])
           }
         }
       end
@@ -261,7 +287,7 @@ class ApplicationController < ActionController::Base
       if @object.name and @object.name != ''
         @object.name = "Copy of #{@object.name}"
       else
-        @object.name = "Copy of unnamed #{@object.class_for_display.downcase}"
+        @object.name = ""
       end
     end
     @object.save!
@@ -341,10 +367,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
@@ -380,9 +410,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
@@ -400,15 +427,7 @@ 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]
-      session[:user] = {
-        uuid: user.uuid,
-        email: user.email,
-        first_name: user.first_name,
-        last_name: user.last_name,
-        is_active: user.is_active,
-        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
@@ -502,6 +521,41 @@ class ApplicationController < ActionController::Base
     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?
+      render 'users/profile'
+    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
@@ -569,7 +623,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
@@ -609,8 +663,8 @@ class ApplicationController < ActionController::Base
     (Job.limit(10) |
      PipelineInstance.limit(10)).
       sort_by do |x|
-      x.finished_at || x.started_at || x.created_at rescue x.created_at
-    end
+      (x.finished_at || x.started_at rescue nil) || x.modified_at || x.created_at
+    end.reverse
   end
 
   helper_method :my_project_tree
@@ -680,7 +734,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
@@ -694,7 +748,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
@@ -872,4 +926,7 @@ class ApplicationController < ActionController::Base
     @objects_for
   end
 
+  def wiselinks_layout
+    'body'
+  end
 end