diff --git a/app/controllers/concerns/publisher_controller.rb b/app/controllers/concerns/publisher_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..06721e300000d4d8726a1468af5facca5eb7343a --- /dev/null +++ b/app/controllers/concerns/publisher_controller.rb @@ -0,0 +1,36 @@ +module PublisherController + extend ActiveSupport::Concern + + # GET /v1/users/1/learning_objects + def show_all_learning_objects + render json: LearningObject.where(publisher: publisher) + end + + def show_all_collections + render json: Collection.where(owner: publisher) + end + + def show_liked_learning_objects + includes = [:taggings, :tags, :subject_relations, :subjects, :stage_relations, :educational_stages, :publisher, :language, :license] + render json: LearningObject.includes(includes).find( + Like.where(user: publisher, likeable_type: 'LearningObject').pluck(:likeable_id) + ) + end + + def show_liked_collections + render json: Collection.find( + Like.where(user: publisher, likeable_type: 'Collection').pluck(:likeable_id) + ) + end + + protected + + def publisher + user, id = request.path.split('/')[2, 3] + return nil unless %w(users institutions).include? user + publisher_model = user.singularize.classify.constantize + publisher = publisher_model.find(id) + authorize publisher + publisher + end +end diff --git a/app/controllers/v1/users_controller.rb b/app/controllers/v1/users_controller.rb index 4f71bdb81dc07159e433bb954a1aa3c18bba94a3..e8e2408bb9b3fe9a0eb4fd6978cdf882c786f979 100644 --- a/app/controllers/v1/users_controller.rb +++ b/app/controllers/v1/users_controller.rb @@ -2,10 +2,11 @@ class V1::UsersController < ApplicationController include ::FollowableController include ::DeletedObjectsController include ::Paginator + include ::PublisherController - - before_action :set_user, only: [:show, :update, :destroy, :following] - before_action :authenticate_user!, only: [:create, :update, :destroy, :following] + before_action :set_user, only: [:show, :update, :destroy, :following, :own_reviews, :received_reviews] + before_action :authenticate_user!, only: [:create, :update, :destroy, :following, :own_reviews, :received_reviews] + before_action :authorize_user, only: [:own_reviews, :received_reviews] # GET /v1/users # GET /v1/users.json @@ -30,7 +31,6 @@ class V1::UsersController < ApplicationController else render json: user.errors, status: :unprocessable_entity end - end # PUT/PATCH /v1/users/1 @@ -62,6 +62,14 @@ class V1::UsersController < ApplicationController render json: w, root: 'follows', status: :ok end + def own_reviews + render json: @user.own_reviews + end + + def received_reviews + render json: @user.received_reviews + end + private def deleted_resource @@ -72,6 +80,10 @@ class V1::UsersController < ApplicationController set_user end + def authorize_user + authorize @user + end + def set_user @user = User.find(params[:id]) end diff --git a/app/models/concerns/publisher.rb b/app/models/concerns/publisher.rb new file mode 100644 index 0000000000000000000000000000000000000000..80d91408afd655f035e6058b7644da601e168c30 --- /dev/null +++ b/app/models/concerns/publisher.rb @@ -0,0 +1,9 @@ +module Publisher + extend ActiveSupport::Concern + + included do + has_many :learning_objects, as: :publisher + has_many :collections, as: :owner + end + +end diff --git a/app/models/institution.rb b/app/models/institution.rb index 3d04651fd1a6409c97b56093ccc2bd3d4a83788a..45a283350e02c5ba95fc64a7719a99d999954026 100644 --- a/app/models/institution.rb +++ b/app/models/institution.rb @@ -14,16 +14,12 @@ class Institution < ApplicationRecord include Tagger - - # *current_user* add member for instituion *name* - # *current_user* create instituion - # *current_user* destroy instituion - # *current_user* update instituion include Trackable + include Publisher has_and_belongs_to_many :users - has_many :learning_objects, as: :publisher - has_many :collections, as: :owner + #has_many :learning_objects, as: :publisher + #has_many :collections, as: :owner validates_presence_of :name diff --git a/app/models/user.rb b/app/models/user.rb index 4a3ae3ff4899ed16653b7520b7eb1301ae753913..c5c74d9aa8d7b9a7159c15db6ac6456fb335156f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -39,6 +39,7 @@ class User < ApplicationRecord include Reputationable include Tagger include Complainable + include Publisher # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable @@ -55,8 +56,8 @@ class User < ApplicationRecord has_many :bookmark_collections, through: :bookmarks, source: :bookmarkable, source_type: 'Collection' has_many :bookmark_learning_objects, through: :bookmarks, source: :bookmarkable, source_type: 'LearningObject' has_many :bookmarks - has_many :collections, as: :owner - has_many :learning_objects, as: :publisher + #has_many :collections, as: :owner + #has_many :learning_objects, as: :publisher has_many :views has_many :downloads has_many :likes @@ -104,6 +105,16 @@ class User < ApplicationRecord lo end + def own_reviews + Review.where(user_id: id) + end + + def received_reviews + Review.joins('INNER JOIN learning_objects ON ' \ + "learning_objects.publisher_id = #{id} AND " \ + 'reviews.reviewable_id = learning_objects.id') + end + # ~~~~ followable actions ~~~~ # # An user can follow anothers users and collections # Examples: diff --git a/app/policies/publisher_policy.rb b/app/policies/publisher_policy.rb new file mode 100644 index 0000000000000000000000000000000000000000..203b7f3c284e0ba04b934d3aef15aef3bffcda3a --- /dev/null +++ b/app/policies/publisher_policy.rb @@ -0,0 +1,21 @@ +module PublisherPolicy + def show_all_learning_objects? + record if same_user? || user.is_admin? + end + + def show_all_collections? + record if same_user? || user.is_admin? + end + + def show_liked_learning_objects? + record if same_user? || user.is_admin? + end + + def show_liked_collections? + record if same_user? || user.is_admin? + end + + def same_user? + record == user + end +end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index 22f65f2ea1aaca9eba75a8506f7f5c375e3ffc4e..424a0a68dc7e2304daffce0daeed2326de355843 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -1,5 +1,6 @@ class UserPolicy < ApplicationPolicy include FollowablePolicy + include PublisherPolicy def create? user.is_admin? @@ -9,4 +10,15 @@ class UserPolicy < ApplicationPolicy record if user_exists? end + def own_reviews? + record if same_user? || user.is_admin? + end + + def received_reviews? + record if same_user? || user.is_admin? + end + + def same_user? + record == user + end end diff --git a/app/serializers/learning_object_serializer.rb b/app/serializers/learning_object_serializer.rb index 119909be70e535358205a78012c40355b00bcf36..244635101daf8ab4e0b2b041c5f3f6e8738e19a5 100644 --- a/app/serializers/learning_object_serializer.rb +++ b/app/serializers/learning_object_serializer.rb @@ -2,7 +2,7 @@ class LearningObjectSerializer < ActiveModel::Serializer cache key: 'learning_object', expires_in: 4.hours def default_location - object.default_attachment.try(:retrieve_url) + object_type == ("VÃdeo" || "Ãudio") ? object.default_attachment.try(:retrieve_cache_link) : object.default_attachment.try(:retrieve_url) end def default_mime_type diff --git a/app/services/score_calculator_service.rb b/app/services/score_calculator_service.rb index b56ad74e83b9a71fd73408e6593b544ab434e666..7cfe477976fe925b08fa9edfd3a46997a25a8791 100644 --- a/app/services/score_calculator_service.rb +++ b/app/services/score_calculator_service.rb @@ -9,19 +9,7 @@ class ScoreCalculatorService values = object_hash if values.nil? values = values.with_indifferent_access - sum = 0 - - if @object.is_a?(User) - Score.object_type(@object.class.name).find_each do |score| - max = score.max_value.to_f - - next if max == 0 - - sum += (values[score.code].to_f / max) * score.weight.to_f - end - else - Score.object_type(@object.class.name).find_each { |score| sum += values[score.code].to_f * score.weight.to_f } - end + sum = @object.is_a?(User) ? calculate_user(values) : calculate_object(values) @value = (sum.to_f / sum_weights.to_f).round(6) end @@ -42,7 +30,25 @@ class ScoreCalculatorService end def sum_weights - Score.object_type(@object.class.name).pluck(:weight).inject(0.0) { |a, e| a + e } + Score.object_type(@object.class.name).pluck(:weight).inject(0.0) { |acc, elem| acc + elem } + end + + def calculate_user(values) + sum = 0.0 + Score.object_type(@object.class.name).find_each do |score| + max = score.max_value.to_f + next if max.zero? + + sum += (values[score.code].to_f / max) * score.weight.to_f + end + sum end + def calculate_object(values) + sum = 0.0 + Score.object_type(@object.class.name).find_each do |score| + sum += values[score.code].to_f * score.weight.to_f + end + sum + end end diff --git a/config/environments/test.rb b/config/environments/test.rb index 0a284f6e9a17b631311da772ec5e1399069baf8d..3608246974a70de5168b7b400cbd6dabd269dc69 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -10,7 +10,7 @@ Rails.application.configure do # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false + config.eager_load = true # Configure static file server for tests with Cache-Control for performance. config.public_file_server.enabled = true @@ -18,6 +18,11 @@ Rails.application.configure do 'Cache-Control' => 'public, max-age=3600' } + # Enable stdout logger + config.logger = Logger.new(STDOUT) + + # Set log level + config.log_level = :warn # Show full error reports and disable caching. config.consider_all_requests_local = true diff --git a/config/feature.yml b/config/feature.yml index b5aa6837a4ad98cc4ae3b1a32159f660f77f09ba..96a072cd02ffc073d840c86c48db02f88cce0a98 100644 --- a/config/feature.yml +++ b/config/feature.yml @@ -4,7 +4,7 @@ development: test: features: - allow_client_application: true + allow_client_application: false production: features: diff --git a/config/routes.rb b/config/routes.rb index 82e1aa113e68f2d9dbab86ce2dd0dfa73e54f39a..0472a038b0880749716e765d85726f54ade7c6c6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -30,7 +30,7 @@ Rails.application.routes.draw do end concern :reviewable do - resources :reviews, only: [:index, :create, :show, :destroy], concerns: :deletable do + resources :reviews, only: [:index, :create, :destroy], concerns: :deletable do member do post :rate end @@ -44,6 +44,16 @@ Rails.application.routes.draw do end end + # GET /users/1/learning_objects/ + concern :publisher do + member do + get 'learning_objects', as: :get_learning_objects, action: :show_all_learning_objects + get 'learning_objects/liked', as: :get_liked_learning_objects, action: :show_liked_learning_objects + get 'collections', as: :get_collections, action: :show_all_collections + get 'collections/liked', as: :get_liked_collections, action: :show_liked_collections + end + end + # GET /learning_objects/1/versions/123 # GET /learning_objects/1/versions # POST /learning_objects/1/versions/234/checkout @@ -63,14 +73,18 @@ Rails.application.routes.draw do resources :activities, only: :index resources :feed, only: [:index] - resources :users, concerns: [:followable, :deletable] do + resources :users, concerns: [:followable, :deletable, :publisher] do member do resources :bookmarks, module: 'users', only: [:index, :create, :destroy] get 'following/:object_type', to: 'users#following' get 'activities', to: 'activities#user_activities' + get 'reviews/own', to: 'users#own_reviews' + get 'reviews/received', to: 'users#received_reviews' end end + resources :reviews, only: :show + # search routes resources :search, only: :index do collection do diff --git a/spec/acceptance/learning_objects_spec.rb b/spec/acceptance/learning_objects_spec.rb index 470f5d1284e7f85104af464fe9f68ead85f53e36..84bec578516e8f2cfd776c2d50b673d1223a89d7 100644 --- a/spec/acceptance/learning_objects_spec.rb +++ b/spec/acceptance/learning_objects_spec.rb @@ -16,7 +16,8 @@ resource 'Learning Objects' do let(:offset) { 0 } example_request 'Get a list of learning objects' do - expect(response_body).to eq(Helper.serialize(LearningObject.limit(limit).offset(offset))) + # active model serializer may render model associations in different order for collections (array of items), so we're verifing only returned ids + expect(JSON.parse(response_body).map { |o| o['id'] }.sort).to eq(LearningObject.limit(limit).offset(offset).pluck(:id).sort) expect(status).to eq(200) end end @@ -32,7 +33,6 @@ resource 'Learning Objects' do end end - # # head "/orders" do # example_request "Getting the headers" do diff --git a/spec/factories/learning_objects.rb b/spec/factories/learning_objects.rb index bd8b48888fa2d4b449ebcdc7d023024bd8d50f52..b84d1866606fefe2b9313b5f5946e09a908402ea 100644 --- a/spec/factories/learning_objects.rb +++ b/spec/factories/learning_objects.rb @@ -3,9 +3,25 @@ FactoryGirl.define do sequence(:name) { |i| "LearningObject #{i}" } sequence(:id_dspace) { |i| i } publisher + score { rand(0.0..1.0) } + description { Faker::Lorem.paragraph } object_type { ObjectType.all.sample } language { Language.all.sample } author { Faker::Name.name } - state { LearningObject.states[:published] } + state LearningObject.states[:published] + + transient do + tags_count 5 + subjects_count 2 + educational_stages_count 1 + end + + after(:create) do |learning_object, evaluator| + create_list(:tagging, evaluator.tags_count, taggable: learning_object) + [Subject, EducationalStage].each do |model| + table = model.to_s.tableize + learning_object.try(table.to_sym) << model.all.sample(evaluator.try("#{table}_count".to_sym)) + end + end end end diff --git a/spec/factories/object_types.rb b/spec/factories/object_types.rb deleted file mode 100644 index 1116b31666e947b19017e080bd3f9e85420f3ec9..0000000000000000000000000000000000000000 --- a/spec/factories/object_types.rb +++ /dev/null @@ -1,5 +0,0 @@ -FactoryGirl.define do - factory :object_type do |o| - o.name { Faker::File.mime_type } - end -end diff --git a/spec/factories/taggings.rb b/spec/factories/taggings.rb new file mode 100644 index 0000000000000000000000000000000000000000..5225d2fa45a810dcfade2efb0f5d7ed4554a34bc --- /dev/null +++ b/spec/factories/taggings.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + factory :tagging do + tag + tagger + after(:create) do |t, evaluator| + t.taggable = evaluator.taggable + end + end +end diff --git a/spec/factories/tags.rb b/spec/factories/tags.rb new file mode 100644 index 0000000000000000000000000000000000000000..3ed954937140bf44357e00cf81bc7483e4e2d3ed --- /dev/null +++ b/spec/factories/tags.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :tag do + sequence(:name) { |i| "Tag #{i}" } + end +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index e7c68f4b8a4be3537c6c15fa76f2138df14e86e7..63967247c7cc5785f57b7d2df672de212e622ca5 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,5 +1,5 @@ FactoryGirl.define do - factory :user, aliases: [:owner, :publisher] do + factory :user, aliases: [:owner, :publisher, :tagger] do name { Faker::Name.name } email { Faker::Internet.email } password '12345678'