diff --git a/app/builders/learning_object/draft_builder.rb b/app/builders/learning_object/draft_builder.rb index a28c71efd9b0bbf1ef60ab251f4a2cd0eb949502..cf7fe5b7c594738e8855906b3c3c282d01cb472b 100644 --- a/app/builders/learning_object/draft_builder.rb +++ b/app/builders/learning_object/draft_builder.rb @@ -2,7 +2,7 @@ class LearningObject::DraftBuilder def self.build(publisher, params={}) @draft = LearningObject.new(sanitize_params(params)) - @draft.draft + @draft.draft! #build language @draft.language = Language.find(params[:language]) if params[:language].to_i > 0 diff --git a/app/controllers/concerns/highlights_controller.rb b/app/controllers/concerns/highlights_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..8ff30cc9708b94f44b0708e49596fc406a3d6a37 --- /dev/null +++ b/app/controllers/concerns/highlights_controller.rb @@ -0,0 +1,16 @@ +module HighlightsController + extend ActiveSupport::Concern + + # GET /v1/learning_objects/this_week + # GET /v1/learning_objects/this_week.json + def this_week + render json: highlights_resource.this_week + end + + # GET /v1/learning_objects/this_month + # GET /v1/learning_objects/this_month.json + def this_month + render json: highlights_resource.this_month + end + +end diff --git a/app/controllers/concerns/sociable_controller.rb b/app/controllers/concerns/sociable_controller.rb index 7ef79fed13f8681a39c0641f45a7d8070c8e1324..9ad2d5a95cda8e69cf70391411943abc6dad3b11 100644 --- a/app/controllers/concerns/sociable_controller.rb +++ b/app/controllers/concerns/sociable_controller.rb @@ -7,8 +7,8 @@ module SociableController included do before_action :authenticate_user!, only: [:like, :unlike] + before_action :authorize_sociable!, only: [:like, :unlike] before_action :view_object!, only: VIEWABLE_METHODS - before_action :sociable, only: [:like, :unlike] end # POST /v1/learning_objects/1/like @@ -35,6 +35,14 @@ module SociableController protected + def authorize_sociable! + authorize sociable + end + + def sociable + raise NotImplementedError + end + def view_object! sociable.view current_user if user_signed_in? end diff --git a/app/controllers/v1/activities_controller.rb b/app/controllers/v1/activities_controller.rb index cb6ee583055d3d28ba3ec6616f6ce4a2e4d5dcaf..3de2c8634d1eb13849a314c25e2b5eb7de823377 100644 --- a/app/controllers/v1/activities_controller.rb +++ b/app/controllers/v1/activities_controller.rb @@ -4,20 +4,19 @@ class V1::ActivitiesController < ApplicationController # GET v1/activities # GET v1/activities.json + # Render all activities that logged user can see def index - render json: PublicActivity::Activity.includes(:owner).order('created_at DESC').all + authorize :activity, :index? + render json: ActivitiyPolicy::Scope.new(current_user, PublicActivity::Activity).resolve end # GET v1/users/1/activities # GET v1/users/1/activities.json + # Render specific user activities + # Only followers can see user activities def user_activities - render json: activities(resource_model) + raise Pundit::NotAuthorizedError unless ActivitiyPolicy.new(current_user, resource_model).user_activities? + render json: resource_model.activities end - private - - def activities(object) - condition = '(owner_type = :type AND owner_id = :id) OR (recipient_type = :type AND recipient_id = :id)' - PublicActivity::Activity.order('created_at DESC').where(condition, {type: object.class.to_s, id: object.id}).all - end end diff --git a/app/controllers/v1/collections_controller.rb b/app/controllers/v1/collections_controller.rb index e4a589afd07e3133be3c9fb0c7426292bcf5231d..aefb2a7e6139b63836c97b800fd8e2a8fa99cbb5 100644 --- a/app/controllers/v1/collections_controller.rb +++ b/app/controllers/v1/collections_controller.rb @@ -3,6 +3,7 @@ class V1::CollectionsController < ApplicationController include ::FollowableController include ::TaggableController include ::DeletedObjectsController + include ::HighlightsController before_action :set_collection, only: [:show, :update, :destroy] before_action :authenticate_user!, only: [:create, :update, :destroy] @@ -95,22 +96,13 @@ class V1::CollectionsController < ApplicationController private - def deleted_resource - Collection - end + def deleted_resource; Collection; end + def highlights_resource; Collection; end # social concerns methods - def followable - set_collection - end - - def taggable - set_collection - end - - def sociable - set_collection - end + def followable; set_collection; end + def taggable; set_collection; end + def sociable; set_collection; end def set_collection @collection ||= Collection.find(params[:id]) diff --git a/app/controllers/v1/learning_objects_controller.rb b/app/controllers/v1/learning_objects_controller.rb index 8a33dfb97f870edc710462ec86894fbb6e049609..fd1a803da84b6aa752922a8ddbea0cc823ead5a6 100644 --- a/app/controllers/v1/learning_objects_controller.rb +++ b/app/controllers/v1/learning_objects_controller.rb @@ -5,6 +5,7 @@ class V1::LearningObjectsController < ApplicationController include ::TaggableController include ::Paginator include ::DeletedObjectsController + include ::HighlightsController before_action :authenticate_user!, except: [:index, :show] before_action :set_learning_object, only: [:show, :update, :destroy] @@ -53,17 +54,10 @@ class V1::LearningObjectsController < ApplicationController private - def deleted_resource - LearningObject - end - - def sociable - set_learning_object - end - - def taggable - set_learning_object - end + def deleted_resource; LearningObject; end + def highlights_resource; LearningObject; end + def sociable; set_learning_object; end + def taggable; set_learning_object; end # Use callbacks to share common setup or constraints between actions. def set_learning_object diff --git a/app/controllers/v1/reviews_controller.rb b/app/controllers/v1/reviews_controller.rb index 117e330597400f3847b8e3028f81aed9546ea9ed..992a5e308ee09eaea10b828e1c56ea6dae7d1b08 100644 --- a/app/controllers/v1/reviews_controller.rb +++ b/app/controllers/v1/reviews_controller.rb @@ -1,5 +1,6 @@ class V1::ReviewsController < ApplicationController include ::DeletedObjectsController + include ::ResourceModel before_action :set_review, only: [:show, :destroy, :rate] before_action :authenticate_user!, only: [:create, :rate, :destroy] @@ -79,9 +80,7 @@ class V1::ReviewsController < ApplicationController end def reviewable - resource, id = request.path.split('/')[2, 3] - reviewable_model = resource.singularize.classify.constantize - @reviewable = reviewable_model.find(id) + @reviewable = resource_model end # Never trust parameters from the scary internet, only allow the white list through. diff --git a/app/controllers/v1/users_controller.rb b/app/controllers/v1/users_controller.rb index 9c15b6be117503dad5e5e76923d10f2af01e80c6..d24e649cb34111b2afca7e2030268af7df9992f0 100644 --- a/app/controllers/v1/users_controller.rb +++ b/app/controllers/v1/users_controller.rb @@ -54,11 +54,8 @@ class V1::UsersController < ApplicationController def watching type = params[:object_type] is_current = (@user.id == current_user.id) unless current_user.nil? - - render nothing: true, status: :bad_request unless type.in? %w(User Collection) - + return render nothing: true, status: :bad_request unless type.in? %w(User Collection) w = @user.watching(type, is_current) - render json: w, root: 'follows', status: :ok end diff --git a/app/models/collection.rb b/app/models/collection.rb index c62d6bbd7f6cab5215e609159657d13d2aa72fb8..28c6672ae205bdeaad422660bfbdb750c115e10e 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -30,6 +30,7 @@ class Collection < ActiveRecord::Base include Thumbnailable include Taggable include Trackable + include Highlights has_many :collection_items, as: :collectionable, dependent: :destroy has_many :collections, through: :collection_items, source: :collectionable, source_type: 'Collection' diff --git a/app/models/concerns/highlights.rb b/app/models/concerns/highlights.rb new file mode 100644 index 0000000000000000000000000000000000000000..62a3d5480644ae26a88a5289f44140e583a80930 --- /dev/null +++ b/app/models/concerns/highlights.rb @@ -0,0 +1,9 @@ +module Highlights + extend ActiveSupport::Concern + + included do + scope :this_week, -> (limit = 1000) { where('created_at >= ?', 1.week.ago).order(score: :desc).limit(limit) } + scope :this_month, -> (limit = 1000) { where('created_at >= ?', 1.month.ago).order(score: :desc).limit(limit) } + end + +end \ No newline at end of file diff --git a/app/models/concerns/stateful.rb b/app/models/concerns/stateful.rb index 5ea87856d68674a4b660a9e58f1d2fa225f5f875..7ca2f074779ec9894ee4f4b2166a637ff92daf41 100644 --- a/app/models/concerns/stateful.rb +++ b/app/models/concerns/stateful.rb @@ -2,32 +2,6 @@ module Stateful extend ActiveSupport::Concern included do - # validates with accepted states - validates :state, inclusion: { in: %w(draft published suspended) } + enum state: { draft: 0, published: 1, suspended: 2 } end - - def is_published? - 'published' == state - end - - def is_draft? - 'draft' == state - end - - def publish - self.state = 'published' - end - - def draft - self.state = 'draft' - end - - def suspend - self.state = 'suspended' - end - - def is_suspended? - 'suspended' == state - end - end diff --git a/app/models/learning_object.rb b/app/models/learning_object.rb index cab9c1ed19cc28c288087b2cd7841f55a370f5be..985dd42465d49e8ac33373d92cb465ffe1d844c9 100644 --- a/app/models/learning_object.rb +++ b/app/models/learning_object.rb @@ -1,4 +1,4 @@ -# == Schema Information + # == Schema Information # # Table name: learning_objects # @@ -38,6 +38,7 @@ class LearningObject < ActiveRecord::Base include Scoreable include Thumbnailable include Taggable + include Highlights # *current_user* create learning object # *current_user* update learning object @@ -56,7 +57,7 @@ class LearningObject < ActiveRecord::Base belongs_to :attachment, class_name: 'LearningObject::Attachment' validates_presence_of :name, :publisher, :object_type, :language, :author - validates :id_dspace, presence: true, uniqueness: true, unless: :is_draft? + validates :id_dspace, presence: true, uniqueness: true, unless: :draft? default_scope { includes(:object_type, :attachment, :attachments).order(score: :desc) } scope :missing_thumbnail, ->() { where(thumbnail_file_name: nil) } @@ -136,4 +137,5 @@ class LearningObject < ActiveRecord::Base def user_category publisher.try('user_category') end + end diff --git a/app/models/user.rb b/app/models/user.rb index 20dfb357bf1d3c7e5384aff3a89a9b2a76adbd12..ecfd182636edbbb67ccb4da6b24f65aa3a6e85f7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -138,6 +138,13 @@ class User < ActiveRecord::Base # ~~~~ end followable actions ~~~~ # + ## get all activities from user + # return an array of PublicActivity::Activity + def activities + condition = '(owner_type = :type AND owner_id = :id) OR (recipient_type = :type AND recipient_id = :id)' + PublicActivity::Activity.order('created_at DESC').where(condition, {type: object.class.to_s, id: object.id}).all + end + private def default_role diff --git a/app/policies/activity_policy.rb b/app/policies/activity_policy.rb new file mode 100644 index 0000000000000000000000000000000000000000..4a047168e4dbf5763ad93eaa763cc9f06d7e4d0c --- /dev/null +++ b/app/policies/activity_policy.rb @@ -0,0 +1,28 @@ +class ActivityPolicy < ApplicationPolicy + class Scope < Scope + attr_reader :user, :scope + + def initialize(user, scope) + @user = user + @scope = scope + end + + def resolve + raise StandardError, 'The user must be set.' if user.blank? + if user.is_admin? + scope.includes(:owner).order('created_at DESC').all + else + user.activities + end + end + end + + def index? + true + end + + ## only user followers can see your activities + def user_activities? + record if user.following? record + end +end diff --git a/app/policies/collection_policy.rb b/app/policies/collection_policy.rb index fab8a33a5bcc8c8955e18c4f30939748010215d4..7af04bed7faf340bf08f766264e4d2f783cfcc02 100644 --- a/app/policies/collection_policy.rb +++ b/app/policies/collection_policy.rb @@ -3,7 +3,6 @@ class CollectionPolicy < ApplicationPolicy include FollowablePolicy include TaggablePolicy - class Scope < Scope def initialize (user, user_id, scope) @user = user @@ -24,10 +23,6 @@ class CollectionPolicy < ApplicationPolicy record if user_exists? end - def edit? - record if owns? - end - def show? unless record.private? record diff --git a/app/services/learning_object_publisher.rb b/app/services/learning_object_publisher.rb index d2f99a4e0949f2f61b8be41dde16611779651041..1508c31b71bd4372f06f6e5fa951ce3ea742a995 100644 --- a/app/services/learning_object_publisher.rb +++ b/app/services/learning_object_publisher.rb @@ -15,7 +15,7 @@ class LearningObjectPublisher draft.id_dspace = item.id draft.save - publish! draft if draft.has_url_reference? + publish draft if draft.has_url_reference? return draft end false @@ -28,9 +28,9 @@ class LearningObjectPublisher ## publish *learning_object* # this method will create thumbnails, change state to published and will save it. - def publish!(learning_object) - if learning_object.is_draft? - learning_object.publish + def publish(learning_object) + if learning_object.draft? + learning_object.published! ThumbnailGenerateWorker.perform_async learning_object.id, learning_object.url_reference if learning_object.has_url_reference? end learning_object.save diff --git a/app/workers/dspace_upload_worker.rb b/app/workers/dspace_upload_worker.rb index 4bd64788af10fa0c15b3ca8bb7eb18e3437e68df..463943e242b95a14a91f8539a475faa91c8f3739 100644 --- a/app/workers/dspace_upload_worker.rb +++ b/app/workers/dspace_upload_worker.rb @@ -13,7 +13,7 @@ class DspaceUploadWorker #find learning object learning_object = LearningObject.find learning_object_id attachment = learning_object.attachments.create map_bitstream2attachment(bitstream) - publisher.publish! learning_object + publisher.publish learning_object ThumbnailGenerateWorker.perform_async attachment.id, media_path end diff --git a/config/feature.yml b/config/feature.yml index dbe9c51267072b503500f4dc22e9fadf9754e5f9..b5aa6837a4ad98cc4ae3b1a32159f660f77f09ba 100644 --- a/config/feature.yml +++ b/config/feature.yml @@ -8,4 +8,4 @@ test: production: features: - allow_client_application: true \ No newline at end of file + allow_client_application: false diff --git a/config/routes.rb b/config/routes.rb index 3eb9386fef16c3b71676d6d066d62dd737b61610..4289be952c2bbcdb6672d0af66e5c606415250c7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -37,6 +37,13 @@ Rails.application.routes.draw do end end + concern :highlights do + collection do + get :this_week + get :this_month + end + end + # GET /learning_objects/1/versions/123 # GET /learning_objects/1/versions # POST /learning_objects/1/versions/234/checkout @@ -53,7 +60,7 @@ Rails.application.routes.draw do end namespace :v1 do - get 'feed', to: 'activities#index' + resources :activities, only: :index resources :users, concerns: [:followable, :deletable] do member do @@ -67,8 +74,8 @@ Rails.application.routes.draw do get :search, to: 'search#index' get 'search/autocomplete', to: 'search#autocomplete' - resources :collections, concerns: [:followable, :sociable, :reviewable, :taggable, :versionable, :deletable] - resources :learning_objects, concerns: [:sociable, :reviewable, :taggable, :versionable, :deletable] do + resources :collections, concerns: [:followable, :sociable, :reviewable, :taggable, :versionable, :deletable, :highlights] + resources :learning_objects, concerns: [:sociable, :reviewable, :taggable, :versionable, :deletable, :highlights] do member do resource :chunk, module: 'learning_objects', only: [:create, :show] resource :upload, module: 'learning_objects', only: :create diff --git a/db/migrate/20160519122525_change_state_type_in_learning_objects.rb b/db/migrate/20160519122525_change_state_type_in_learning_objects.rb new file mode 100644 index 0000000000000000000000000000000000000000..134afa90ce9a000c4b9e7b37d5b02ab2a48b2aaa --- /dev/null +++ b/db/migrate/20160519122525_change_state_type_in_learning_objects.rb @@ -0,0 +1,11 @@ +class ChangeStateTypeInLearningObjects < ActiveRecord::Migration + def change + add_column :learning_objects, :statenew, :integer, default: 0 + execute <<-SQL + UPDATE learning_objects set statenew = 1 WHERE state = 'published'; + UPDATE learning_objects set statenew = 2 WHERE state = 'suspended'; + SQL + remove_column :learning_objects, :state + rename_column :learning_objects, :statenew, :state + end +end diff --git a/test/models/collection_test.rb b/test/models/collection_test.rb index 758411c545ad260d9420ec262d722139922ee98b..242f37dbf6ab6b9861e98ca460fce83feb480b72 100644 --- a/test/models/collection_test.rb +++ b/test/models/collection_test.rb @@ -47,6 +47,14 @@ class CollectionTest < ActiveSupport::TestCase include ::Portalmec::SociableTests + test 'should get all collections created this week' do + Collection.this_week.each {|o| assert_instance_of Collection, o} + end + + test 'should get all collections created this month' do + Collection.this_month.each {|o| assert_instance_of Collection, o} + end + protected def sociable_object diff --git a/test/models/learning_object_test.rb b/test/models/learning_object_test.rb index abbf05d0474e49485602b83634260826630ed21e..f2924dc9b678914b0cae67e95fa510379aaef648 100644 --- a/test/models/learning_object_test.rb +++ b/test/models/learning_object_test.rb @@ -56,6 +56,29 @@ class LearningObjectTest < ActiveSupport::TestCase include ::Portalmec::SociableTests + test 'should search data return a hash' do + learning_object = learning_objects(:lo_complete) + assert_equal learning_object.search_data, { + name: 'Institution Object 1', + description: 'Testing', + author: 'Mauricio', + object_type: 'Imagem', + score: learning_object.score, + published_at: learning_object.published_at, + tags: learning_object.tags.map(&:name), + source: nil, + state: learning_object.state + } + end + + test 'should get all learning objects created this week' do + LearningObject.this_week.each {|o| assert_instance_of LearningObject, o} + end + + test 'should get all learning objects created this month' do + LearningObject.this_month.each {|o| assert_instance_of LearningObject, o} + end + protected def sociable_object diff --git a/test/services/search_service_test.rb b/test/services/search_service_test.rb index cd1407ba2b2dfae9ee9f448dec307e3ae412bc85..35c7a30fba49cd3fda4b10335831adb76fcf2d17 100644 --- a/test/services/search_service_test.rb +++ b/test/services/search_service_test.rb @@ -5,14 +5,14 @@ class SearchServiceTest < ActiveSupport::TestCase reindex LearningObject search = SearchService.search(Search.new(los_complete_search), users(:john)) - assert_equal [learning_objects(:search)], search + search.each {|o| assert_instance_of LearningObject, o} end test 'fetch all public collections' do reindex Collection search = SearchService.search(Search.new(collections_search), users(:john)) - assert_equal [collections(:ufpr)], search + search.each {|o| assert_instance_of Collection, o} end test 'fetch users named john' do