diff --git a/app/controllers/v1/omniauth_callbacks_controller.rb b/app/controllers/v1/omniauth_callbacks_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4bffba452e309a0916576aae140a5d7e07f0d6fb
--- /dev/null
+++ b/app/controllers/v1/omniauth_callbacks_controller.rb
@@ -0,0 +1,254 @@
+  class V1::OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
+
+    attr_reader :auth_params
+    skip_before_action :set_user_by_token, raise: false
+    skip_after_action :update_auth_header
+
+    # intermediary route for successful omniauth authentication. omniauth does
+    # not support multiple models, so we must resort to this terrible hack.
+    def redirect_callbacks
+
+      # derive target redirect route from 'resource_class' param, which was set
+      # before authentication.
+      devise_mapping = [request.env['omniauth.params']['namespace_name'],
+                        request.env['omniauth.params']['resource_class'].underscore.gsub('/', '_')].compact.join('_')
+      redirect_route = "#{request.protocol}#{request.host_with_port}/#{Devise.mappings[devise_mapping.to_sym].fullpath}/#{params[:provider]}/callback"
+
+      # preserve omniauth info for success route. ignore 'extra' in twitter
+      # auth response to avoid CookieOverflow.
+      session['dta.omniauth.auth'] = request.env['omniauth.auth'].except('extra')
+      session['dta.omniauth.params'] = request.env['omniauth.params']
+
+      redirect_to redirect_route
+    end
+
+    def omniauth_success
+      get_resource_from_auth_hash
+      create_token_info
+      set_token_on_resource
+      create_auth_params
+
+      if resource_class.devise_modules.include?(:confirmable)
+        # don't send confirmation email!!!
+        @resource.skip_confirmation!
+      end
+
+      sign_in(:user, @resource, store: false, bypass: false)
+
+      @resource.save!
+
+      yield @resource if block_given?
+
+      render_data_or_redirect('deliverCredentials', @auth_params.as_json, @resource.as_json)
+    end
+
+    def omniauth_failure
+      @error = params[:message]
+      render_data_or_redirect('authFailure', {error: @error})
+    end
+
+    protected
+
+    # this will be determined differently depending on the action that calls
+    # it. redirect_callbacks is called upon returning from successful omniauth
+    # authentication, and the target params live in an omniauth-specific
+    # request.env variable. this variable is then persisted thru the redirect
+    # using our own dta.omniauth.params session var. the omniauth_success
+    # method will access that session var and then destroy it immediately
+    # after use.  In the failure case, finally, the omniauth params
+    # are added as query params in our monkey patch to OmniAuth in engine.rb
+    def omniauth_params
+      if !defined?(@_omniauth_params)
+        if request.env['omniauth.params'] && request.env['omniauth.params'].any?
+          @_omniauth_params = request.env['omniauth.params']
+        elsif session['dta.omniauth.params'] && session['dta.omniauth.params'].any?
+          @_omniauth_params ||= session.delete('dta.omniauth.params')
+          @_omniauth_params
+        elsif params['omniauth_window_type']
+          @_omniauth_params = params.slice('omniauth_window_type', 'auth_origin_url', 'resource_class', 'origin')
+        else
+          @_omniauth_params = {}
+        end
+      end
+      @_omniauth_params
+
+    end
+
+    # break out provider attribute assignment for easy method extension
+    def assign_provider_attrs(user, auth_hash)
+      user.assign_attributes({
+        nickname: auth_hash['info']['nickname'],
+        name:     auth_hash['info']['name'],
+        avatar:   auth_hash['info']['image'],
+        email:    auth_hash['info']['email']
+      })
+    end
+
+    # derive allowed params from the standard devise parameter sanitizer
+    def whitelisted_params
+      whitelist = params_for_resource(:sign_up)
+
+      whitelist.inject({}){|coll, key|
+        param = omniauth_params[key.to_s]
+        if param
+          coll[key] = param
+        end
+        coll
+      }
+    end
+
+    def resource_class(mapping = nil)
+      if omniauth_params['resource_class']
+        omniauth_params['resource_class'].constantize
+      elsif params['resource_class']
+        params['resource_class'].constantize
+      else
+        raise "No resource_class found"
+      end
+    end
+
+    def resource_name
+      resource_class
+    end
+
+    def omniauth_window_type
+      omniauth_params['omniauth_window_type']
+    end
+
+    def auth_origin_url
+      omniauth_params['auth_origin_url'] || omniauth_params['origin']
+    end
+
+    # in the success case, omniauth_window_type is in the omniauth_params.
+    # in the failure case, it is in a query param.  See monkey patch above
+    def omniauth_window_type
+      omniauth_params.nil? ? params['omniauth_window_type'] : omniauth_params['omniauth_window_type']
+    end
+
+    # this sesison value is set by the redirect_callbacks method. its purpose
+    # is to persist the omniauth auth hash value thru a redirect. the value
+    # must be destroyed immediatly after it is accessed by omniauth_success
+    def auth_hash
+      @_auth_hash ||= session.delete('dta.omniauth.auth')
+      @_auth_hash
+    end
+
+    # ensure that this controller responds to :devise_controller? conditionals.
+    # this is used primarily for access to the parameter sanitizers.
+    def assert_is_devise_resource!
+      true
+    end
+
+    # necessary for access to devise_parameter_sanitizers
+    def devise_mapping
+      if omniauth_params
+        Devise.mappings[[omniauth_params['namespace_name'],
+                         omniauth_params['resource_class'].underscore].compact.join('_').to_sym]
+      else
+        request.env['devise.mapping']
+      end
+    end
+
+    def set_random_password
+      # set crazy password for new oauth users. this is only used to prevent
+        # access via email sign-in.
+        p = SecureRandom.urlsafe_base64(nil, false)
+        @resource.password = p
+        @resource.password_confirmation = p
+    end
+
+    def create_token_info
+      # create token info
+      @client_id = SecureRandom.urlsafe_base64(nil, false)
+      @token     = SecureRandom.urlsafe_base64(nil, false)
+      @expiry    = (Time.now + DeviseTokenAuth.token_lifespan).to_i
+      @config    = omniauth_params['config_name']
+    end
+
+    def create_auth_params
+      @auth_params = {
+        auth_token:     @token,
+        client_id: @client_id,
+        uid:       @resource.uid,
+        expiry:    @expiry,
+        config:    @config
+      }
+      @auth_params.merge!(oauth_registration: true) if @oauth_registration
+      @auth_params
+    end
+
+    def set_token_on_resource
+      @resource.tokens[@client_id] = {
+        token: BCrypt::Password.create(@token),
+        expiry: @expiry
+      }
+    end
+
+    def render_data(message, data)
+      @data = data.merge({
+        message: message
+      })
+      render :layout => nil, :template => "devise_token_auth/omniauth_external_window"
+    end
+
+    def render_data_or_redirect(message, data, user_data = {})
+
+      # We handle inAppBrowser and newWindow the same, but it is nice
+      # to support values in case people need custom implementations for each case
+      # (For example, nbrustein does not allow new users to be created if logging in with
+      # an inAppBrowser)
+      #
+      # See app/views/devise_token_auth/omniauth_external_window.html.erb to understand
+      # why we can handle these both the same.  The view is setup to handle both cases
+      # at the same time.
+      if ['inAppBrowser', 'newWindow'].include?(omniauth_window_type)
+        render_data(message, user_data.merge(data))
+
+      elsif auth_origin_url # default to same-window implementation, which forwards back to auth_origin_url
+
+        # build and redirect to destination url
+        redirect_to DeviseTokenAuth::Url.generate(auth_origin_url, data.merge(blank: true))
+      else
+
+        # there SHOULD always be an auth_origin_url, but if someone does something silly
+        # like coming straight to this url or refreshing the page at the wrong time, there may not be one.
+        # In that case, just render in plain text the error message if there is one or otherwise
+        # a generic message.
+        fallback_render data[:error] || 'An error occurred'
+      end
+    end
+
+    def fallback_render(text)
+        render inline: %Q|
+
+            <html>
+                    <head></head>
+                    <body>
+                            #{text}
+                    </body>
+            </html>|
+    end
+
+    def get_resource_from_auth_hash
+      # find or create user by provider and provider uid
+      @resource = resource_class.where({
+        uid:      auth_hash['uid'],
+        provider: auth_hash['provider']
+      }).first_or_initialize
+
+      if @resource.new_record?
+        @oauth_registration = true
+        set_random_password
+      end
+
+      # sync user info with provider, update/generate auth token
+      assign_provider_attrs(@resource, auth_hash)
+
+      # assign any additional (whitelisted) attributes
+      extra_params = whitelisted_params
+      @resource.assign_attributes(extra_params) if extra_params
+
+      @resource
+    end
+
+  end
diff --git a/app/models/collection.rb b/app/models/collection.rb
index 54212efb4ecf76278f3e6d93dd9c8bb1e090392b..f3b7f2745949ffd7685e585600c73272172b3165 100644
--- a/app/models/collection.rb
+++ b/app/models/collection.rb
@@ -65,7 +65,8 @@ class Collection < ApplicationRecord
       created_at: created_at,
       likes: likes_count,
       downloads: downloads_count,
