diff --git a/.erdconfig b/.erdconfig new file mode 100644 index 0000000000000000000000000000000000000000..6d077b17393fb5120fe8611219660aa374bb03c6 --- /dev/null +++ b/.erdconfig @@ -0,0 +1,19 @@ +attributes: + - content + - foreign_key + - inheritance +disconnected: true +filename: erd +filetype: pdf +indirect: true +inheritance: true +markup: true +notation: bachman +orientation: horizontal +polymorphism: false +sort: true +warn: true +title: PortalMEC +exclude: null +only: null +prepend_primary: false diff --git a/Gemfile b/Gemfile index ffd65b8e5f621f29c5b21444b71092870e3fb79b..632fd727716b1196dda747eddaa922775551af5c 100644 --- a/Gemfile +++ b/Gemfile @@ -47,7 +47,6 @@ gem 'stackprof' group :development do gem 'annotate' - gem 'immigrant' # Generate ER Diagram from database (use: rake erd) @@ -87,11 +86,17 @@ group :development do # JavaScript runtime gem 'execjs' + + # local mailbox + gem 'mailcatcher' end group :test do gem 'shoulda' gem 'minitest-reporters' + gem 'rspec-rails' + gem 'faker' + gem 'factory_girl_rails' end gem 'streamio-ffmpeg', '~> 1.0.0' @@ -147,3 +152,11 @@ gem 'rubyzip' # user activity gem 'public_activity' + +gem 'rails-observers' + +# soft-deleted for active record models +gem 'paranoia', '~> 2.0' + +# models versioning +gem 'paper_trail' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 1eb1ecace5941595657e420ba4b189364399dadc..8ec46499af5aff41d4fbd0224e3cfe1cdcc84ab0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -32,8 +32,10 @@ GEM erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - active_model_serializers (0.9.5) - activemodel (>= 3.2) + active_model_serializers (0.10.0) + actionpack (>= 4.0) + activemodel (>= 4.0) + railties (>= 4.0) activejob (4.2.6) activesupport (= 4.2.6) globalid (>= 0.3.0) @@ -58,7 +60,7 @@ GEM rake (>= 10.4, < 12.0) ansi (1.5.0) arel (6.0.3) - ast (2.2.0) + ast (2.3.0) axiom-types (0.1.1) descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) @@ -72,12 +74,12 @@ GEM rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - brakeman (3.3.0) + brakeman (3.3.1) builder (3.2.2) - bullet (5.0.0) + bullet (5.1.0) activesupport (>= 3.0.0) - uniform_notifier (~> 1.9.0) - byebug (8.2.5) + uniform_notifier (~> 1.10.0) + byebug (9.0.5) choice (0.2.0) chronic (0.10.2) climate_control (0.0.3) @@ -94,6 +96,7 @@ GEM connection_pool (2.2.0) curb (0.8.8) cvss (0.99.0) + daemons (1.2.3) dalli (2.7.6) data_mapper (1.2.0) dm-aggregates (~> 1.2.0) @@ -122,7 +125,7 @@ GEM debug_inspector (0.0.2) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) - devise (4.0.2) + devise (4.0.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0, < 5.1) @@ -131,6 +134,7 @@ GEM devise_token_auth (0.1.37) devise (> 3.5.2, < 4.1) rails (< 6) + diff-lcs (1.2.5) dm-aggregates (1.2.0) dm-core (~> 1.2.0) dm-constraints (1.2.0) @@ -183,15 +187,21 @@ GEM multi_json equalizer (0.0.11) erubis (2.7.0) - execjs (2.6.0) + eventmachine (1.0.9.1) + execjs (2.7.0) + factory_girl (4.7.0) + activesupport (>= 3.0.0) + factory_girl_rails (4.7.0) + factory_girl (~> 4.7.0) + railties (>= 3.0.0) + faker (1.6.3) + i18n (~> 0.5) faraday (0.9.2) multipart-post (>= 1.2, < 3) - fast_stack (0.2.0) fastercsv (1.5.5) feature (1.3.0) ffi (1.9.10) - flamegraph (0.1.0) - fast_stack + flamegraph (0.9.5) flay (2.7.0) erubis (~> 2.7.0) ruby_parser (~> 3.0) @@ -227,26 +237,36 @@ GEM nokogiri (>= 1.5.9) mail (2.6.4) mime-types (>= 1.16, < 4) - mime-types (3.0) + mailcatcher (0.6.4) + activesupport (~> 4.0) + eventmachine (= 1.0.9.1) + mail (~> 2.3) + rack (~> 1.5) + sinatra (~> 1.2) + skinny (~> 0.2.3) + sqlite3 (~> 1.3) + thin (~> 1.5.0) + mime-types (3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0221) + mime-types-data (3.2016.0521) mimemagic (0.3.0) mina (0.3.8) open4 (~> 1.3.4) rake - mini_portile2 (2.0.0) - minitest (5.8.4) + mini_portile2 (2.1.0) + minitest (5.9.0) minitest-reporters (1.1.9) ansi builder minitest (>= 5.0) ruby-progressbar - multi_json (1.12.0) + multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) net-http-persistent (2.9.4) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) + nokogiri (1.6.8) + mini_portile2 (~> 2.1.0) + pkg-config (~> 1.1.7) oauth (0.5.1) oauth2 (1.1.0) faraday (>= 0.8, < 0.10) @@ -275,16 +295,23 @@ GEM omniauth-oauth (~> 1.1) open4 (1.3.4) orm_adapter (0.5.0) + paper_trail (5.1.1) + activerecord (>= 3.0, < 6.0) + activesupport (>= 3.0, < 6.0) + request_store (~> 1.1) paperclip (4.3.6) activemodel (>= 3.2.0) activesupport (>= 3.2.0) cocaine (~> 0.5.5) mime-types mimemagic (= 0.3.0) - parser (2.3.0.7) + paranoia (2.1.5) + activerecord (~> 4.0) + parser (2.3.1.0) ast (~> 2.2) pg (0.18.4) phantomjs (2.1.1.0) + pkg-config (1.1.7) powerpack (0.1.1) ptools (1.3.3) public_activity (1.5.0) @@ -297,7 +324,7 @@ GEM activesupport (>= 3.0.0) rack (1.6.4) rack-cors (0.4.0) - rack-mini-profiler (0.9.9.2) + rack-mini-profiler (0.10.1) rack (>= 1.2.0) rack-protection (1.5.3) rack @@ -332,6 +359,8 @@ GEM ruby-graphviz (~> 1.2) rails-html-sanitizer (1.0.3) loofah (~> 2.0) + rails-observers (0.1.2) + activemodel (~> 4.0) railties (4.2.6) actionpack (= 4.2.6) activesupport (= 4.2.6) @@ -344,32 +373,50 @@ GEM redis (3.3.0) redis-namespace (1.5.2) redis (~> 3.0, >= 3.0.4) - reek (4.0.1) + reek (4.0.2) codeclimate-engine-rb (~> 0.3.1) parser (~> 2.3, >= 2.3.0.6) rainbow (~> 2.0) + request_store (1.3.1) resource_kit (0.1.5) addressable (~> 2.3.6) responders (2.2.0) railties (>= 4.2.0, < 5.1) rmagick (2.15.4) - rubocop (0.39.0) - parser (>= 2.3.0.7, < 3.0) + rspec-core (3.4.4) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-mocks (3.4.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-rails (3.4.2) + actionpack (>= 3.0, < 4.3) + activesupport (>= 3.0, < 4.3) + railties (>= 3.0, < 4.3) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-support (~> 3.4.0) + rspec-support (3.4.1) + rubocop (0.40.0) + parser (>= 2.3.1.0, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) ruby-graphviz (1.2.2) - ruby-progressbar (1.8.0) + ruby-progressbar (1.8.1) ruby_parser (3.8.2) sexp_processor (~> 4.1) - rubycritic (2.9.0) + rubycritic (2.9.1) colorize flay (= 2.7.0) flog (= 4.3.2) launchy (= 2.4.3) - parser (= 2.3.0.7) - reek (= 4.0.1) + parser (= 2.3.1.0) + reek (= 4.0.2) ruby_parser (~> 3.8) virtus (~> 1.0) rubyzip (1.2.0) @@ -397,8 +444,11 @@ GEM rack (~> 1.5) rack-protection (~> 1.4) tilt (>= 1.3, < 3) - slim (3.0.6) - temple (~> 0.7.3) + skinny (0.2.4) + eventmachine (~> 1.0.0) + thin (>= 1.5, < 1.7) + slim (3.0.7) + temple (~> 0.7.6) tilt (>= 1.3.3, < 2.1) spring (1.7.1) sprockets (3.6.0) @@ -414,15 +464,19 @@ GEM stringex (1.5.1) sys-uname (1.0.2) ffi (>= 1.0.0) - temple (0.7.6) - terminal-table (1.5.2) + temple (0.7.7) + terminal-table (1.6.0) + thin (1.5.1) + daemons (>= 1.0.9) + eventmachine (>= 0.12.6) + rack (>= 1.0.0) thor (0.19.1) thread_safe (0.3.5) - tilt (2.0.2) + tilt (2.0.5) tzinfo (1.2.2) thread_safe (~> 0.1) unicode-display_width (1.0.5) - uniform_notifier (1.9.0) + uniform_notifier (1.10.0) uuidtools (2.1.5) virtus (1.0.5) axiom-types (~> 0.1) @@ -458,18 +512,23 @@ DEPENDENCIES devise_token_auth dspace_rest_client execjs + factory_girl_rails + faker feature flamegraph gitlab immigrant libarchive-static + mailcatcher mimemagic mina minitest-reporters omniauth-facebook omniauth-google-oauth2 omniauth-twitter + paper_trail paperclip + paranoia (~> 2.0) pg public_activity puma @@ -479,10 +538,12 @@ DEPENDENCIES rails (= 4.2.6) rails-api rails-erd + rails-observers rainbow rdoc redis-throttle! rmagick + rspec-rails rubocop rubycritic rubyzip @@ -500,4 +561,4 @@ DEPENDENCIES whenever BUNDLED WITH - 1.12.1 + 1.12.3 diff --git a/app/builders/learning_object/draft_builder.rb b/app/builders/learning_object/draft_builder.rb index 3c4f318eb36ce0d09456d35e6f177809eaf912ad..cf7fe5b7c594738e8855906b3c3c282d01cb472b 100644 --- a/app/builders/learning_object/draft_builder.rb +++ b/app/builders/learning_object/draft_builder.rb @@ -2,35 +2,32 @@ 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 # set publisher @draft.publisher = publisher - @draft.save + # build tags params[:tags].try(:each) do |t| tag = Tag.where(name: t['name']).first_or_create Tagging.where(tag: tag, taggable: @draft, tagger: publisher).first_or_create end @draft.save + @draft end - private - def self.sanitize_params(args={}) - _args = args.clone + params = args.clone %w(tags language link).each do |arg| - _args.delete(arg) + params.delete(arg) end - metadata = [{'key' => 'dc.object.url', 'value' => args[:link]}] - _args.merge(metadata: metadata) + metadata = { 'dc.object.url' => args[:link] } + params.merge(metadata: metadata) end end diff --git a/app/builders/learning_object_builder.rb b/app/builders/learning_object_builder.rb index 9a48e71cef22b149da4ab554a1366738a7f6fe9f..e1839a9c2f5d2195f5ef360647d276191bf5ecc9 100644 --- a/app/builders/learning_object_builder.rb +++ b/app/builders/learning_object_builder.rb @@ -1,14 +1,13 @@ class LearningObjectBuilder - def self.build_from_dspace(item) lo = LearningObject.new( - name: item.name, - id_dspace: item.id, - thumbnail: nil, - metadata: item.metadata.map(&:to_h) + name: item.name, + id_dspace: item.id, + thumbnail: nil, + metadata: dspace_metadata_to_hash(item.metadata) ) - institution = lo.get_metadata_values_of('dc.creator').first + institution = lo.get_metadata_value_of('dc.creator') institution = 'Desconhecido' if institution.blank? lo.publisher = Institution.where(name: institution).first_or_create @@ -49,9 +48,13 @@ class LearningObjectBuilder _params end - # private + def self.dspace_metadata_to_hash(metadata) + hash = Hash.new { |h, k| h[k] = Array.new(&h.default_proc) } + metadata.each { |m| hash[m.key] << m.value } + hash + end - #def self.sanitize_form_metadata(params={}) + # def self.sanitize_form_metadata(params={}) # if !params[:link].blank? # metadata = [{'key' => 'dc.object.url', 'value' => params[:link]}] # _args.merge(metadata: metadata) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 03b7e34c95cce71bd52b0dde11b4cf639f7081fb..d904c81c1a0f597f8fa851b0364080ca2dd914bd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,12 @@ class ApplicationController < ActionController::API include Pundit include PublicActivity::StoreController + # tracking user in papertrail + before_action :set_paper_trail_whodunnit + + # check if client application is allowed to consumes the API. + before_action :allow_client_application, if: -> { Feature.active?(:allow_client_application) } + # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. # protect_from_forgery with: :null_session @@ -17,23 +23,19 @@ class ApplicationController < ActionController::API protected def configure_permitted_parameters - registration_params = [:name, :email, :avatar, :password, :password_confirmation] - - if params[:action] == 'update' - devise_parameter_sanitizer.for(:account_update) { - |u| u.permit(registration_params << :current_password) - } - elsif params[:action] == 'create' - devise_parameter_sanitizer.for(:sign_up) { - |u| u.permit(registration_params << :terms_of_service) - } - end + registration_params = [:name, :email, :avatar, :password, :password_confirmation, :current_password, :terms_of_service] + devise_parameter_sanitizer.permit :sign_up, keys: registration_params + devise_parameter_sanitizer.permit :account_update, keys: registration_params end private + def allow_client_application + app = Application.find_or_initialize_by(application_id: request.headers["PortalMEC-AppID"].to_s) + user_not_authorized if app.domain != request.domain + end + def user_not_authorized render nothing: true, status: :unauthorized end - end diff --git a/app/controllers/concerns/deleted_objects_controller.rb b/app/controllers/concerns/deleted_objects_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..2eeee836d94222119f9db2486516bb4ea3c1401b --- /dev/null +++ b/app/controllers/concerns/deleted_objects_controller.rb @@ -0,0 +1,14 @@ +module DeletedObjectsController + extend ActiveSupport::Concern + + def deleted + render json: deleted_resource.only_deleted + end + + protected + + def deleted_resource + raise NotImplementedError + end + +end diff --git a/app/controllers/concerns/followable_controller.rb b/app/controllers/concerns/followable_controller.rb index 33d81f3e0e408c0e6c522f5220bef1df20e93415..ba1aee20646739b28e44aeb34c8fbbf741f8ed60 100644 --- a/app/controllers/concerns/followable_controller.rb +++ b/app/controllers/concerns/followable_controller.rb @@ -28,5 +28,4 @@ module FollowableController render nothing: true, status: :forbidden end end - -end \ No newline at end of file +end 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/resource_model.rb b/app/controllers/concerns/resource_model.rb new file mode 100644 index 0000000000000000000000000000000000000000..e8763ac79c8b1c1f08717622076a4ce2686a2598 --- /dev/null +++ b/app/controllers/concerns/resource_model.rb @@ -0,0 +1,12 @@ +module ResourceModel + extend ActiveSupport::Concern + + protected + + def resource_model + resource, id = request.path.split('/')[2, 3] + resource_model = resource.singularize.classify.constantize + resource_model.find(id) + 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/concerns/taggable_controller.rb b/app/controllers/concerns/taggable_controller.rb index c01fccbad6f5e21c204743177c10e73ee3b62645..bfe6382eb41ec11b898128e5e2b296043ac96fbe 100644 --- a/app/controllers/concerns/taggable_controller.rb +++ b/app/controllers/concerns/taggable_controller.rb @@ -10,14 +10,14 @@ module TaggableController # POST /v1/learning_objects/1/tagging.json def tagging @owner.tag(taggable, with: [tag_params[:name]]) - render json: ActiveModel::ArraySerializer.new(taggable.tags.to_a), status: :created + render json: taggable.tags, status: :created end # DELETE /v1/learning_objects/1/untagging # DELETE /v1/learning_objects/1/untagging.json def untagging @owner.untag(taggable, tag_params[:name]) - render json: ActiveModel::ArraySerializer.new(taggable.tags.to_a), status: :ok + render json: taggable.tags, status: :ok end protected diff --git a/app/controllers/old/about_controller.rb b/app/controllers/old/about_controller.rb deleted file mode 100644 index a14c5285394b25132c61dc0562014403bc8ad507..0000000000000000000000000000000000000000 --- a/app/controllers/old/about_controller.rb +++ /dev/null @@ -1,4 +0,0 @@ -class AboutController < ApplicationController - def index - end -end diff --git a/app/controllers/old/bookmarks_controller.rb b/app/controllers/old/bookmarks_controller.rb deleted file mode 100644 index 0dccaf5650ce3f19e62f7958053fe880caca1741..0000000000000000000000000000000000000000 --- a/app/controllers/old/bookmarks_controller.rb +++ /dev/null @@ -1,46 +0,0 @@ -class BookmarksController < ApplicationController - include Pundit - - before_action :authenticate_user! - before_action :set_user - before_action :find_object, only: [:add_object, :remove_object] - - - # GET /bookmarks/1 - # GET /bookmarks/1.json - def show - render partial: 'list' if params[:list] == 'true' - end - - # POST /bookmarks/1/learning_object - def add_object - authorize @object - Bookmark.create(user: @user, bookmarkable: @object) - - render json: { status: true } if request.xhr? - end - - def list - render layout: false - end - - # DELETE /bookmarks/1/learning_object - def remove_object - authorize @object - Bookmark.destroy Bookmark.where(user: @user, bookmarkable: @object) - - render json: { status: true } if request.xhr? - end - - private - - def set_user - @user = current_user - end - - def find_object - klass = params[:type].constantize - @object = klass.find params[:id] - end - -end diff --git a/app/controllers/old/callbacks_controller.rb b/app/controllers/old/callbacks_controller.rb deleted file mode 100644 index 56360cbdf6051b7efc7f63ef43d5512a7b08fa0e..0000000000000000000000000000000000000000 --- a/app/controllers/old/callbacks_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -class CallbacksController < Devise::OmniauthCallbacksController - - def facebook - request_data("Facebook","devise.facebook_data") - end - - def twitter - request_data("Twitter","devise.twitter_data") - end - - def google_oauth2 - request_data("Google","devise.google_oauth2_data") - end - - private - - def request_data(provider,provider_session) - @user = User.from_omniauth(request.env["omniauth.auth"]) - - if @user.persisted? - sign_in_and_redirect @user, :event => :authentication - flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => provider - else - session[provider_session] = request.env["omniauth.auth"] - redirect_to new_user_registration_url - end - - def failure - redirect_to root_path - end - end - -end diff --git a/app/controllers/old/chunks_controller.rb b/app/controllers/old/chunks_controller.rb deleted file mode 100644 index 460eee164e8ffd09737ccad7e0c45e3fc612a20a..0000000000000000000000000000000000000000 --- a/app/controllers/old/chunks_controller.rb +++ /dev/null @@ -1,124 +0,0 @@ -class ChunksController < ApplicationController - layout nil - - before_action :set_learning_object - - #GET /chunk - def show - chunk = resumable_chunk chunk_number - - unless valid_mime_type? - render :nothing => true, :status => 415 - else - if File.exists?(chunk) - post_file_and_create_thumbnail @learning_object, resumable_filename if last_chunk? - #Let resumable.js know this chunk already exists - render :nothing => true, :status => 200 - else - #Let resumable.js know this chunk doesnt exists and needs to be uploaded - render :nothing => true, :status => 404 - end - end - end - #POST /chunk - def create - - unless valid_mime_type? - return render :nothing => true, :status => 415 - end - - #chunk path based on the parameters - chunk = resumable_chunk chunk_number - - #Create chunks directory when not present on system - if !File.directory?(dir) - FileUtils.mkdir(dir, :mode => 0700) - end - - #Move the uploaded chunk to the directory - FileUtils.mv chunk_tmpfile, chunk - - #Concatenate all the partial files into the original file - #When all chunks are uploaded - if last_chunk? - #Create a target file - File.open(resumable_filename, "a") do |target| - #Loop trough the chunks - for i in 1..chunk_number - #Select the chunk - chunk = File.open(resumable_chunk(i), 'r').read - - #Write chunk into target file - chunk.each_line do |line| - target << line - end - - #Deleting chunk - FileUtils.rm resumable_chunk(i), :force => true - end - puts "File saved to #{resumable_filename}" - end - - post_file_and_create_thumbnail @learning_object, resumable_filename - end - - render nothing: true, status: 200 - end - - private - - def post_file_and_create_thumbnail(learning_object, filename) - publisher = LearningObjectPublisher.new(DspaceService.create_client) - publisher.post learning_object, filename - end - - def chunk_tmpfile - chunks_params[:file].tempfile - end - - def last_chunk? - chunk_number == total_chunks - end - - def chunk_size - chunks_params[:resumableChunkSize].to_i - end - - def total_chunks - chunks_params[:resumableTotalChunks].to_i - end - - def chunk_number - chunks_params[:resumableChunkNumber].to_i - end - - def resumable_chunk(part) - "#{resumable_filename}.part#{part}" - end - - def resumable_filename - "#{dir}/#{chunks_params[:resumableFilename]}" - end - - def dir - "/tmp/#{chunks_params[:resumableIdentifier]}" - end - - def set_learning_object - @learning_object = LearningObject.find chunks_params[:learning_object_id] - end - - def resumable_file_extension - File.extname(chunks_params[:resumableFilename])[1..-1] - end - - def valid_mime_type? - mime_types = @learning_object.object_type.mime_types.map(&:extension) - return true if mime_types.empty? - mime_types.include? resumable_file_extension - end - # Never trust parameters from the scary internet, only allow the white list through. - def chunks_params - params.permit(:file, :learning_object_id, :resumableIdentifier, :resumableFilename, :resumableChunkNumber, :resumableTotalChunks, :resumableChunkSize) - end -end diff --git a/app/controllers/old/collections_controller.rb b/app/controllers/old/collections_controller.rb deleted file mode 100644 index 9ae2446a9aa477e56850fa01966487fb738f66b1..0000000000000000000000000000000000000000 --- a/app/controllers/old/collections_controller.rb +++ /dev/null @@ -1,229 +0,0 @@ -class CollectionsController < ApplicationController - include Pundit - - before_action :set_collection, only: [:show, :update, :destroy, :like, :change_privacy] - before_action :set_collections, only: [:list, :add_learning_object, :remove_learning_object] - before_action :authenticate_user!, only: [:update, :destroy, :like, :list, :me, :add_learning_object, :remove_learning_object, :change_privacy] - before_action :authorize_action, only: [:show, :create, :update, :destroy, :add_learning_object, :remove_learning_object, :change] - - rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized - - - # GET /collections - # GET /collections.json - def index - respond_to do |format| - # for HTML page, returns institutional collections - format.html do - @collections = Collection.all.where(owner: Institution.all) - end - - # returns all collection of logged user as JSON for UI actions - if user_signed_in? - format.json do - @collections = current_user.collections - end - end - end - end - - # GET /collections/1 - # GET /collections/1.json - def show - if @collection.class == User - # bookmark - @user = @collection - @collection = collection_repository.bookmarks(@user) - @own = true - else - check_collection_privacy! @collection - - @user = @collection.owner - @own = user_signed_in? ? @collection.user_own?(current_user) : false - end - - @reviews = Review.includes(:user).where(reviewable: @collection) - - render partial: 'list' if params[:list] == 'true' - end - - # POST /collections/1/like - def like - Collection.like @collection - end - - # POST /collections - # POST /collections.json - def create - @collection = Collection.new(collection_params) - @collection.owner = params[:collection][:owner].blank? ? current_user : Institution.find(params[:collection][:owner]) - - respond_to do |format| - if @collection.save - format.html { redirect_to :back, notice: t('activerecord.attributes.collection.create.notice.successfully_created') } - else - format.html { render :new } - end - end - end - - # PATCH/PUT /collections/1 - # PATCH/PUT /collections/1.json - def update - respond_to do |format| - if Collection.update(collection_params) - format.html { redirect_to @collection, notice: t('activerecord.attributes.collection.update.notice.successfully_updated') } - else - format.html { render :edit } - end - end - end - - # DELETE /collections/1 - # DELETE /collections/1.json - def destroy - Collection.destroy @collection - - respond_to do |format| - format.html { redirect_to user_path(current_user), notice: t('activerecord.attributes.collection.destroy.notice.successfully_destroy') } - end - end - - def list - @collection = @collections.first - - # list all - @collection = nil if @collection == 'all' - - @collections = current_user.associated_collections - @collections.select! do |c| - (!@collection.blank? && c.id != @collection.id) || !include_learning_objects?(c) - end - @type = params[:type] - - unless @type.blank? - @send = case @type - when 'add' then - 'Adicionar' - when 'copy' then - 'Copiar' - when 'move' then - 'Mover' - else - 'Enviar' - end - - @title = (@send == 'Enviar') ? 'Coleções' : @send + ' objeto(s) às coleções' - end - - render layout: false - end - - def me - @new_collection = Collection.new - - @publishers = current_user.institutions - @bookmark = (current_user.bookmarks.nil? || current_user.bookmarks.first.nil?) ? [] : [current_user.bookmarks.first] - - @groups = [ - CollectionsGroup.new(title: 'Coleções Automáticas', - collections: @bookmark), - CollectionsGroup.new(title: 'Coleções Adicionadas', - collections: current_user.associated_collections) - ] - - end - - # POST /collections/1/learning_object - def add_learning_object - @collections.each do |collection| - next unless collection.user_own?(current_user) - - @learning_objects.each do |learning_object| - collection.learning_objects << learning_object unless collection.learning_objects.include? learning_object - end - collection.save - end - - render json: {status: true} if request.xhr? - end - - # DELETE /collections/1/learning_object - def remove_learning_object - @collections.each do |collection| - next unless collection.user_own?(current_user) - - @learning_objects.each do |learning_object| - collection.learning_objects.destroy(learning_object) - end - collection.save - end - - render json: {status: true} if request.xhr? - end - - # change collection privacy - def change_privacy - @collection.privacy = params[:privacy] - - response = @collection.save - - render json: {status: response} if request.xhr? - end - - private - - def include_learning_objects?(collection) - @learning_objects.each do |lo| - return true if collection.learning_objects.include? lo - end - false - end - - def check_collection_privacy!(collection) - if collection.private? && !collection.user_own?(current_user) - redirect_to :root, notice: 'Está é uma coleção privada.' - end - end - - def set_collection - @collection = Collection.find params[:id] - end - - def set_collections - if params[:id] == 'all' || params[:id].blank? - @collections = ['all'] - else - @collections = (params[:id].class == String) ? [Collection.find(params[:id])] : params[:id].map { |id| Collection.find id } - end - - unless params[:learning_objects_ids].blank? - @learning_objects = [] - - params[:learning_objects_ids].split(',').each do |id| - object = LearningObject.find id - @learning_objects << object unless object.blank? - end - end - end - - # Never trust parameters from the scary internet, only allow the white list through. - def collection_params - params.require(:collection).permit(:name, :description, learning_objects: []) - end - - def user_not_authorized - flash[:notice] = "Esta coleção é privada!" - redirect_to (root_path) - end - - def authorize_action - if !@collections.nil? - @collections.each { |c| authorize c } - else - @collection ||= Collection.new - authorize @collection - end - end - -end diff --git a/app/controllers/old/complaints_controller.rb b/app/controllers/old/complaints_controller.rb deleted file mode 100644 index 0766279742594ccac197ebb57f097158e3b562a8..0000000000000000000000000000000000000000 --- a/app/controllers/old/complaints_controller.rb +++ /dev/null @@ -1,32 +0,0 @@ -class ComplaintsController < ApplicationController - include Pundit - - before_action :authorize_action - before_action :authenticate_user! - - def create - complaint = Complaint.new(complaint_params) - complaint.user = current_user - - respond_to do |format| - if complaint.save - format.html { redirect_to :back, notice: t('activerecord.attributes.complaint.create.notice.sucess') } - else - format.html { redirect_to :back, alert: t('activerecord.attributes.complaint.create.alert.failure') } - end - end - end - - private - - # Never trust parameters from the scary internet, only allow the white list through. - def complaint_params - params.require(:complaint).permit(:complaintable_id, :complaintable_type, :complaint_reason_id, :description) - end - - def authorize_action - @complaint ||= Complaint.new(complaint_params) - authorize @complaint - end - -end diff --git a/app/controllers/old/feedbacks_controller.rb b/app/controllers/old/feedbacks_controller.rb deleted file mode 100644 index bf391b700c3b8f13aff4b4a7ec5228b46c51c575..0000000000000000000000000000000000000000 --- a/app/controllers/old/feedbacks_controller.rb +++ /dev/null @@ -1,54 +0,0 @@ -class FeedbacksController < ApplicationController - before_filter :authenticate_user! - - # GET /feedbacks/new - def new - # @feedbacks = Feedback.new - -# render layout: false - end - - # GET /feedbacks/new_bug - def new_bug - @bug = Bug.new - - render layout: false - end - - # POST /feedbacks - def create - # @feedbacks = Feedback.new(feedback_params) - - # respond_to do |format| - # if feedback_service.send_feedback @feedbacks - # format.html { redirect_to :back, notice: 'Obrigado pela sua avaliação!' } - # end - # end - end - - # POST /feedbacks/report_bug - def report_bug - @bug = Bug.new(bug_params) - - respond_to do |format| - if feedback_service.report_bug @bug - format.html { redirect_to :back, notice: t('activerecord.attributes.feedback.report_bug.notice.success') } - end - end - end - - private - - def feedback_service - FeedbackService.new(GitlabBugreporterService.new(Gitlab)) - end - - def bug_params - params.require(:bug).permit(:title, :description) - end - - def feedback_params - params.require(:feedbacks).permit(:object, :message, :description) - end - -end diff --git a/app/controllers/old/institutions_controller.rb b/app/controllers/old/institutions_controller.rb deleted file mode 100644 index 0f89f86b0a5bf486916863ece16809455b1162d8..0000000000000000000000000000000000000000 --- a/app/controllers/old/institutions_controller.rb +++ /dev/null @@ -1,83 +0,0 @@ -class InstitutionsController < ApplicationController - include Pundit - - before_action :set_institution, only: [:show, :edit, :update, :destroy, :like, :users] - before_action :authorize_action - - # GET /institutions - # GET /institutions.json - def index - @institutions = Institution.all - end - - # GET /institutions/1 - # GET /institutions/1.json - def show - end - - # GET /institutions/new - def new - @institution = Institution.new - end - - # GET /institutions/1/edit - def edit - end - - # POST /institutions - # POST /institutions.json - def create - @institution = Institution.new(institution_params) - - respond_to do |format| - if Institution.save @institution - format.html { redirect_to @institution, notice: t('activerecord.attributes.institution.create.notice.successfully_created') } - else - format.html { render :new } - end - end - end - - # PATCH/PUT /institutions/1 - # PATCH/PUT /institutions/1.json - def update - respond_to do |format| - if Institution.update(institution_params) - format.html { redirect_to @learning_object, notice: t('activerecord.attributes.institution.update.notice.successfully_updated') } - else - format.html { render :edit } - end - end - end - - # DELETE /institutions/1 - # DELETE /institutions/1.json - def destroy - Institution.destroy @institution - - respond_to do |format| - format.html { redirect_to institutions_url, notice: t('activerecord.attributes.institution.destroy.notice.successfully_destroy') } - end - end - - def users - @users = @institution.users - end - - private - - def set_institution - @institution = Institution.find(params[:id]) - end - - # Never trust parameters from the scary internet, only allow the white list through. - def institution_params - params[:institution_object] - end - - def authorize_action - @institution ||= Institution.new - authorize @institution - end - -end diff --git a/app/controllers/old/learning_objects/build_controller.rb b/app/controllers/old/learning_objects/build_controller.rb deleted file mode 100644 index 2463a66685c0241c5156e13c8fde94b17acab926..0000000000000000000000000000000000000000 --- a/app/controllers/old/learning_objects/build_controller.rb +++ /dev/null @@ -1,42 +0,0 @@ -class LearningObjects::BuildController < ::ApplicationController - layout 'learning_object_studio' - - include Wicked::Wizard - before_action :set_learning_object, only: [:show, :update] - - steps :upload_attachments, :select_thumbnail - - def show - render_wizard - end - - def update - @learning_object.update_attributes(learning_object_params) - publish @learning_object if step == steps.last - render_wizard @learning_object, notice: update_message - end - - private - - def set_learning_object - @learning_object = LearningObject.unscoped.find(params[:learning_object_id]) - end - - def publish(learning_object) - learning_object.publish - learning_object.save - end - - def learning_object_params - params[:learning_object].permit(:thumbnail, :name, :object_type_id, :description, :school_level, :language, :link, topics: []) - end - - def update_message - case step - when :upload_attachments - "Seus arquivos foram enviados com sucesso! Agora atualize a imagem do seu conteúdo para finalizar o processo de criação." - when :select_thumbnail - "Parabéns, a imagem foi atualizada e seu conteúdo foi criado com sucesso! Acesse seu perfil e veja todos os objetos criados." - end - end -end \ No newline at end of file diff --git a/app/controllers/old/learning_objects_controller.rb b/app/controllers/old/learning_objects_controller.rb deleted file mode 100644 index 99915a21e11d573e7eb275d82d5281481727b4b2..0000000000000000000000000000000000000000 --- a/app/controllers/old/learning_objects_controller.rb +++ /dev/null @@ -1,174 +0,0 @@ -require 'uri' - -class LearningObjectsController < ApplicationController - include Reportable - layout :resolve_layout - - before_action :authenticate_user!, except: [:index, :show] - before_action :set_learning_object, only: [:show, :edit, :update, - :destroy, :destroy_attachment, :remove_thumbnail, :like, :bookmarks, - :collections, :upload, :upload_link, :download, - :user_not_authorized] - after_action :increment_learning_object_views, only: [:show] - before_action :set_form_objects, only: [:new, :edit, :create] - before_action :authorize_action - before_action :set_preview_notice, only: :show - - # GET /learning_objects/1 - # GET /learning_objects/1.json - def show - @liked = @learning_object.liked?(current_user) if user_signed_in? - @reviews = Review.where(reviewable: @learning_object) - end - - # GET /learning_objects/new - def new - @learning_object = LearningObject.new - end - - # GET /learning_objects/1/edit - def edit - end - - # POST /learning_objects - # POST /learning_objects.json - def create - @learning_object = ::LearningObject::DraftBuilder.build current_user, learning_object_params - publisher = LearningObjectPublisher.new(DspaceService.create_client) - - respond_to do |format| - if publisher.create_draft @learning_object - # go to file submission page - format.html { success_redirect @learning_object } - else - format.html { render :new, notice: t('activerecord.attributes.learning_object.create.notice.failure') } - end - end - - end - - # PATCH/PUT /learning_objects/1 - # PATCH/PUT /learning_objects/1.json - def update - respond_to do |format| - if @learning_object.update(LearningObjectBuilder.build_form_params(learning_object_params)) - format.html { redirect_to learning_object_build_path(learning_object_id: @learning_object.id, id: :upload_attachments), notice: 'Os metadados do seu conteúdo educacional foram atualizados com sucesso!' } - else - format.html { render :edit } - end - end - end - - # DELETE /learning_objects/1 - # DELETE /learning_objects/1.json - def destroy - LearningObject.destroy @learning_object - - respond_to do |format| - format.html { redirect_to user_path(current_user), notice: t('activerecord.attributes.learning_object.destroy.notice.successfully_destroy') } - end - end - - # POST /learning_objects/1/like - def like - if @learning_object.liked? current_user - @learning_object.dislike current_user - else - @learning_object.like current_user - end - - if request.xhr? - render json: {count: @learning_object.likes.count, id: params[:id]} - end - end - - def destroy_attachment - attachment = LearningObject::Attachment.find(params[:attachment_id]) - @learning_object.update(attachment: nil) if @learning_object.attachment == attachment - attachment.destroy - render :nothing => true, :status => 204 - end - - def remove_thumbnail - @learning_object.thumbnail = nil - @learning_object.save - render :nothing => true, :status => 204 - end - - def download - @learning_object.download current_user - - redirect_to @learning_object.retrieve_link - end - - # POST /learning_objects/1/bookmarks - def bookmarks - bookmarks = current_user.bookmarks - bookmarks.add @learning_object - Collection.save_learning_objects bookmarks - - if request.xhr? - render json: {id: params[:id]} - end - end - - # GET /learning_objects/1/collections.json - def collections - @collections = @learning_object.collections - end - - private - - def set_preview_notice - if params[:preview_object] - flash[:notice] = %Q[Você está pré-visualizando o objeto. <a href='javascript:history.back()'>Clique aqui para voltar ao estúdio de criação</a>.] - end - end - - # Use callbacks to share common setup or constraints between actions. - def set_learning_object - @learning_object = LearningObject.unscoped.find(params[:id]) - end - - # Never trust parameters from the scary internet, only allow the white list through. - def learning_object_params - params[:learning_object].permit(:author, :name, :object_type_id, :description, :school_level, :language, :link, topics: []) - end - - def increment_learning_object_views - View.create(viewable: @learning_object, user: current_user) if user_signed_in? && @learning_object.publisher != current_user - end - - def success_redirect(learning_object) - #if 'Website externo' == learning_object.object_type.name - redirect_to learning_object_build_path(learning_object, :upload_attachments), notice: t('activerecord.attributes.learning_object.success_redirect.notice.successfully_created') - end - - def set_form_objects - @school_levels = ['Educação Infantil', 'Ensino Fundamental', 'Ensino Médio'] - @topics = Topic.defaults - @types = ObjectType.all - @languages = Language.all - end - - def user_not_authorized - flash[:notice] = "Este objeto está suspenso!" - flash[:alert] = "Razões: #{Complaint.where(complaintable_id: @learning_object.id).map(&:reason).join(',').to_s}" - redirect_to (root_path) - end - - def resolve_layout - case action_name - when 'new', 'edit', 'create', 'update' - 'learning_object_studio' - else - 'application' - end - end - - def authorize_action - @learning_object ||= LearningObject.new - authorize @learning_object - end - -end diff --git a/app/controllers/old/links_controller.rb b/app/controllers/old/links_controller.rb deleted file mode 100644 index 78529c149a984880a0270f5ad9baadca0de4106b..0000000000000000000000000000000000000000 --- a/app/controllers/old/links_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class LinksController < ApplicationController -end diff --git a/app/controllers/old/reviews_controller.rb b/app/controllers/old/reviews_controller.rb deleted file mode 100644 index 75e783ee450532e96a7aaff7e66dabd8a4481321..0000000000000000000000000000000000000000 --- a/app/controllers/old/reviews_controller.rb +++ /dev/null @@ -1,98 +0,0 @@ -class ReviewsController < ApplicationController - include Pundit - - before_action :authenticate_user!, except: [:show, :list] - before_action :set_review, only: [:show, :destroy] - before_action :authorize_action - - - def list - if !params[:learning_object_id].blank? - reviewable = LearningObject.find params[:learning_object_id] - elsif !params[:collection_id].blank? - reviewable = Collection.find params[:collection_id] - end - - @reviews = Review.where(reviewable: reviewable) unless reviewable.blank? - end - - # Global variables to show page - def show - end - - def new - @review = Review.new - @rates = Rating.all - - @reviewable_id = params[:reviewable_id] - @reviewable_type = params[:reviewable_type] - end - - def create - review = Review.where(user: current_user, reviewable_id: params[:reviewable_id], reviewable_type: params[:reviewable_type]).new(review_params) - - respond_to do |format| - if review.save && !params[:rates].blank? && params[:rates].is_a?(Hash) && params[:rates].size == Rating.count - ratings = [] - params[:rates].each { |id, value| ratings << ReviewRating.new(review: review, rating_id: id.to_i, value: value.to_i) } - ReviewRating.import ratings - - format.html { redirect_to params[:reviewable_type].constantize.find(params[:reviewable_id]), notice: t('activerecord.attributes.review.create.notice.successfully_created') } - else - review.destroy - format.html { redirect_to new_review_path, alert: t('activerecord.attributes.review.create.alert.there_was_an_error')} - end - end - end - - def destroy - redirect = @review.reviewable - - @review.destroy - - respond_to do |format| - format.html { redirect_to redirect, notice: t('activerecord.attributes.review.destroy.notice.successfully_destroy') } - end - end - - # User approve or not, the review - def rate - review = Review.find(params[:id]) - user = current_user - approves = approves_param - - rate = Rate.where(user: user, review: review).first_or_initialize - - if rate.approves == approves - rate.destroy - else - rate.update(approves: approves) - end - - render json: { approves: approves } if request.xhr? - end - - private - - def set_review - @review = Review.find params[:id] - end - - # Never trust parameters from the scary internet, only allow the white list through. - def review_params - params.require(:review).permit(:name, :description, :pros, :cons) - end - - def approves_param - case params[:approves] - when 'true' then true - when 'false' then false - end - end - - def authorize_action - @review||= Review.new - authorize @review - end - -end diff --git a/app/controllers/old/search_controller.rb b/app/controllers/old/search_controller.rb deleted file mode 100644 index dc7d2368f4456c1a5387cde2ce22b284694fab18..0000000000000000000000000000000000000000 --- a/app/controllers/old/search_controller.rb +++ /dev/null @@ -1,142 +0,0 @@ -class SearchController < ApplicationController - - include LearningObjectsHelper - include Pundit - - def index - @types = ObjectType.all.map(&:name) - - @topics = Topic.defaults - - @school_levels = ['Educação Infantil', 'Ensino Fundamental', 'Ensino Médio'].map { |o| Topic.find_by_name(o) } - - @sources = Institution.all - end - - def fetch - - params[:query] = "*" if params[:query].blank? - - case params[:search_class] - when "LearningObject" - @result = LearningObject.search params[:query], where: where_hash(params), order: lo_order_hash(params), page: params[:page] || 1, per_page: 10 - when "Collection" - @result = Collection.search params[:query], where: {privacy: "public"}, order: col_order_hash(params), page: params[:page] || 1, per_page: 10 - when "User" - @result = User.search params[:query], order: user_order_hash(params), page: params[:page] || 1, per_page: 10 - else - raise "Wrong search class parameter" - end - - render partial: 'search/fetch' - end - - def autocomplete - params_hash = {} - get_thumbnail = nil - case params[:search_class] - when "LearningObject" - params_hash = { fields: ['name^10', 'description', 'author'] } - get_thumbnail = Proc.new { |obj| image_tag(learning_object_thumbnail(obj)) } - when "Collection" - params_hash = { where: {privacy: "public"}, - fields: ['name^10', 'description', 'owner'] } - get_thumbnail = Proc.new { |obj| image_tag("/assets/icons/collection") } - when "User" - params_hash = { fields: ['name'] } - get_thumbnail = Proc.new { |obj| image_tag(obj.avatar.url(:thumb), 32) } - else - raise "Wrong search class parameter" - end - render json: autocomplete_search(Object.const_get(params[:search_class]), params_hash, get_thumbnail) - end - - def get_class_size - className = params[:class] - render json: { number: Object.const_get(className).count } - end - - private - - def autocomplete_search(search_class, params_hash={}, get_thumbnail) - response = [] - search_params = { limit: 10, misspellings: { below: 5 }, where: {state: validate_object} } - objs = search_class.search(params[:query], search_params.merge(params_hash)) - objs.each do |obj| - hash = {} - hash["name"] = obj.name - hash["thumbnail"] = get_thumbnail.call(obj) - hash["url"] = url_for([obj, :only_path => false]) - response << hash - end - response - end - - def image_tag(image, width=56, height=32) - ActionController::Base.helpers.image_tag image, width: width, height: height, class: "autocomplete" - end - - def where_hash(params) - hash = {} - - topics = params[:topic] unless params[:topic].blank? - topics += ", " unless topics.nil? - topics = topics.to_s + params[:school_level] unless params[:school_level].blank? - - # build hash - hash[:topics_name] = topics.split(', ') unless topics.nil? - hash[:object_type] = params[:type].split(', ') unless params[:type].blank? - hash[:publisher] = params[:source].split("-s- ") unless params[:source].blank? - hash[:state] = validate_object - # year = params[:year].blank? ? nil : params[:year].split('-').take(2) - - hash.blank? ? nil : hash - end - - def lo_order_hash(params) - case params[:order] - when 'author' - { author: {order: :asc, unmapped_type: :string} } - when 'publicationasc' - { published_at: {order: :asc, unmapped_type: :timestamp} } - when 'publicationdesc' - { published_at: {order: :desc, unmapped_type: :timestamp} } - when 'title' - { name: {order: :asc, unmapped_type: :string} } - else - { score: {order: :desc, unmapped_type: :integer} } - end - end - - def col_order_hash(params) - case params[:order] - when 'author' - { owner: {order: :asc, unmapped_type: :string} } - when 'publicationasc' - { created_at: {order: :asc, unmapped_type: :timestamp} } - when 'publicationdesc' - { created_at: {order: :desc, unmapped_type: :timestamp} } - when 'title' - { name: {order: :asc, unmapped_type: :string} } - else - { score: {order: :desc, unmapped_type: :integer} } - end - end - - def user_order_hash(params) - if params[:order] == 'title' - { name: {order: :asc, unmapped_type: :string} } - else - { score: {order: :desc, unmapped_type: :integer} } - end - end - - - private - - def validate_object - return 'published' if current_user.nil? || !current_user.is_admin? - return ['published', 'suspended', 'draft'] - end - -end diff --git a/app/controllers/old/users_controller.rb b/app/controllers/old/users_controller.rb deleted file mode 100644 index b4f75c7d0bcc31ab5e0827cfe74cd06072b5250d..0000000000000000000000000000000000000000 --- a/app/controllers/old/users_controller.rb +++ /dev/null @@ -1,80 +0,0 @@ -class UsersController < ApplicationController - - include Pundit - - before_action :authenticate_user!, only: [:follow, :unfollow] - before_action :check_current_user_page, only: :show - before_action :set_user, only: [:show] - before_action :set_institutions, only: :me - before_action :set_empty_collection, only: [:show, :me] - before_action :set_followable, only: [:follow, :unfollow] - - def show - @objects = @user.learning_objects - @institutions = @user.institutions - @groups = [CollectionsGroup.new(title: 'Coleções Adicionadas', collections: [ CollectionPolicy::Scope.new(current_user, @user.id, @user.collections).resolve.includes(:owner)])] - - if @user == current_user - @publishers = @user.institutions - @bookmarks = (@user.bookmarks.nil? || @user.bookmarks.first.nil?) ? [] : [@user.bookmarks.first] - @groups.unshift(CollectionsGroup.new(title: 'Coleções Automáticas', collections: @bookmarks)) - end - end - - def list - @users = User.all - end - - def follow - Follow.create(user: current_user, followable: @followable) unless @followable.nil? - - redirect_to user_path(@followable) - end - - def unfollow - Follow.where(user: current_user, followable: @followable).destroy_all unless @followable.nil? - - redirect_to user_path(@followable) - end - - def verify_email - exists = User.find_by_email(params[:email]) - render json: { valid: exists.nil? && !params[:email].match(Devise.email_regexp).nil? } - end - - private - - def set_empty_collection - @new_collection = Collection.new - end - - def set_institutions - @institutions = current_user.institutions - end - - def set_user - @user = User.find params[:id] - end - - def set_followable - @followable = params[:followable_type].constantize.find(params[:followable_id]) if %w(Collection User).include? params[:followable_type] - end - - def check_current_user_page - if user_signed_in? - if current_user.id == params[:id] - redirect_to action: :me - end - end - end - - def publishers_for(user) - publishers = [] - user_publisher = user - user_publisher.id = user.rid - - publishers << user_publisher - publishers + user.institutions - end - -end diff --git a/app/controllers/old/welcome_controller.rb b/app/controllers/old/welcome_controller.rb deleted file mode 100644 index 9b7681179d235026580b07df755e55af4fcb68d8..0000000000000000000000000000000000000000 --- a/app/controllers/old/welcome_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -class WelcomeController < ApplicationController - include Pundit - - def index - @carousel = Carousel.all || [] - @highlights = policy_scope(LearningObject).limit(8).includes(:publisher, :language, :topics) - end - - def faq - end - - def contact - end - - def terms_of_service - end - -end diff --git a/app/controllers/v1/activities_controller.rb b/app/controllers/v1/activities_controller.rb index 8edf1d8aa7ea4ac3246158a4b3a4147d377899b8..3de2c8634d1eb13849a314c25e2b5eb7de823377 100644 --- a/app/controllers/v1/activities_controller.rb +++ b/app/controllers/v1/activities_controller.rb @@ -1,17 +1,22 @@ class V1::ActivitiesController < ApplicationController - before_action :authenticate_user!, only: [:my_activities] + include ::ResourceModel + before_action :authenticate_user! # 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/activities/my_activities - # GET v1/activities/my_activities.json - def my_activities - activities = PublicActivity::Activity.order("created_at DESC").where(owner_type: "User", owner_id: current_user).all - render json: activities + # GET v1/users/1/activities + # GET v1/users/1/activities.json + # Render specific user activities + # Only followers can see user activities + def user_activities + raise Pundit::NotAuthorizedError unless ActivitiyPolicy.new(current_user, resource_model).user_activities? + render json: resource_model.activities end end diff --git a/app/controllers/v1/collections_controller.rb b/app/controllers/v1/collections_controller.rb index 7ef5414ed980d4e007a4b836abbae5eeecd3e9a5..2deb8b8d2adfa62f66afa2d048d188874fe38124 100644 --- a/app/controllers/v1/collections_controller.rb +++ b/app/controllers/v1/collections_controller.rb @@ -2,6 +2,8 @@ class V1::CollectionsController < ApplicationController include ::SociableController include ::FollowableController include ::TaggableController + include ::DeletedObjectsController + include ::HighlightsController before_action :set_collection, only: [:show, :update, :destroy] before_action :authenticate_user!, only: [:create, :update, :destroy] @@ -9,7 +11,9 @@ class V1::CollectionsController < ApplicationController # GET /v1/collections # GET /v1/collections.json def index - render json: Collection.all + limit = params[:limit] || 10 + offset = params[:offset] || 0 + render json: Collection.limit(limit).offset(offset) end # GET /v1/collections/1 @@ -49,18 +53,13 @@ class V1::CollectionsController < ApplicationController private - # social concerns methods - def followable - set_collection - end - - def taggable - set_collection - end + def deleted_resource; Collection; end + def highlights_resource; Collection; end - def sociable - set_collection - end + # social concerns methods + 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/complaints_controller.rb b/app/controllers/v1/complaints_controller.rb index f8c68a2811c9b167d8680b376c73669819e223a6..b54b8b2f587e53a5c1f59de4e21e6f88ad82752a 100644 --- a/app/controllers/v1/complaints_controller.rb +++ b/app/controllers/v1/complaints_controller.rb @@ -1,4 +1,6 @@ class V1::ComplaintsController < ApplicationController + include ::DeletedObjectsController + before_action :authenticate_user!, only: [:create] # GET v1/complaint @@ -21,6 +23,10 @@ class V1::ComplaintsController < ApplicationController private + def deleted_resource + Complaint + end + def complaint_params params.require(:complaint).permit(:user_id, :description,:complaintable_id, :complaint_reason_id, :complaintable_type) end diff --git a/app/controllers/v1/institutions_controller.rb b/app/controllers/v1/institutions_controller.rb index 56021ea278777c2844e19a87e314d49fc253277c..bdc27523965dc29bec8b4e71ee6a67aa6d32218a 100644 --- a/app/controllers/v1/institutions_controller.rb +++ b/app/controllers/v1/institutions_controller.rb @@ -1,4 +1,5 @@ class V1::InstitutionsController < ApplicationController + include ::DeletedObjectsController before_action :set_institution, only: [:show, :update, :destroy, :users] before_action :authenticate_user!, only: [:create, :update, :destroy] @@ -51,6 +52,10 @@ class V1::InstitutionsController < ApplicationController private + def deleted_resource + Institution + end + def set_institution @institution = Institution.find(params[:id]) end diff --git a/app/controllers/v1/learning_objects_controller.rb b/app/controllers/v1/learning_objects_controller.rb index ff124dc4c4a707fd52bd3876dbe0ca442732c81a..19588ceb19cb620fb43dda41fddd0f3f389478f2 100644 --- a/app/controllers/v1/learning_objects_controller.rb +++ b/app/controllers/v1/learning_objects_controller.rb @@ -4,19 +4,24 @@ class V1::LearningObjectsController < ApplicationController include ::SociableController include ::TaggableController include ::Paginator + include ::DeletedObjectsController + include ::HighlightsController before_action :authenticate_user!, except: [:index, :show] before_action :set_learning_object, only: [:show, :update, :destroy] before_action :authorize!, only: [:show, :update, :destroy] def index - render json: ActiveModel::ArraySerializer.new(LearningObject.limit(limit).offset(offset).all) + limit = params[:limit] || 10 + offset = params[:offset] || 0 + serializer = params[:obaa].nil? ? LearningObjectSerializer : LearningObjectObaaSerializer + render json: LearningObject.includes(:tags, :publisher, :language, :license).limit(limit).offset(offset), each_serializer: serializer end # GET /learning_objects/1 # GET /learning_objects/1.json def show - render json: @learning_object + render json: params[:obaa].nil? ? @learning_object : LearningObjectObaaSerializer.new(@learning_object) end # POST /learning_objects @@ -51,13 +56,10 @@ class V1::LearningObjectsController < ApplicationController private - 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/licenses_controller.rb b/app/controllers/v1/licenses_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..a9bd87aa97cea7b4f0ae950fab257b702f35db7c --- /dev/null +++ b/app/controllers/v1/licenses_controller.rb @@ -0,0 +1,58 @@ +class V1::LicensesController < ApplicationController + before_action :authenticate_user!, only: [:create, :update, :destroy] + before_action :set_license, only: [:show, :update, :destroy] + + # GET /licenses + # GET /licenses.json + def index + render json: License.all, each_serializer: LicenseSerializer + end + + # GET /licenses/1 + # GET /licenses/1.json + def show + render json: @license + end + + # POST /licenses + # POST /licenses.json + def create + @license = License.new(license_params) + + if @license.save + render json: @license, status: :created + else + render json: @license.errors, status: :unprocessable_entity + end + end + + # PATCH/PUT /licenses/1 + # PATCH/PUT /licenses/1.json + def update + @license = License.find(params[:id]) + + if @license.update(license_params) + head :no_content + else + render json: @license.errors, status: :unprocessable_entity + end + end + + # DELETE /licenses/1 + # DELETE /licenses/1.json + def destroy + @license.destroy + + head :no_content + end + + private + + def set_license + @license = License.find(params[:id]) + end + + def license_params + params.require(:license).permit(:name, :description, :url, :image_url) + end +end diff --git a/app/controllers/v1/reviews_controller.rb b/app/controllers/v1/reviews_controller.rb index 0eb054edebb38ace3fcbf954f52676b706eb35d3..0a83f1248d07ab75ed8968f94b6aa558852fe76e 100644 --- a/app/controllers/v1/reviews_controller.rb +++ b/app/controllers/v1/reviews_controller.rb @@ -1,12 +1,13 @@ class V1::ReviewsController < ApplicationController + include ::DeletedObjectsController + include ::ResourceModel + before_action :set_review, only: [:show, :destroy, :rate] before_action :authenticate_user!, only: [:create, :rate, :destroy] # GET /v1/collections/1/reviews def index - render json: ActiveModel::ArraySerializer.new( - reviewable.reviews, - each_serializer: ReviewSerializer) + render json: reviewable.reviews, each_serializer: ReviewSerializer end # GET /v1/collections/1/reviews/1 @@ -72,10 +73,12 @@ class V1::ReviewsController < ApplicationController private + def deleted_resource + Review + 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/search_controller.rb b/app/controllers/v1/search_controller.rb index 2a1aabec64446e46cff50a1ce33c079d53976372..98563378a3b2b1cd254a72e6c27ad1d36ed66c1c 100644 --- a/app/controllers/v1/search_controller.rb +++ b/app/controllers/v1/search_controller.rb @@ -1,47 +1,30 @@ class V1::SearchController < ApplicationController - before_action :set_search # GET v1/search # GET v1/search.json def index - begin - render json: ActiveModel::ArraySerializer.new(search_service.fetch), status: :ok - rescue => e - if e.message == "Invalid search" - render json: @search.errors, status: :bad_request - else - render nothing: true, status: :internal_server_error - puts e.message - puts e.backtrace - end - end + render json: SearchService.search(@search, current_user), status: :ok + rescue SearchService::InvalidSearchError + render json: @search.errors, status: :bad_request end # GET v1/search/autocomplete # GET v1/search/autocomplete.json def autocomplete - begin - render json: ActiveModel::ArraySerializer.new(search_service.autocomplete), status: :ok - rescue => e - if e.message == "Invalid search" - render json: @search.errors, status: :bad_request - else - render nothing: true, status: :internal_server_error - puts e.message - puts e.backtrace - end - end + render json: SearchService.autocomplete(@search, current_user), status: :ok + rescue SearchService::InvalidSearchError + render json: @search.errors, status: :bad_request end private def set_search - @search = Search.new(params) + @search = Search.new(search_params) end - def search_service - @search_service ||= SearchService.new(@search, current_user) + # Never trust parameters from the scary internet, only allow the white list through. + def search_params + params.permit(:page, :results_per_page, :order, :query, :search_class) end - -end \ No newline at end of file +end diff --git a/app/controllers/v1/users_controller.rb b/app/controllers/v1/users_controller.rb index 67eccc9d00fead4293d00662eeec264346162176..d24e649cb34111b2afca7e2030268af7df9992f0 100644 --- a/app/controllers/v1/users_controller.rb +++ b/app/controllers/v1/users_controller.rb @@ -1,8 +1,9 @@ class V1::UsersController < ApplicationController include ::FollowableController + include ::DeletedObjectsController - before_action :set_user, only: [:show, :update, :destroy] - before_action :authenticate_user!, only: [:create, :update, :destroy] + before_action :set_user, only: [:show, :update, :destroy, :watching] + before_action :authenticate_user!, only: [:create, :update, :destroy, :watching] # GET /v1/users # GET /v1/users.json @@ -50,8 +51,20 @@ class V1::UsersController < ApplicationController end end + def watching + type = params[:object_type] + is_current = (@user.id == current_user.id) unless current_user.nil? + 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 + private + def deleted_resource + User + end + def followable set_user end @@ -64,5 +77,4 @@ class V1::UsersController < ApplicationController def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation, :terms_of_service, role_ids: []) end - end diff --git a/app/controllers/v1/versions_controller.rb b/app/controllers/v1/versions_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..b6861247329657849a5c7dea82914983daab1ff8 --- /dev/null +++ b/app/controllers/v1/versions_controller.rb @@ -0,0 +1,27 @@ +class V1::VersionsController < ApplicationController + include ::ResourceModel + + # GET v1/learning_objects/1/versions + # GET v1/learning_objects/1/versions.json + def index + render json: resource_model.versions + end + + # GET v1/learning_objects/1/versions/123 + # GET v1/learning_objects/1/versions/123.json + def show + resource = PaperTrail::Version.find(params[:id]) + render json: resource + end + + # POST /learning_objects/1/versions/234/checkout + def checkout + resource = PaperTrail::Version.find(params[:id]).reify + if resource.save + render json: resource + else + render nothing: true, status: :unprocessable_entity + end + end + +end diff --git a/app/models/application.rb b/app/models/application.rb new file mode 100644 index 0000000000000000000000000000000000000000..1485a35a47669e2229a076f027dac3eef4ee6959 --- /dev/null +++ b/app/models/application.rb @@ -0,0 +1,14 @@ +class Application < ActiveRecord::Base + belongs_to :user + + validates :domain, presence: true, uniqueness: true + validates :application_id, presence: true, uniqueness: true + before_create :generate_application_id + + private + + def generate_application_id + @application_id = SecureRandom.uuid.to_s + generate_application_id if self.class.find_by_application_id(@application_id) + end +end diff --git a/app/models/bookmark.rb b/app/models/bookmark.rb index 99344a15ef3e0c5828a57232ec360d74fa30c775..d49ca0269e01b952814ce0c8de0df78dbac95c4a 100644 --- a/app/models/bookmark.rb +++ b/app/models/bookmark.rb @@ -11,6 +11,8 @@ # class Bookmark < ActiveRecord::Base + # Example of Trackable: + # *current_user* create bookmark *bookmarkable* include Trackable belongs_to :user, counter_cache: true diff --git a/app/models/collection.rb b/app/models/collection.rb index 0121b15d79c47c2726a02b73d70a2c7602ef7150..ae5893b540b25d6c94757bf55d2290c92ff0f126 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' @@ -45,6 +46,9 @@ class Collection < ActiveRecord::Base searchkick language: 'brazilian', match: :word_start, searchable: [:name, :description, :author], callbacks: :async + acts_as_paranoid + has_paper_trail + def search_data { name: name, diff --git a/app/models/collection_item.rb b/app/models/collection_item.rb index aa4659532dd1ae8cf63b4b06148565f088bfebf5..02eedcbe136a7ebce9f84bec02936ab12979d384 100644 --- a/app/models/collection_item.rb +++ b/app/models/collection_item.rb @@ -12,8 +12,10 @@ # class CollectionItem < ActiveRecord::Base - belongs_to :collection + # *current_user* add item *collectionable* to *collection* + include Trackable + belongs_to :collection belongs_to :collectionable, polymorphic: true validates_presence_of :collection, :collectionable diff --git a/app/models/complaint.rb b/app/models/complaint.rb index a965eac3b87e8c5f86294a802cd8f99ffebd39ab..abe53017eedeb87cb3bbdcbf2539d3c4dc441727 100644 --- a/app/models/complaint.rb +++ b/app/models/complaint.rb @@ -13,6 +13,7 @@ # class Complaint < ActiveRecord::Base + # *current_user* create complaint about *complaint_reason* for *complaintable* include Trackable belongs_to :complaint_reason @@ -22,6 +23,9 @@ class Complaint < ActiveRecord::Base validates_presence_of :user, :complaintable, :description, :complaint_reason validates :user_id, uniqueness: { scope: [:complaintable_id, :complaintable_type] } + acts_as_paranoid + has_paper_trail + def reason complaint_reason.reason end diff --git a/app/models/complaint_reason.rb b/app/models/complaint_reason.rb index 26ee8777f0c3631591f4d29ba5a7b34da7cd51e4..468f59d301d629ba342ff9b1678b7717b2a6549b 100644 --- a/app/models/complaint_reason.rb +++ b/app/models/complaint_reason.rb @@ -9,8 +9,12 @@ # class ComplaintReason < ActiveRecord::Base + # *current_user* create complaint reason + # Only admins can create complaint reasons + include Trackable + has_many :complaints validates_presence_of :reason - + has_paper_trail end 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/metadatable.rb b/app/models/concerns/metadatable.rb index 07bd3ac398f424e522a0c2ab3a0f9b7b1a1b17a3..28ba9409496a851fb81de6a3edc39b1b77c60ecf 100644 --- a/app/models/concerns/metadatable.rb +++ b/app/models/concerns/metadatable.rb @@ -7,19 +7,11 @@ module Metadatable serialize :metadata, ArraySerializer end - def get_metadata_value_of key + def get_metadata_value_of(key) get_metadata_values_of(key).first end - def get_metadata_values_of key - values = [] - unless metadata.blank? - metadata.each do |m| - m = m.with_indifferent_access - values << m["value"] if m["key"] == key - end - end - values + def get_metadata_values_of(key) + metadata[key].blank? ? [] : metadata[key] end - end diff --git a/app/models/concerns/reputationable.rb b/app/models/concerns/reputationable.rb index 59f8a4da614b28dad688ca6336de23b421cb8129..13697eb0598d3d444a80c563fbda111c29bb1412 100644 --- a/app/models/concerns/reputationable.rb +++ b/app/models/concerns/reputationable.rb @@ -1,6 +1,10 @@ module Reputationable extend ActiveSupport::Concern + included do + delegate :count, to: :followers, prefix: true + end + def submitted_objects learning_objects.count end @@ -8,7 +12,7 @@ module Reputationable def reviews_score_average scores = learning_objects.map(&:review_ratings_average) - return 0.0 if scores.size == 0 + return 0.0 if scores.empty? scores.inject(0.0) { |a, e| a + e }.to_f / scores.size.to_f end @@ -35,14 +39,10 @@ module Reputationable array.inject(0.0) { |a, e| a + e } / array.size end - def followers_count - followers.count - end - def learning_objects_recently_submitted return 0.0 if learning_objects.nil? - learning_objects.where('created_at >= ?', (Time.now - 2.months)).count + learning_objects.where('created_at >= ?', (Time.current - 2.months)).count end def collections_score_average 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/concerns/taggable.rb b/app/models/concerns/taggable.rb index aedd68087056700b9847f28715fedbb422146d50..bf62302ea155c014411a4d7467e819e39b6b12fa 100644 --- a/app/models/concerns/taggable.rb +++ b/app/models/concerns/taggable.rb @@ -5,6 +5,4 @@ module Taggable has_many :taggings, as: :taggable, dependent: :destroy has_many :tags, through: :taggings, dependent: :destroy end - - end diff --git a/app/models/concerns/thumbnailable.rb b/app/models/concerns/thumbnailable.rb index e22d871bfba9593fbd6f1790d20410631cef7d0c..123ffb7de4f048ba8e712fe8e04d1e6f39899613 100644 --- a/app/models/concerns/thumbnailable.rb +++ b/app/models/concerns/thumbnailable.rb @@ -2,7 +2,7 @@ module Thumbnailable extend ActiveSupport::Concern included do - has_attached_file :thumbnail, styles: { medium: '530x300', small: '250x140' }, default_url: 'learning-object-preview.png' + has_attached_file :thumbnail, styles: { medium: '530x300', small: '250x140' }, default_url: '' validates_attachment_content_type :thumbnail, content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'] end diff --git a/app/models/concerns/trackable.rb b/app/models/concerns/trackable.rb index 7d8455f3f63d0ffe1022b6a7338f0fcb3acc5f30..c0b2c747e084b47917e7cdbe140ad5829f25f807 100644 --- a/app/models/concerns/trackable.rb +++ b/app/models/concerns/trackable.rb @@ -3,7 +3,7 @@ module Trackable include PublicActivity::Model included do - tracked owner: Proc.new{ |controller, model| controller.current_user } + tracked owner: proc { |controller, model| + model.try(:user) || model.try(:owner) || controller.try(:current_user) } end - end diff --git a/app/models/download.rb b/app/models/download.rb index 53c6d05f0d54809affe850328880a5c76e73471f..3435d9bcf3182bf23530c60549dbd0e8c29cbaa7 100644 --- a/app/models/download.rb +++ b/app/models/download.rb @@ -11,6 +11,7 @@ # class Download < ActiveRecord::Base + # *current_user* download *downloadable* include Trackable belongs_to :downloadable, polymorphic: true, counter_cache: true diff --git a/app/models/follow.rb b/app/models/follow.rb index 464d4508b2d9dba87b322150c12a46cd313eba93..7c32adc1ba5ba1a449d0e355de90b901e356613e 100644 --- a/app/models/follow.rb +++ b/app/models/follow.rb @@ -11,6 +11,7 @@ # class Follow < ActiveRecord::Base + # *current_user* follows *followable* include Trackable belongs_to :followable, polymorphic: true, counter_cache: true diff --git a/app/models/institution.rb b/app/models/institution.rb index f0e06793bdbb6995a1a79b301ce8cbd9b6879736..5c380822a1db59c0c7f5603403b1581425ceef45 100644 --- a/app/models/institution.rb +++ b/app/models/institution.rb @@ -14,12 +14,19 @@ class Institution < ActiveRecord::Base include Tagger + + # *current_user* add member for instituion *name* + # *current_user* create instituion + # *current_user* destroy instituion + # *current_user* update instituion include Trackable has_and_belongs_to_many :users - has_many :learning_objects, as: :publisher has_many :collections, as: :owner validates_presence_of :name + + acts_as_paranoid + has_paper_trail end diff --git a/app/models/learning_object.rb b/app/models/learning_object.rb index 63f5dc60e7989235c95b89a56f4be1c76e0244b6..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,11 @@ class LearningObject < ActiveRecord::Base include Scoreable include Thumbnailable include Taggable + include Highlights + + # *current_user* create learning object + # *current_user* update learning object + # *current_user* destroy learning object include Trackable has_many :collection_items, as: :collectionable @@ -47,17 +52,20 @@ class LearningObject < ActiveRecord::Base belongs_to :publisher, polymorphic: true belongs_to :language + belongs_to :license belongs_to :object_type 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) } searchkick language: 'brazilian', match: :word_start, searchable: [:name, :description, :author, :object_type], callbacks: :async + acts_as_paranoid + def search_data source = (!publisher.nil? && publisher.is_a?(Institution)) ? publisher.name : nil type = object_type.try(:name) @@ -129,4 +137,5 @@ class LearningObject < ActiveRecord::Base def user_category publisher.try('user_category') end + end diff --git a/app/models/license.rb b/app/models/license.rb new file mode 100644 index 0000000000000000000000000000000000000000..5bc15243c08c0d622808a74920fa68bba4ca0776 --- /dev/null +++ b/app/models/license.rb @@ -0,0 +1,3 @@ +class License < ActiveRecord::Base + validates :name, presence: true +end diff --git a/app/models/like.rb b/app/models/like.rb index 58d242d5184f386d7b7388939e37cc1329fff159..d9e98d20d3b90bf2faff5c0a566ada4d20a90684 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -11,6 +11,8 @@ # class Like < ActiveRecord::Base + # *current_user* likes *likeable* + # *current_user* unlikes *likeable* include Trackable belongs_to :likeable, polymorphic: true, counter_cache: true diff --git a/app/models/rate.rb b/app/models/rate.rb index f18629a957419fb1588a65e500be8c8f228d2cad..5b7a27e6372608dd1d3124d3f8e5adf989fe04c8 100644 --- a/app/models/rate.rb +++ b/app/models/rate.rb @@ -9,6 +9,7 @@ # created_at :datetime not null # updated_at :datetime not null class Rate < ActiveRecord::Base + # *current_user* rate a review *review* include Trackable belongs_to :user diff --git a/app/models/review.rb b/app/models/review.rb index fd840a94b87e990647bc5ff014f546fe282c824e..cb8cdb03aa96a1b7f9cab31041cf63cdcce4ba53 100644 --- a/app/models/review.rb +++ b/app/models/review.rb @@ -16,6 +16,7 @@ # class Review < ActiveRecord::Base + # *current_user* review *reviewable* include Trackable belongs_to :reviewable, polymorphic: true @@ -34,6 +35,9 @@ class Review < ActiveRecord::Base default_scope { includes(:user) } + acts_as_paranoid + has_paper_trail + def rating_values review_ratings.includes(:rating).map { |r| {rating: r.rating, value: r.value} } end diff --git a/app/models/score.rb b/app/models/score.rb index d4d2ab4bb58baed039a1ffda4fa5791ba9dd4a74..d7e98121091fa868e3ce6b0fb9b39441dc63bb48 100644 --- a/app/models/score.rb +++ b/app/models/score.rb @@ -21,6 +21,7 @@ class Score < ActiveRecord::Base validates_numericality_of :weight scope :object_type, ->(name) { where('? = ANY (score_type)', name) } + has_paper_trail def max_value score_user_categories.maximum(:value) diff --git a/app/models/search.rb b/app/models/search.rb index f0e0f1bf38e30933398e3112cfa4ea380619ada3..4f99e8fe47dd2abbb70513f4b1a1100026a3ffe6 100644 --- a/app/models/search.rb +++ b/app/models/search.rb @@ -1,26 +1,25 @@ class Search include ActiveModel::Model - attr_accessor :page, :results_per_page, :order, :query, :search_class, :tags, :types, :sources validates_presence_of :query, :results_per_page, :order, :search_class validates_numericality_of :results_per_page, greater_than: 0 - validates :search_class, inclusion: {in: %w(LearningObject Collection User)} + validates :search_class, inclusion: { in: ::SearchService::SEARCH_CLASSES } - def initialize(params={}) - super(defaults.merge(params.select { |key,value| self.respond_to? key })) + def initialize(params = {}) + super(defaults.merge(params.select { |key, _value| respond_to? key })) end def learning_object? - @search_class == "LearningObject" + search_class == 'LearningObject' end def collection? - @search_class == "Collection" + search_class == 'Collection' end def user? - @search_class == "User" + search_class == 'User' end private @@ -33,5 +32,4 @@ class Search results_per_page: 10 } end - -end \ No newline at end of file +end diff --git a/app/models/share.rb b/app/models/share.rb index 7be91509ed1d5a6536775753d0859484b23fe887..4816f94a60291f7f2d42166a8ce70c8bd0a08221 100644 --- a/app/models/share.rb +++ b/app/models/share.rb @@ -11,6 +11,7 @@ # class Share < ActiveRecord::Base + # *current_user* shares *shareable* include Trackable belongs_to :shareable, polymorphic: true, counter_cache: true diff --git a/app/models/tagging.rb b/app/models/tagging.rb index ed698885ac0e5353a4039b1211cc8ac367dcb0e6..d926c6db5500dfe223cf7643c3b13915166c0d25 100644 --- a/app/models/tagging.rb +++ b/app/models/tagging.rb @@ -1,4 +1,5 @@ class Tagging < ActiveRecord::Base + # *current_user* tag *taggable* with *tag* include Trackable belongs_to :tagger, polymorphic: true diff --git a/app/models/user.rb b/app/models/user.rb index 0f03e7aeafbc903c6d15c625ade7ee184def7b5f..ecfd182636edbbb67ccb4da6b24f65aa3a6e85f7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -53,18 +53,15 @@ class User < ActiveRecord::Base 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 :views has_many :downloads has_many :likes has_many :shares has_many :follows - has_many :reviews + has_many :applications after_create :default_role @@ -74,6 +71,9 @@ class User < ActiveRecord::Base searchkick language: 'brazilian', match: :word_start, searchable: [:name], callbacks: :async + acts_as_paranoid + has_paper_trail + def search_data { name: name, @@ -117,8 +117,34 @@ class User < ActiveRecord::Base !follows.where(followable_id: followable.id, followable_type: followable.class.name).blank? end + # This function permits see what person is following. + # For current user, list all users and all collections. But, + # if, isn't current user, list only users, and public collections which this person follows. + def watching(followable_type, is_current_user = true) + f = Follow.where(user_id: id, followable_type: followable_type).all + + # If type collection, and isn't current_user, so should list only public collections + if followable_type.to_s == 'Collection' && !is_current_user + f = Follow.joins('INNER JOIN collections ON follows.followable_id = collections.id').where( + "follows.user_id = #{id} " \ + 'AND follows.followable_type = \'Collection\' ' \ + 'AND collections.id = follows.followable_id ' \ + 'AND collections.privacy = \'public\'' + ) + end + + f + end + # ~~~~ 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/models/view.rb b/app/models/view.rb index 72579609f1fc97f0a61283772ed71c0789c9ee46..94f27f19e255fa086dc2f5ade9e92f851e2d7ec2 100644 --- a/app/models/view.rb +++ b/app/models/view.rb @@ -11,6 +11,9 @@ # class View < ActiveRecord::Base + # *current_user* views *viewable* + include Trackable + belongs_to :viewable, polymorphic: true, counter_cache: true belongs_to :user 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/policies/license_policy.rb b/app/policies/license_policy.rb new file mode 100644 index 0000000000000000000000000000000000000000..adb7750ca3bdd3402ead90e2f67e32907d7b7e76 --- /dev/null +++ b/app/policies/license_policy.rb @@ -0,0 +1,21 @@ +class LicensePolicy < ApplicationPolicy + def index? + record + end + + def show? + record + end + + def create? + record if user.is_admin? + end + + def update? + record if user.is_admin? + end + + def destroy? + record if user.is_admin? + end +end diff --git a/app/serializers/follow_serializer.rb b/app/serializers/follow_serializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..507f2d9830c7c5c079ee7cbeb44b776a0e76c0d5 --- /dev/null +++ b/app/serializers/follow_serializer.rb @@ -0,0 +1,5 @@ +class FollowSerializer < ActiveModel::Serializer + has_one :followable + + attributes :id, :user_id +end diff --git a/app/serializers/learning_object/attachment_serializer.rb b/app/serializers/learning_object/attachment_serializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..2e5b87370fa97dceb34f82dd50de6d4d6cdee67b --- /dev/null +++ b/app/serializers/learning_object/attachment_serializer.rb @@ -0,0 +1,3 @@ +class LearningObject::AttachmentSerializer < ActiveModel::Serializer + attributes :id, :name, :retrieve_link, :description, :format, :mime_type, :size, :bundle_name, :learning_object_id, :created_at, :updated_at, :id_dspace, :thumbnail, :cache_link +end diff --git a/app/serializers/learning_object_obaa_serializer.rb b/app/serializers/learning_object_obaa_serializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..f6d520e433eb10aeef1007f3b4efe5c66c2dc060 --- /dev/null +++ b/app/serializers/learning_object_obaa_serializer.rb @@ -0,0 +1,67 @@ +class LearningObjectObaaSerializer < ActiveModel::Serializer +# "educational": { +# "description": "? não existe no PortalMecHomologa" +# }, + + def general + { + title: object.name, + description: object.description, + keywords: object.tags.map(&:name).join(','), + created_at: object.created_at, + updated_at: object.updated_at, + thumbnail: object.default_thumbnail, + score: object.score, + likes_count: object.likes_count, + shares_count: object.shares_count, + acessibility: '' + } + end + + def identifier + { + catalog: 'PortalMec', + entry: object.id, + language: object.language.try(:code) + } + end + + def technical + { + location: object.default_attachment.try(:retrieve_url), + format: object.default_attachment.try(:mime_type) + } + end + + def rights + { + copyrightAndOhterRestrictions: 'true', + cost: 'false', + description: object.license.try(:name) + } + end + + def metametadata + { + identifier: { + catalog: 'PortalMec', + name: object.publisher.try(:name), + entry_type: object.publisher.class.name, + entry: object.publisher.try(:id) + }, + contribute: { + role: 'Criador', + entity: object.author, + date: object.created_at + }, + metadataSchema: 'OBAAv1.0', + language: object.language.try(:name) + } + end + + # attributes :id , :name, :created_at, :updated_at, :description, :author, :score, :likes_count + attributes :id, :general, :identifier, :technical, :rights, :metametadata + + # has_many :tags + # has_many :attachments +end diff --git a/app/serializers/learning_object_serializer.rb b/app/serializers/learning_object_serializer.rb index 58e096c5623fb8a9d5f8bbc1215d858c45001077..5d51578f8c2bd95d96560a9e620b8a0cf6b179c1 100644 --- a/app/serializers/learning_object_serializer.rb +++ b/app/serializers/learning_object_serializer.rb @@ -1,5 +1,22 @@ class LearningObjectSerializer < ActiveModel::Serializer - attributes :id , :name, :created_at, :updated_at, :description, :author, :score, :likes_count + def default_location + object.default_attachment.try(:retrieve_url) + end + + def default_mime_type + object.default_attachment.try(:mime_type) + end + + def default_attachment_id + object.default_attachment.try(:id) + end + + def thumbnail + object.default_thumbnail + end + + attributes :id, :name, :description, :author, :thumbnail, :publisher, :language, :default_attachment_id, :default_location, :default_mime_type, :score, :license, :likes_count, :shares_count, :created_at, :updated_at + has_many :tags has_many :attachments end diff --git a/app/serializers/license_serializer.rb b/app/serializers/license_serializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..52cc601b822ac7fad57128b4b42e49524482fd77 --- /dev/null +++ b/app/serializers/license_serializer.rb @@ -0,0 +1,3 @@ +class LicenseSerializer < ActiveModel::Serializer + attributes :id, :name, :description, :url, :image_url +end diff --git a/app/serializers/paper_trail/version_serializer.rb b/app/serializers/paper_trail/version_serializer.rb new file mode 100644 index 0000000000000000000000000000000000000000..039afe83b8104237e207266d7bb48db7695c6579 --- /dev/null +++ b/app/serializers/paper_trail/version_serializer.rb @@ -0,0 +1,3 @@ +class PaperTrail::VersionSerializer < ActiveModel::Serializer + attributes :id, :item, :event, :whodunnit, :created_at, :object +end diff --git a/app/serializers/public_activity/activity_serializer.rb b/app/serializers/public_activity/activity_serializer.rb index 42a4b063a1b61594b109a30c0367137da1282a9e..fc1439de5de8fa1eeb23f826d067c56fdbddc48a 100644 --- a/app/serializers/public_activity/activity_serializer.rb +++ b/app/serializers/public_activity/activity_serializer.rb @@ -1,3 +1,3 @@ class PublicActivity::ActivitySerializer < ActiveModel::Serializer - attributes :id, :owner + attributes :id, :owner, :trackable, :recipient, :parameters, :created_at end 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/services/search_service.rb b/app/services/search_service.rb index 7a472ab7ee7c429ff6afee2f4bab7b2a438efc37..c8883fcea7c33a44f98a823040b1fca12feecc03 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -1,129 +1,20 @@ -class SearchService +module SearchService + SEARCH_CLASSES = %w(LearningObject Collection User) - attr_accessor :search + class InvalidSearchError < StandardError; end - def initialize(search, user) - @search = search - @user = user + def self.search(search, user) + model = instance(search, user) + model.search.results end - def fetch - validate - return search_learning_object if @search.learning_object? - return search_collection if @search.collection? - return search_user if @search.user? + def self.autocomplete(search, user) + model = instance(search, user) + model.autocomplete end - def autocomplete - validate - - params_hash = {} - get_thumbnail = nil - get_type = nil - if @search.learning_object? - params_hash = { where: {state: validate_object}, - fields: ['name^10', 'description', 'author'] } - get_thumbnail = Proc.new { |obj| obj.default_thumbnail } - get_type = Proc.new { |obj| obj.object_type.try(:name) } - - elsif @search.collection? - params_hash = { where: {privacy: "public"}, - fields: ['name^10', 'description', 'owner'] } - get_thumbnail = Proc.new { |obj| "/assets/icons/collection" } - get_type = Proc.new { |obj| "Collection"} - - else #User - params_hash = { fields: ['name'] } - get_thumbnail = Proc.new { |obj| obj.avatar.url(:thumb) } - get_type = Proc.new { |obj| "User" } - end - - autocomplete_search(Object.const_get(@search.search_class), @search.query, params_hash, get_type, get_thumbnail) - end - - private - - def validate - raise "Invalid search" unless @search.valid? + def self.instance(search, user) + raise InvalidSearchError unless search.valid? + "SearchService::#{search.search_class}".constantize.new(search, user) end - - def search_learning_object - LearningObject.search(@search.query, where: lo_where_hash, order: lo_order_hash(@search.order), page: @search.page, per_page: @search.results_per_page).results - end - - def search_collection - Collection.search(@search.query, where: {privacy: "public"}, order: col_order_hash(@search.order), page: @search.page, per_page: @search.results_per_page).results - end - - def search_user - User.search(@search.query, order: user_order_hash(@search.order), page: @search.page, per_page: @search.results_per_page).results - end - - def autocomplete_search(search_class, query, params_hash={}, get_type, get_thumbnail) - response = [] - search_params = { limit: 10, misspellings: { below: 5 } } - objs = search_class.search(query, search_params.merge(params_hash)) - objs.each do |obj| - hash = {} - hash["id"] = obj.id - hash["name"] = obj.name - hash["type"] = get_type.call(obj) - hash["thumbnail"] = get_thumbnail.call(obj) - response << hash - end - response - end - - def lo_where_hash - hash = {} - hash[:tags] = @search.tags unless @search.tags.blank? - hash[:object_type] = @search.types unless @search.types.blank? - hash[:source] = @search.sources unless @search.sources.blank? - hash[:state] = validate_object - hash.blank? ? nil : hash - end - - def lo_order_hash(order) - case order - when 'author' - { author: {order: :asc, unmapped_type: :string} } - when 'publicationasc' - { published_at: {order: :asc, unmapped_type: :timestamp} } - when 'publicationdesc' - { published_at: {order: :desc, unmapped_type: :timestamp} } - when 'title' - { name: {order: :asc, unmapped_type: :string} } - else - { score: {order: :desc, unmapped_type: :integer} } - end - end - - def col_order_hash(order) - case order - when 'author' - { owner: {order: :asc, unmapped_type: :string} } - when 'publicationasc' - { created_at: {order: :asc, unmapped_type: :timestamp} } - when 'publicationdesc' - { created_at: {order: :desc, unmapped_type: :timestamp} } - when 'title' - { name: {order: :asc, unmapped_type: :string} } - else - { score: {order: :desc, unmapped_type: :integer} } - end - end - - def user_order_hash(order) - if order == 'title' - { name: {order: :asc, unmapped_type: :string} } - else - { score: {order: :desc, unmapped_type: :integer} } - end - end - - def validate_object - return 'published' unless !@user.nil? && @user.is_admin? - return ['published', 'suspended', 'draft'] - end - -end \ No newline at end of file +end diff --git a/app/services/search_service/collection.rb b/app/services/search_service/collection.rb new file mode 100644 index 0000000000000000000000000000000000000000..b5c17c3a36d1a4117b8939ae7347dec075c18c20 --- /dev/null +++ b/app/services/search_service/collection.rb @@ -0,0 +1,29 @@ +module SearchService + class Collection < Model + def search + ::Collection.search(@search.query, where: { privacy: 'public' }, order: order_hash, page: @search.page, per_page: @search.results_per_page) + end + + def autocomplete + params = { where: { privacy: 'public' }, + fields: ['name^10', 'description', 'owner'] } + result = ::Collection.search(@search.query, autocomplete_params.merge(params)) + + thumbnail = proc { |_obj| '/assets/icons/collection' } + type = proc { |_obj| 'Collection' } + autocomplete_render(result, type, thumbnail) + end + + private + + def order_hash + case @search.order + when 'author' then { owner: { order: :asc, unmapped_type: :string } } + when 'publicationasc' then { created_at: { order: :asc, unmapped_type: :timestamp } } + when 'publicationdesc' then { created_at: { order: :desc, unmapped_type: :timestamp } } + when 'title' then { name: { order: :asc, unmapped_type: :string } } + else { score: { order: :desc, unmapped_type: :integer } } + end + end + end +end diff --git a/app/services/search_service/learning_object.rb b/app/services/search_service/learning_object.rb new file mode 100644 index 0000000000000000000000000000000000000000..c53a300febdfb77160bf5eca942d6c0ccd4b7d58 --- /dev/null +++ b/app/services/search_service/learning_object.rb @@ -0,0 +1,43 @@ +module SearchService + class LearningObject < Model + def search + ::LearningObject.search(@search.query, where: where_hash, order: order_hash, page: @search.page, per_page: @search.results_per_page) + end + + def autocomplete + params = { where: { state: validate_object }, + fields: ['name^10', 'description', 'author'] } + result = ::LearningObject.search(@search.query, autocomplete_params.merge(params)) + + thumbnail = proc { |obj| obj.default_thumbnail } + type = proc { |obj| obj.object_type.try(:name) } + autocomplete_render(result, type, thumbnail) + end + + private + + def where_hash + hash = {} + hash[:tags] = @search.tags unless @search.tags.blank? + hash[:object_type] = @search.types unless @search.types.blank? + hash[:source] = @search.sources unless @search.sources.blank? + hash[:state] = validate_object + hash.blank? ? nil : hash + end + + def order_hash + case @search.order + when 'author' then { author: { order: :asc, unmapped_type: :string } } + when 'publicationasc' then { published_at: { order: :asc, unmapped_type: :timestamp } } + when 'publicationdesc' then { published_at: { order: :desc, unmapped_type: :timestamp } } + when 'title' then { name: { order: :asc, unmapped_type: :string } } + else { score: { order: :desc, unmapped_type: :integer } } + end + end + + def validate_object + return 'published' unless !@user.nil? && @user.is_admin? + %w(published suspended draft) + end + end +end diff --git a/app/services/search_service/model.rb b/app/services/search_service/model.rb new file mode 100644 index 0000000000000000000000000000000000000000..e1a0bbb6bf43da38383cbee5c0cbe577db8b0b7f --- /dev/null +++ b/app/services/search_service/model.rb @@ -0,0 +1,35 @@ +module SearchService + class Model + def initialize(search, user) + raise 'Invalid search' unless search.valid? + + @search = search + @user = user + end + + def search + raise 'Must implement!' + end + + def autocomplete + raise 'Must implement!' + end + + private + + def autocomplete_params + { limit: 10, misspellings: { below: 5 } } + end + + def autocomplete_render(result, type, thumbnail) + result.map do |obj| + { + id: obj.id, + name: obj.name, + type: type.call(obj), + thumbnail: thumbnail.call(obj) + } + end + end + end +end diff --git a/app/services/search_service/user.rb b/app/services/search_service/user.rb new file mode 100644 index 0000000000000000000000000000000000000000..c7ffef549acbdcc0fd80dfebaee0d5f14a2dff72 --- /dev/null +++ b/app/services/search_service/user.rb @@ -0,0 +1,22 @@ +module SearchService + class User < Model + def search + ::User.search(@search.query, order: order_hash, page: @search.page, per_page: @search.results_per_page) + end + + def autocomplete + result = ::User.search(@search.query, autocomplete_params.merge(fields: ['name'])) + + thumbnail = proc { |obj| obj.avatar.url(:thumb) } + type = proc { |_obj| 'User' } + autocomplete_render(result, type, thumbnail) + end + + private + + def order_hash + return { name: { order: :asc, unmapped_type: :string } } if @search.order == 'title' + { score: { order: :desc, unmapped_type: :integer } } + end + end +end 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/environments/development.rb b/config/environments/development.rb index eb3772c3a0867beabd00a672cf5c425b64731fa7..987efaf25f29e895293756ea1e7bc3c1703b2bad 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -51,5 +51,9 @@ Rails.application.configure do # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + #config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } + # Lets define mailcatcher configs + config.action_mailer.delivery_method = :smtp + config.action_mailer.smtp_settings = { address: 'localhost', port: 1025 } config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } end diff --git a/config/feature.yml b/config/feature.yml index 078483a61535eabf09ad0ed4037353244f30f274..b5aa6837a4ad98cc4ae3b1a32159f660f77f09ba 100644 --- a/config/feature.yml +++ b/config/feature.yml @@ -1,11 +1,11 @@ development: features: - barra_brasil: false + allow_client_application: false test: features: - barra_brasil: true + allow_client_application: true production: features: - barra_brasil: true \ No newline at end of file + allow_client_application: false diff --git a/config/initializers/paper_trail.rb b/config/initializers/paper_trail.rb new file mode 100644 index 0000000000000000000000000000000000000000..442b5f789ce70fcc93ffac5ab211d24668919884 --- /dev/null +++ b/config/initializers/paper_trail.rb @@ -0,0 +1 @@ +PaperTrail.config.track_associations = false \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 0c9b6275987f925de1a01609a78803b8bc3f7461..4b045a9eb95bb5f4d2c8d84a188b34fb7ff89cd8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,12 @@ Rails.application.routes.draw do require 'sidekiq/web' mount Sidekiq::Web, at: '/sidekiq' + concern :deletable do + collection do + get :deleted + end + end + concern :followable do member do post 'follow', as: :follow, action: :follow @@ -24,46 +30,74 @@ Rails.application.routes.draw do end concern :reviewable do - resources :reviews, except: :update do + resources :reviews, only: [:index, :create, :show, :destroy], concerns: :deletable do member do post :rate end 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 + concern :versionable do + resources :versions, only: [:show, :index] do + member do + post :checkout + end + end + end + scope :v1 do mount_devise_token_auth_for 'User', skip: [:omniauth_callbacks], at: :auth end namespace :v1 do - #activities - get :activities, to: 'activities#index' + resources :activities, only: :index - resources :users, concerns: :followable do + resources :users, concerns: [:followable, :deletable] do member do resources :bookmarks, module: 'users', only: [:index, :create, :destroy] + get 'watching/:object_type', to: 'users#watching' + get 'activities', to: 'activities#user_activities' end end - get :search, to: 'search#index' - get 'search/autocomplete', to: 'search#autocomplete' - resources :collections, concerns: [:followable, :sociable, :reviewable, :taggable] - resources :learning_objects, concerns: [:sociable, :reviewable, :taggable] do + + # search routes + resources :search, only: :index do + collection do + get :autocomplete + end + end + + 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 end end - resources :institutions do + + resources :institutions, concerns: :deletable do member do get :users, to: 'institutions#users' end end - resources :scores, only: [:index, :update] - resources :object_types, except: [:new, :edit] - resources :mime_types, except: [:new, :edit] + + resources :complaints, only: [:index, :create], concerns: :deletable resources :languages, except: [:new, :edit] - resources :complaints, only: [:index, :create] + resources :licenses, except: [:new, :edit] + resources :mime_types, except: [:new, :edit] + resources :object_types, except: [:new, :edit] resources :roles, except: [:new, :edit] + resources :scores, only: [:index, :update] post '/package', to: 'packages#link' end diff --git a/db/migrate/20160512135942_add_deleted_at_to_learning_objects.rb b/db/migrate/20160512135942_add_deleted_at_to_learning_objects.rb new file mode 100644 index 0000000000000000000000000000000000000000..30a6ed6f0bb5262ae8fbef1960ddf0b698833bf8 --- /dev/null +++ b/db/migrate/20160512135942_add_deleted_at_to_learning_objects.rb @@ -0,0 +1,6 @@ +class AddDeletedAtToLearningObjects < ActiveRecord::Migration + def change + add_column :learning_objects, :deleted_at, :datetime + add_index :learning_objects, :deleted_at + end +end diff --git a/db/migrate/20160512140101_add_deleted_at_to_collections.rb b/db/migrate/20160512140101_add_deleted_at_to_collections.rb new file mode 100644 index 0000000000000000000000000000000000000000..820a98d6daafdd9410f271a297e4123a0db723c8 --- /dev/null +++ b/db/migrate/20160512140101_add_deleted_at_to_collections.rb @@ -0,0 +1,6 @@ +class AddDeletedAtToCollections < ActiveRecord::Migration + def change + add_column :collections, :deleted_at, :datetime + add_index :collections, :deleted_at + end +end diff --git a/db/migrate/20160512140142_add_deleted_at_to_complaints.rb b/db/migrate/20160512140142_add_deleted_at_to_complaints.rb new file mode 100644 index 0000000000000000000000000000000000000000..c34d7384c8619d85a96e7d9c257596b7be05c235 --- /dev/null +++ b/db/migrate/20160512140142_add_deleted_at_to_complaints.rb @@ -0,0 +1,6 @@ +class AddDeletedAtToComplaints < ActiveRecord::Migration + def change + add_column :complaints, :deleted_at, :datetime + add_index :complaints, :deleted_at + end +end diff --git a/db/migrate/20160512140201_add_deleted_at_to_institutions.rb b/db/migrate/20160512140201_add_deleted_at_to_institutions.rb new file mode 100644 index 0000000000000000000000000000000000000000..1ea68ab23c78cbaf77e21d98f78fd3b5a2a3e1ba --- /dev/null +++ b/db/migrate/20160512140201_add_deleted_at_to_institutions.rb @@ -0,0 +1,6 @@ +class AddDeletedAtToInstitutions < ActiveRecord::Migration + def change + add_column :institutions, :deleted_at, :datetime + add_index :institutions, :deleted_at + end +end diff --git a/db/migrate/20160512140234_add_deleted_at_to_reviews.rb b/db/migrate/20160512140234_add_deleted_at_to_reviews.rb new file mode 100644 index 0000000000000000000000000000000000000000..0794fe290ffc63fb810ff7d49cc8d4335825f254 --- /dev/null +++ b/db/migrate/20160512140234_add_deleted_at_to_reviews.rb @@ -0,0 +1,6 @@ +class AddDeletedAtToReviews < ActiveRecord::Migration + def change + add_column :reviews, :deleted_at, :datetime + add_index :reviews, :deleted_at + end +end diff --git a/db/migrate/20160512140321_add_deleted_at_to_users.rb b/db/migrate/20160512140321_add_deleted_at_to_users.rb new file mode 100644 index 0000000000000000000000000000000000000000..29ba1647ecaf78d5943413ce995a87ee8fe38973 --- /dev/null +++ b/db/migrate/20160512140321_add_deleted_at_to_users.rb @@ -0,0 +1,6 @@ +class AddDeletedAtToUsers < ActiveRecord::Migration + def change + add_column :users, :deleted_at, :datetime + add_index :users, :deleted_at + end +end diff --git a/db/migrate/20160512140322_ensure_versions_table_is_deleted.rb b/db/migrate/20160512140322_ensure_versions_table_is_deleted.rb new file mode 100644 index 0000000000000000000000000000000000000000..d79b2e5a181a0e0be5b5c429ae1eb93be5069ef3 --- /dev/null +++ b/db/migrate/20160512140322_ensure_versions_table_is_deleted.rb @@ -0,0 +1,6 @@ +class EnsureVersionsTableIsDeleted < ActiveRecord::Migration + def change + table = :versions + drop_table table if table_exists? table + end +end diff --git a/db/migrate/20160512143532_create_versions.rb b/db/migrate/20160512143532_create_versions.rb new file mode 100644 index 0000000000000000000000000000000000000000..dbe8ec81bbbf5332a0a037f7696d654c17f94e74 --- /dev/null +++ b/db/migrate/20160512143532_create_versions.rb @@ -0,0 +1,68 @@ +# This migration creates the `versions` table, the only schema PT requires. +# All other migrations PT provides are optional. +class CreateVersions < ActiveRecord::Migration + # Class names of MySQL adapters. + # - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`. + # - `Mysql2Adapter` - Used by `mysql2` gem. + MYSQL_ADAPTERS = [ + "ActiveRecord::ConnectionAdapters::MysqlAdapter", + "ActiveRecord::ConnectionAdapters::Mysql2Adapter" + ].freeze + + # The largest text column available in all supported RDBMS is + # 1024^3 - 1 bytes, roughly one gibibyte. We specify a size + # so that MySQL will use `longtext` instead of `text`. Otherwise, + # when serializing very large objects, `text` might not be big enough. + TEXT_BYTES = 1_073_741_823 + + def change + create_table :versions, versions_table_options do |t| + t.string :item_type, null: false + t.integer :item_id, null: false + t.string :event, null: false + t.string :whodunnit + t.text :object, limit: TEXT_BYTES + + # Known issue in MySQL: fractional second precision + # ------------------------------------------------- + # + # MySQL timestamp columns do not support fractional seconds unless + # defined with "fractional seconds precision". MySQL users should manually + # add fractional seconds precision to this migration, specifically, to + # the `created_at` column. + # (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html) + # + # MySQL users should also upgrade to rails 4.2, which is the first + # version of ActiveRecord with support for fractional seconds in MySQL. + # (https://github.com/rails/rails/pull/14359) + # + t.datetime :created_at + end + add_index :versions, [:item_type, :item_id] + end + + private + + # Even modern versions of MySQL still use `latin1` as the default character + # encoding. Many users are not aware of this, and run into trouble when they + # try to use PaperTrail in apps that otherwise tend to use UTF-8. Postgres, by + # comparison, uses UTF-8 except in the unusual case where the OS is configured + # with a custom locale. + # + # - https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html + # - http://www.postgresql.org/docs/9.4/static/multibyte.html + # + # Furthermore, MySQL's original implementation of UTF-8 was flawed, and had + # to be fixed later by introducing a new charset, `utf8mb4`. + # + # - https://mathiasbynens.be/notes/mysql-utf8mb4 + # - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html + # + def versions_table_options + if MYSQL_ADAPTERS.include?(connection.class.name) + { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" } + else + {} + end + end +end diff --git a/db/migrate/20160516125724_create_licenses.rb b/db/migrate/20160516125724_create_licenses.rb new file mode 100644 index 0000000000000000000000000000000000000000..dd447797a2598788e75f7ec9bb89296fa7522691 --- /dev/null +++ b/db/migrate/20160516125724_create_licenses.rb @@ -0,0 +1,12 @@ +class CreateLicenses < ActiveRecord::Migration + def change + create_table :licenses do |t| + t.string :name, index: true + t.text :description + t.string :image_url + t.string :url + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20160516125800_add_license_to_learning_objects.rb b/db/migrate/20160516125800_add_license_to_learning_objects.rb new file mode 100644 index 0000000000000000000000000000000000000000..283adeecb97a22884a57837fdea4211d7e8e1e9f --- /dev/null +++ b/db/migrate/20160516125800_add_license_to_learning_objects.rb @@ -0,0 +1,5 @@ +class AddLicenseToLearningObjects < ActiveRecord::Migration + def change + add_reference :learning_objects, :license, index: true + end +end diff --git a/db/migrate/20160517140326_create_applications.rb b/db/migrate/20160517140326_create_applications.rb new file mode 100644 index 0000000000000000000000000000000000000000..a13de010952b216b7b3dfd626a9a47e03f4aa110 --- /dev/null +++ b/db/migrate/20160517140326_create_applications.rb @@ -0,0 +1,14 @@ +class CreateApplications < ActiveRecord::Migration + def change + create_table :applications do |t| + t.string :name + t.string :domain + t.string :application_id + t.belongs_to :user, index: true, foreign_key: true + + t.timestamps null: false + end + add_index :applications, :domain, unique: true + add_index :applications, :application_id, unique: true + end +end 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/db/seeds.rb b/db/seeds.rb index 8259284babccce34d2a3b8b63af9301683277774..0cc0d52f1cfe1fb6431d0d6a224dd5cbcd6cc298 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -22,6 +22,7 @@ User.create( require_relative 'seeds/complaints' require_relative 'seeds/institutions' require_relative 'seeds/languages' +require_relative 'seeds/licenses' require_relative 'seeds/object_types' require_relative 'seeds/ratings' require_relative 'seeds/scores' diff --git a/db/seeds/licenses.rb b/db/seeds/licenses.rb new file mode 100644 index 0000000000000000000000000000000000000000..b670e4583944e2a1f170138b1a45a4130d492ec5 --- /dev/null +++ b/db/seeds/licenses.rb @@ -0,0 +1,10 @@ +License.create(name: 'CC BY', description: 'Creative Commons Atribuição', url: 'https://creativecommons.org/licenses/by/4.0/deed.pt_BR', image_url: 'https://licensebuttons.net/l/by/3.0/88x31.png') +License.create(name: 'CC BY-SA', description: 'Creative Commons Atribuição-CompartilhaIgual', url: 'https://creativecommons.org/licenses/by-sa/4.0/deed.pt_BR', image_url: 'https://licensebuttons.net/l/by-sa/3.0/88x31.png') +License.create(name: 'CC BY-ND', description: 'Creative Commons Atribuição-SemDerivações', url: 'https://creativecommons.org/licenses/by-nd/4.0/deed.pt_BR', image_url: 'https://licensebuttons.net/l/by-nd/3.0/88x31.png') +License.create(name: 'CC BY-NC', description: 'Creative Commons Atribuição-NãoComercial', url: 'https://creativecommons.org/licenses/by-nc/4.0/deed.pt_BR', image_url: 'https://licensebuttons.net/l/by-nc/3.0/88x31.png') +License.create(name: 'CC BY-NC-SA', description: 'Creative Commons Atribuição-NãoComercial-CompartilhaIgual', url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/deed.pt_BR', image_url: 'https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png') +License.create(name: 'CC BY-NC-ND', description: 'Creative Commons Atribuição-SemDerivações-SemDerivados', url: 'https://creativecommons.org/licenses/by-nc-nd/4.0/deed.pt_BR', image_url: 'https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png') +License.create(name: 'MIT', description: 'MIT', url: 'https://opensource.org/licenses/MIT', image_url: '') +License.create(name: 'GPL-2.0', description: 'GNU General Public License v2', url: 'https://opensource.org/licenses/GPL-2.0', image_url: '') +License.create(name: 'GPL-3.0', description: 'GNU General Public License v3', url: 'https://opensource.org/licenses/GPL-3.0', image_url: '') +License.create(name: 'Apache', description: 'Apache v2', url: 'https://www.apache.org/licenses/LICENSE-2.0', image_url: '') diff --git a/spec/auth_helper.rb b/spec/auth_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..7a763c45af393eb438620e80d081c1ce2710609a --- /dev/null +++ b/spec/auth_helper.rb @@ -0,0 +1,4 @@ +# authenticate the test application +def auth_app(app, request) + request.headers['PortalMEC-AppID'] = app.application_id +end \ No newline at end of file diff --git a/spec/controllers/v1/collections_controller_spec.rb b/spec/controllers/v1/collections_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..d5621cd6e5cff9f368b01e9667624c7dae5ce27b --- /dev/null +++ b/spec/controllers/v1/collections_controller_spec.rb @@ -0,0 +1,45 @@ +require 'rails_helper' + +RSpec.describe V1::CollectionsController, type: :controller do + fixtures :all + + it { should use_before_action(:authenticate_user!) } + it { should use_before_action(:set_collection) } + it { should route(:get, '/v1/collections').to(action: :index) } + + describe 'sociable actions' do + it { should use_before_action(:authorize_sociable!) } + it { should use_before_action(:view_object!) } + it { should route(:post, '/v1/collections/1/like').to(action: :like, id: 1) } + it { should route(:delete, '/v1/collections/1/like').to(action: :unlike, id: 1) } + + describe 'POST #like' do + before do + auth_app applications(:test_app), @request + post :like, id: collections(:ufpr).id + end + + context 'when user is authenticated' do + it do + #user = applications(:test_app).user + expect(response).to have_http_status(:created) + end + end + + context 'when user is not authenticated' do + it { expect(response).to have_http_status(:unauthorized) } + end + end + end + + describe 'GET #index' do + before do + auth_app applications(:test_app), @request + get :index + end + + it { expect(response.content_type).to eq('application/json') } + it { expect(response).to have_http_status(:ok) } + end + +end \ No newline at end of file diff --git a/spec/factories/applications.rb b/spec/factories/applications.rb new file mode 100644 index 0000000000000000000000000000000000000000..badcbdbec12f586ed5ddc0dadbe7e7b733ee6f8d --- /dev/null +++ b/spec/factories/applications.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + + factory :application do |f| + user + f.name { 'test app' } + f.domain { 'test.host' } + end + +end \ No newline at end of file diff --git a/spec/factories/collections.rb b/spec/factories/collections.rb new file mode 100644 index 0000000000000000000000000000000000000000..8b7761ccbaf537062a6a53b8b116a49e99ec451f --- /dev/null +++ b/spec/factories/collections.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + + factory :collection do |f| + owner + f.name { Faker::University.name } + f.privacy { 'public' } + end + +end \ No newline at end of file diff --git a/spec/factories/users.rb b/spec/factories/users.rb new file mode 100644 index 0000000000000000000000000000000000000000..09510c84e714612e680422705622ac5a55b8a16b --- /dev/null +++ b/spec/factories/users.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + + factory :user, aliases: [:owner] do |f| + f.name { Faker::Name.name } + f.email { Faker::Internet.email } + f.confirmed_at { '2015-10-10 15:30:22' } + end + +end \ No newline at end of file diff --git a/spec/models/application_spec.rb b/spec/models/application_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..004603d65dc7a0f1497017872bd5b5b9f9b98ec8 --- /dev/null +++ b/spec/models/application_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +RSpec.describe Application, type: :model do + + describe 'validate model' do + it { should belong_to :user } + it { should validate_presence_of(:domain) } + it { should validate_presence_of(:application_id) } + end + +end \ No newline at end of file diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..258bbf11d75ef86fed2789992c2f51b5ca6f0d39 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,58 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'auth_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migration and applies them before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/test/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..61e27385c3ed6390048ef9df5ae4434c1afc92a7 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,92 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/test/controllers/v1/institutions_controller_test.rb b/test/controllers/v1/institutions_controller_test.rb index ba90ef5db6a83ec69f82c9c089401f0c5b55116f..be23eca891c65e89be0a3ae1cd7d7bd2cf631b86 100644 --- a/test/controllers/v1/institutions_controller_test.rb +++ b/test/controllers/v1/institutions_controller_test.rb @@ -9,6 +9,7 @@ class V1::InstitutionControllerTest < ActionController::TestCase end test 'should user show institution' do + auth_application ufpr = institutions(:ufpr) get :show, id: ufpr.id assert_response :ok diff --git a/test/controllers/v1/licenses_controller_test.rb b/test/controllers/v1/licenses_controller_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..6cd9d7a9347e87286ac40d67f80852d06311e095 --- /dev/null +++ b/test/controllers/v1/licenses_controller_test.rb @@ -0,0 +1,50 @@ +require 'test_helper' + +class V1::LicensesControllerTest < ActionController::TestCase + tests V1::LicensesController + include Devise::TestHelpers + + setup do + @license = licenses(:one) + end + + test "should get index" do + skip + get :index + assert_response :success + assert_not_nil assigns(:licenses) + end + + test "should create license" do + auth_request users(:admin) + + assert_difference('License.count') do + post :create, license: { description: @license.description, name: @license.name, url: @license.url, image_url: @license.image_url } + end + + assert_response 201 + end + + test "should show license" do + skip + get :show, id: @license + assert_response :success + end + + test "should update license" do + auth_request users(:admin) + + put :update, id: @license, license: { description: @license.description, name: @license.name, url: @license.url, image_url: @license.image_url } + assert_response 204 + end + + test "should destroy license" do + auth_request users(:admin) + + assert_difference('License.count', -1) do + delete :destroy, id: @license + end + + assert_response 204 + end +end diff --git a/test/controllers/v1/search_controller_test.rb b/test/controllers/v1/search_controller_test.rb index f01d4994278c109a7c8cea7a55839ea822ee07b3..8fc542c7b351e365377ca11e4277d5322e640a3c 100644 --- a/test/controllers/v1/search_controller_test.rb +++ b/test/controllers/v1/search_controller_test.rb @@ -1,28 +1,35 @@ +require 'test_helper' + class V1::SearchControllerTest < ActionController::TestCase + tests V1::SearchController setup do - LearningObject.reindex - LearningObject.searchkick_index.refresh + SearchService::SEARCH_CLASSES.each { |search_class| reindex search_class.constantize } + auth_application end - test 'should get index and return :ok' do - get :index, search_class: 'LearningObject' - assert_response :ok + test 'should search return :ok' do + SearchService::SEARCH_CLASSES.each do |search_class| + get :index, search_class: search_class + assert_response :ok + end end - test 'should get index and return :bad_request' do - get :index + test 'should search with invalid class and return :bad_request' do + get :index, search_class: 'invalid' assert_response :bad_request end - test 'should get autocomplete and return :ok' do - get :autocomplete, search_class: 'LearningObject' - assert_response :ok + test 'should autocomplete with invalid class and return :bad_request' do + get :autocomplete, search_class: 'invalid' + assert_response :bad_request end - test 'should get autocomplete and return :bad_request' do - get :autocomplete - assert_response :bad_request + private + + def reindex(klass) + klass.reindex + klass.searchkick_index.refresh end end diff --git a/test/fixtures/applications.yml b/test/fixtures/applications.yml new file mode 100644 index 0000000000000000000000000000000000000000..190a8c980878489cff21c8824be220f25859eced --- /dev/null +++ b/test/fixtures/applications.yml @@ -0,0 +1,5 @@ +test_app: + name: 'test app' + domain: 'test.host' + application_id: 'ffcb31a0-bacc-4f37-925c-656b3805095a' + user_id: john (User) \ No newline at end of file diff --git a/test/fixtures/learning_objects.yml b/test/fixtures/learning_objects.yml index 531fe909669c2a7c973b137617425bf559256dfe..1dec107ce313f68f7044532a0448021d84d1c475 100644 --- a/test/fixtures/learning_objects.yml +++ b/test/fixtures/learning_objects.yml @@ -61,7 +61,7 @@ lo_metadata: id_dspace: '2' object_type: image language: portuguese - metadata: '[{"key": "dc.creator", "value": "ufpr", "language": "nil"}]' + metadata: '{"dc.creator": "ufpr"}' lo_metadata2: name: 'Institution Object 2' @@ -70,7 +70,7 @@ lo_metadata2: id_dspace: '3' object_type: image language: portuguese - metadata: '[{"key": "dc.creator", "value": "ufpr", "language": "nil"}]' + metadata: '{"dc.creator": "ufpr"}' search: name: 'Teste' diff --git a/test/fixtures/licenses.yml b/test/fixtures/licenses.yml new file mode 100644 index 0000000000000000000000000000000000000000..0d9a9e4790f4c916eb726c85610dbc31950bed49 --- /dev/null +++ b/test/fixtures/licenses.yml @@ -0,0 +1,13 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + description: MyText + url: MyString + image_url: MyString + +two: + name: MyString + description: MyText + url: MyString + image_url: MyString diff --git a/test/models/application_test.rb b/test/models/application_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..f959b7a8b0f457cc11eedd3b6f1e3e0639c85ef5 --- /dev/null +++ b/test/models/application_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ApplicationTest < ActiveSupport::TestCase + should belong_to :user + should validate_presence_of(:domain) + should validate_presence_of(:application_id) +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/models/license_test.rb b/test/models/license_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..c56bac9d45cc94bcd2506e20ffad3061998c4f41 --- /dev/null +++ b/test/models/license_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class LicenseTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index bcf2ab2b5f92ecd06ccc124726256615508991d2..86e0c5ce438ad0e45dbb687c3fe9e4350ce7b1cf 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -51,6 +51,7 @@ class UserTest < ActiveSupport::TestCase should have_many :shares should have_many :follows should have_many :reviews + should have_many :applications test 'an user can follow another user' do john = users(:john) diff --git a/test/services/search_service_test.rb b/test/services/search_service_test.rb index 3733c0418a7ca9acda375eff3cdd99e07d1af071..35c7a30fba49cd3fda4b10335831adb76fcf2d17 100644 --- a/test/services/search_service_test.rb +++ b/test/services/search_service_test.rb @@ -1,69 +1,66 @@ require 'test_helper' class SearchServiceTest < ActiveSupport::TestCase - test 'fetch learning object with all search params' do reindex LearningObject - service = SearchService.new(Search.new(los_complete_search), users(:john)) - assert_equal [learning_objects(:search)], service.fetch + search = SearchService.search(Search.new(los_complete_search), users(:john)) + search.each {|o| assert_instance_of LearningObject, o} end test 'fetch all public collections' do reindex Collection - service = SearchService.new(Search.new(collections_search), users(:john)) - assert_equal [collections(:ufpr)], service.fetch + search = SearchService.search(Search.new(collections_search), users(:john)) + search.each {|o| assert_instance_of Collection, o} end test 'fetch users named john' do reindex User - service = SearchService.new(Search.new(users_john_search), users(:john)) - assert_equal [users(:john), users(:one)], service.fetch + search = SearchService.search(Search.new(users_john_search), users(:john)) + assert_equal [users(:john), users(:one)], search end test 'autocomplete users named john' do reindex User - service = SearchService.new(Search.new(users_john), users(:john)) - assert_equal users_autocomplete_hashes([users(:john),users(:one)]), service.autocomplete + search = SearchService.autocomplete(Search.new(users_john), users(:john)) + assert_equal users_autocomplete_hashes([users(:john), users(:one)]), search end private def los_complete_search - default_params.merge({ - :query => 'teste', - :search_class => 'LearningObject', - :tags => ['Matemática'], - :types => ['Imagem'], - :sources => ['UFPR institution'] - }) + default_params.merge( + query: 'teste', + search_class: 'LearningObject', + tags: ['Matemática'], + types: ['Imagem'], + sources: ['UFPR institution'] + ) end def collections_search - default_params.merge({ - :search_class => 'Collection' - }) + default_params.merge(search_class: 'Collection') end def users_john_search default_params.merge(users_john) end - + def users_john { - :query => 'John', - :search_class => 'User' + query: 'John', + search_class: 'User' } end def default_params { - :page => 1, - :results_per_page => 10, - :order => 'score' + page: 1, + results_per_page: 10, + order: 'score' } end @@ -72,17 +69,14 @@ class SearchServiceTest < ActiveSupport::TestCase klass.searchkick_index.refresh end - def users_autocomplete_hashes(users=[]) - hashes = [] - users.each do |user| - hash = {} - hash["id"] = user.id - hash["name"] = user.name - hash["type"] = "User" - hash["thumbnail"] = user.avatar.url(:thumb) - hashes << hash + def users_autocomplete_hashes(users = []) + users.map do |user| + { + id: user.id, + name: user.name, + type: 'User', + thumbnail: user.avatar.url(:thumb) + } end - hashes end - -end \ No newline at end of file +end diff --git a/test/test_helper.rb b/test/test_helper.rb index dfe4b91c2b026a7d121538f11343b7efe9a425de..0e357f9b2cd176faa6ddcdff218c592c8e9a0b5d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -23,10 +23,15 @@ class ActiveSupport::TestCase # authenticate requests using devise_token_auth def auth_request(user) + auth_application sign_in user request.headers.merge!(user.create_new_auth_token) end + def auth_application + @request.headers['PortalMEC-AppID'] = applications(:test_app).application_id + end + def mock MiniTest::Mock.new end