Merge branch '2257-inequality-conditions' into 2290-user-activity
[arvados.git] / apps / workbench / app / controllers / application_controller.rb
index 5b8276a9e01f9fca39f22ca60510a88879b82960..6b0492a90f50e3b9dafd312bd0db52c57ac2a6e6 100644 (file)
@@ -1,8 +1,13 @@
 class ApplicationController < ActionController::Base
+  respond_to :html, :json, :js
   protect_from_forgery
   around_filter :thread_clear
-  around_filter :thread_with_api_token, :except => [:render_exception, :render_not_found]
+  around_filter :thread_with_mandatory_api_token, :except => [:render_exception, :render_not_found]
+  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]
+  theme :select_theme
 
   begin
     rescue_from Exception,
@@ -19,14 +24,19 @@ class ApplicationController < ActionController::Base
 
   def unprocessable(message=nil)
     @errors ||= []
+
     @errors << message if message
     render_error status: 422
   end
 
   def render_error(opts)
     respond_to do |f|
-      f.html { render opts.merge(controller: 'application', action: 'error') }
+      # json must come before html here, so it gets used as the
+      # default format when js is requested by the client. This lets
+      # ajax:error callback parse the response correctly, even though
+      # the browser can't.
       f.json { render opts.merge(json: {success: false, errors: @errors}) }
+      f.html { render opts.merge(controller: 'application', action: 'error') }
     end
   end
 
@@ -36,7 +46,7 @@ class ApplicationController < ActionController::Base
     if @object.andand.errors.andand.full_messages.andand.any?
       @errors = @object.errors.full_messages
     else
-      @errors = [e.inspect]
+      @errors = [e.to_s]
     end
     self.render_error status: 422
   end
@@ -47,12 +57,12 @@ class ApplicationController < ActionController::Base
     self.render_error status: 404
   end
 
-
   def index
-    @objects ||= model_class.all
+    @objects ||= model_class.limit(200).all
     respond_to do |f|
       f.json { render json: @objects }
       f.html { render }
+      f.js { render }
     end
   end
 
@@ -69,6 +79,7 @@ class ApplicationController < ActionController::Base
           redirect_to params[:return_to] || @object
         end
       }
+      f.js { render }
     end
   end
 
@@ -97,14 +108,27 @@ class ApplicationController < ActionController::Base
   end
 
   def create
-    @object ||= model_class.new params[model_class.to_s.singularize.to_sym]
+    @object ||= model_class.new params[model_class.to_s.underscore.singularize]
     @object.save!
-    redirect_to(params[:return_to] || @object)
+
+    respond_to do |f|
+      f.json { render json: @object }
+      f.html {
+        redirect_to(params[:return_to] || @object)
+      }
+      f.js { render }
+    end
   end
 
   def destroy
     if @object.destroy
-      redirect_to(params[:return_to] || :back)
+      respond_to do |f|
+        f.json { render json: @object }
+        f.html {
+          redirect_to(params[:return_to] || :back)
+        }
+        f.js { render }
+      end
     else
       self.render_error status: 422
     end
@@ -123,6 +147,20 @@ class ApplicationController < ActionController::Base
     controller_name.classify.constantize
   end
 
+  def breadcrumb_page_name
+    (@breadcrumb_page_name ||
+     (@object.friendly_link_name if @object.respond_to? :friendly_link_name) ||
+     action_name)
+  end
+
+  def index_pane_list
+    %w(Recent)
+  end
+
+  def show_pane_list
+    %w(Attributes Metadata JSON API)
+  end
+
   protected
     
   def find_object_by_uuid
@@ -139,7 +177,9 @@ class ApplicationController < ActionController::Base
   def thread_clear
     Thread.current[:arvados_api_token] = nil
     Thread.current[:user] = nil
+    Rails.cache.delete_matched(/^request_#{Thread.current.object_id}_/)
     yield
+    Rails.cache.delete_matched(/^request_#{Thread.current.object_id}_/)
   end
 
   def thread_with_api_token(login_optional = false)
@@ -207,12 +247,25 @@ class ApplicationController < ActionController::Base
     end
   end
 
-  def thread_with_optional_api_token 
-    thread_with_api_token(true) do 
+  def thread_with_mandatory_api_token
+    thread_with_api_token do
       yield
     end
   end
 
+  # This runs after thread_with_mandatory_api_token in the filter chain.
+  def thread_with_optional_api_token
+    if Thread.current[:arvados_api_token]
+      # We are already inside thread_with_mandatory_api_token.
+      yield
+    else
+      # We skipped thread_with_mandatory_api_token. Use the optional version.
+      thread_with_api_token(true) do 
+        yield
+      end
+    end
+  end
+
   def verify_api_token
     begin
       Link.where(uuid: 'just-verifying-my-api-token')
@@ -228,4 +281,90 @@ class ApplicationController < ActionController::Base
       self.render_error status: 401
     end
   end
+
+  def check_user_agreements
+    if current_user && !current_user.is_active && current_user.is_invited
+      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?
+        # No agreements to sign. Perhaps we just need to ask?
+        current_user.activate
+        if !current_user.is_active
+          logger.warn "#{current_user.uuid.inspect}: " +
+            "No user agreements to sign, but activate failed!"
+        end
+      end
+      if !current_user.is_active
+        render 'user_agreements/index'
+      end
+    end
+    true
+  end
+
+  def select_theme
+    return Rails.configuration.arvados_theme
+  end
+
+  @@notification_tests = []
+
+  @@notification_tests.push lambda { |controller, current_user|
+    AuthorizedKey.limit(1).where(authorized_user_uuid: current_user.uuid).each do   
+      return nil
+    end
+    return lambda { |view|
+      view.render partial: 'notifications/ssh_key_notification'
+    }
+  }
+
+  #@@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
+    end
+    return lambda { |view|
+      view.render partial: 'notifications/collections_notification'
+    }
+  }
+
+  @@notification_tests.push lambda { |controller, current_user|
+    PipelineInstance.limit(1).where(created_by: current_user.uuid).each do
+      return nil
+    end
+    return lambda { |view|
+      view.render partial: 'notifications/pipelines_notification'
+    }
+  }
+
+  def check_user_notifications
+    @notification_count = 0
+    @notifications = []
+
+    if current_user
+      @showallalerts = false      
+      @@notification_tests.each do |t|
+        a = t.call(self, current_user)
+        if a
+          @notification_count += 1
+          @notifications.push a
+        end
+      end
+    end
+
+    if @notification_count == 0
+      @notification_count = ''
+    end
+  end
 end