-      review_average: review_ratings_average
+      review_average: review_ratings_average,
+      empty: collection_items.empty?
     }
   end
 
diff --git a/app/services/search_service/collection.rb b/app/services/search_service/collection.rb
index c6f805616be02c01391a98b623f62e0aba342bfc..5bd29469709d51634c3d8489b27f653afed1edd1 100644
--- a/app/services/search_service/collection.rb
+++ b/app/services/search_service/collection.rb
@@ -26,6 +26,7 @@ module SearchService
       filter << { in: { tags: @search.tags } } unless @search.tags.blank?
       filter << { in: { subjects: @search.subjects } } unless @search.subjects.blank?
       filter << { in: { educational_stages: @search.educational_stages } } unless @search.educational_stages.blank?
+      filter << { terms: { empty: show_empty } }
       filter
     end
 
@@ -40,5 +41,11 @@ module SearchService
       when 'review_average' then { review_average: { order: :desc } }
       end
     end
+
+    def show_empty
+      return [true,false] if !@user.nil? && @user.is_admin?
+      [false]
+    end
+
   end
 end
diff --git a/app/services/search_service/learning_object.rb b/app/services/search_service/learning_object.rb
index ebd525e6335b141e4f75c47c9513937f5c575da3..bff63f89f5d272e4c242eab493cea34bac8e619f 100644
--- a/app/services/search_service/learning_object.rb
+++ b/app/services/search_service/learning_object.rb
@@ -27,7 +27,7 @@ module SearchService
       filter << { in: { subjects: @search.subjects } } unless @search.subjects.blank?
       filter << { in: { educational_stages: @search.educational_stages } } unless @search.educational_stages.blank?
       filter << { in: { object_type: @search.object_types.map(&:to_i) } } unless @search.object_types.blank?
-      filter << { term: { state: validate_object } }
+      filter << { terms: { state: validate_object } }
       filter
     end
 
@@ -44,7 +44,7 @@ module SearchService
     end
 
     def validate_object
-      return ::LearningObject.states[:published] unless !@user.nil? && @user.is_admin?
+      return [::LearningObject.states[:published]] unless !@user.nil? && @user.is_admin?
       ::LearningObject.states.values
     end
   end
diff --git a/app/services/search_service/model.rb b/app/services/search_service/model.rb
index 632825a4fb309a5f1fc45aaafc861284777ecbe1..eda8a5d6e734389b82930cd87790fab5ba1354f8 100644
--- a/app/services/search_service/model.rb
+++ b/app/services/search_service/model.rb
@@ -37,8 +37,13 @@ module SearchService
     end
 
     def mount_query
-      # TODO: match_all don't work with filter, fix when possible
-      return { "match_all": {} } if @search.query == "*"
+      match_all_query = {
+        filtered:{
+          query: { match_all: {} },
+          filter: mount_filter
+        }
+      }
+      return match_all_query if @search.query == "*"
 
       {
         function_score: {
diff --git a/app/workers/attachment_cache_worker.rb b/app/workers/attachment_cache_worker.rb
index 248337bdde8d43bb9b6d5cafd512240fd78b2e73..5e8bb82d87587fa994e28a5faada9e5a57603d9e 100644
--- a/app/workers/attachment_cache_worker.rb
+++ b/app/workers/attachment_cache_worker.rb
@@ -18,6 +18,7 @@ class AttachmentCacheWorker
       FileUtils.mkdir_p(directory_root)
       FileUtils.mv(file.path, file_root)
       FileUtils.chmod 0644, file_root.to_s, verbose: true
+      FileUtils.chown_R 'portalmec', 'www-data', directory_root.to_s, verbose: true
       @attachment.update(cache_link: cache_link)
     ensure
       file.close if !file.nil? && File.exist?(file.path)
diff --git a/config/initializers/devise_token_auth.rb b/config/initializers/devise_token_auth.rb
index ba76d510ae984c0236119db596223b166f04a930..13b395649a738df1c0c4b0eb19fe5a41a6622f2a 100644
--- a/config/initializers/devise_token_auth.rb
+++ b/config/initializers/devise_token_auth.rb
@@ -22,7 +22,7 @@ DeviseTokenAuth.setup do |config|
   # This route will be the prefix for all oauth2 redirect callbacks. For
   # example, using the default '/omniauth', the github oauth2 provider will
   # redirect successful authentications to '/omniauth/github/callback'
-  # config.omniauth_prefix = "/omniauth"
+  config.omniauth_prefix = "/omniauth"
 
   # By default sending current password is not needed for the password update.
   # Uncomment to enforce current_password param to be checked before all
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb
index 8863174a07d6df1a886558eb45f381b4b5c120be..1ed6c505fd34e364209e98ed848648c6a99bb98e 100644
--- a/config/initializers/omniauth.rb
+++ b/config/initializers/omniauth.rb
@@ -1,5 +1,5 @@
 Rails.application.config.middleware.use OmniAuth::Builder do
   provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
-  provider :facebook,      ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
+  provider :facebook,      ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], secure_image_url: true
   provider :google_oauth2, ENV['GOOGLE_KEY'],   ENV['GOOGLE_SECRET']
 end
diff --git a/config/routes.rb b/config/routes.rb
index 10df93354e6cb9993ede0ede3a34635f62a5e4a1..e96849f41e0a794ed060653cca0145c9f308d5e9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -74,7 +74,9 @@ Rails.application.routes.draw do
   end
 
   scope :v1 do
-    mount_devise_token_auth_for 'User', at: 'auth'
+    mount_devise_token_auth_for 'User', at: 'auth', controllers: {
+      omniauth_callbacks: 'v1/omniauth_callbacks'
+    }
   end
 
   namespace :v1 do
diff --git a/lib/tasks/attachment_maintaining_service.rake b/lib/tasks/attachment_maintaining_service.rake
index 6587edd4c8c5d01ee8f47c379fdbe34b4b06925d..13e3f6a29bccc88b0a2d3d09cb075d2edb5a5852 100644
--- a/lib/tasks/attachment_maintaining_service.rake
+++ b/lib/tasks/attachment_maintaining_service.rake
@@ -1,25 +1,26 @@
 require 'fileutils'
 
   namespace :attachment_maintaining_service do
-    desc 'Removing 10 attachments'
-    task remove_attachments: :environment do
-      m = sort_directories.first(10)
-      m.each do |mm|
-        #puts (mm)
-        FileUtils.rm_r(mm)
-      end
-    end
 
-    def sort_directories
-      files_sorted_by_time = Dir[dir_path].sort_by{ |f| File.atime(f) }
-      files_sorted_by_time
+    desc 'Removing attachments using random politic'
+    task :remove_attachments, [:limit] => :environment do |t, args|
+      args.with_defaults(limit: 10.gigabyte)
+      attachments_dir = attachment_dir + "/*"
+
+      while dir_size(attachment_dir) > args.limit.to_i do
+        # TODO now the politic is random, verify if politics like LRU or NRU improve the efficiency
+        FileUtils.rm_r Dir[attachments_dir].sample
+      end
     end
 
     private
 
-    def dir_path
-      c = Rails.root.join('public','attachments','*').to_s
-      c
+    def dir_size(dir)
+      `du -sb #{dir} | cut -f 1`.to_i
+    end
+
+    def attachment_dir
+      Rails.root.join('public','attachments').to_s
     end
 
   end
diff --git a/spec/controllers/v1/omniauth_callbacks_controller_spec.rb b/spec/controllers/v1/omniauth_callbacks_controller_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a7bb409edcb96cebfd6491d500b11824d5a06f11
--- /dev/null
+++ b/spec/controllers/v1/omniauth_callbacks_controller_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe V1::OmniauthCallbacksController, type: :controller do
+
+end