diff --git a/app/controllers/exam_questions_controller.rb b/app/controllers/exam_questions_controller.rb index 1c160750c..158d5e9e6 100644 --- a/app/controllers/exam_questions_controller.rb +++ b/app/controllers/exam_questions_controller.rb @@ -38,7 +38,7 @@ def create if @exam_question.save if @exam_question.exam.questions.size > 1 - render partial: 'question', locals: { question: @exam_question.question, exam_question: @exam_question, exam: @exam_question.exam, hide_columns: false, can_see_preview: true } + render partial: 'question', locals: { question: @exam_question.question, exam_question: @exam_question, exam: @exam_question.exam, hide_columns: false, can_see_preview: true, can_show_order: true } else redirect_to exam_questions_path(exam_id: @exam_question.exam_id, allocation_tags_ids: at_ids) end @@ -94,7 +94,7 @@ def update QuestionText.find(params['question_texts_id']).destroy end end - render partial: 'question', locals: { question: @exam_question.question, exam_question: @exam_question, exam: @exam_question.exam, hide_columns: false, can_see_preview: true } + render partial: 'question', locals: { question: @exam_question.question, exam_question: @exam_question, exam: @exam_question.exam, hide_columns: false, can_see_preview: true, can_show_order: true } else @errors = [] @exam_question.errors.each do |attribute, erro| @@ -136,6 +136,8 @@ def publish ExamQuestion.where(id: ids).each do |exam_question| exam_question.question.can_change_status? exam_question.question.update_attributes status: true + + log(exam_question.exam, "question: #{exam_question.question_id} [publish], exam: #{exam_question.exam_id}, #{exam_question.log_description}", LogAction::TYPE[:update]) rescue nil end end diff --git a/app/controllers/exams_controller.rb b/app/controllers/exams_controller.rb index c34e6d736..39f5a7043 100644 --- a/app/controllers/exams_controller.rb +++ b/app/controllers/exams_controller.rb @@ -149,6 +149,10 @@ def open @total_time = (@last_attempt.try(:complete) ? 0 : @last_attempt.try(:get_total_time)) || 0 + if params[:page].nil? && @last_attempt.total_time == 0 + log(@exam, "exam_id: #{@exam&.id}#{@exam.attempts > 1 ? ", attempt: #{@exam&.exam_user_attempts&.length}" : ''}, description: \"Prova iniciada!\"", LogAction::TYPE[:update]) + end + SysLog::Actions.log_info do "[PROVA] Abriu prova pagina #{params[:page]} exam_id #{@exam.try(:id)} user_id=#{current_user.try(:id)} last_attempt: #{@last_attempt.as_json} - total_time #{@total_time} - exam_user_attempt #{params[:exam_user_attempt_id]}" end @@ -266,9 +270,12 @@ def complete SysLog::Actions.log_info do "[PROVA] Abriu método de finalizar prova #{params[:id]} user_id=#{current_user.try(:id)} acu #{acu.as_json} - SUCESSO" end + user_session[:blocking_content] = Exam.verify_blocking_content(current_user.id) - render_exam_success_json('finish') - #redirect_to exams_path, notice: t('finish', scope: 'exams.success') + + log(exam, "exam_id: #{exam&.id}#{exam.attempts > 1 ? ", attempt: #{exam&.exam_user_attempts&.length}" : ''}, description: \"Prova finalizada!\"", LogAction::TYPE[:update]) + #render_exam_success_json('finish') + redirect_to exams_path, notice: t('finish', scope: 'exams.success') end end rescue => error @@ -325,8 +332,15 @@ def calculate_grade def change_status authorize! :change_status, Exam, { on: params[:allocation_tags_ids] } exam = Exam.find(params[:id]) + exam.can_change_status? - exam.update_attributes status: !exam.status + + updated_status = !exam.status + + log(exam, "exam: #{exam.id} [#{updated_status ? 'publish' : 'unpublish' }], #{exam.attributes.except('id')}", LogAction::TYPE[:update]) rescue nil + + exam.update_attributes status: updated_status + render_exam_success_json('status') rescue CanCan::AccessDenied render json: { success: false, alert: t(:no_permission) }, status: :unauthorized @@ -452,4 +466,12 @@ def return_acu_result(acu, at_id, score_type) render json: { success: false, alert: error } end + def log(object, message, type=LogAction::TYPE[:update]) + user_params = { user_id: current_user.id, ip: get_remote_ip } + + object.academic_allocations.each do |ac| + LogAction.create(user_params.merge!(description: "user_id: #{user_params[:user_id]}, #{message}", academic_allocation_id: ac.id, log_type: type)) + end + end + end diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index 2c9d64acc..535733e8f 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -93,7 +93,7 @@ def update end if @question.update_attributes question_params - render partial: 'question', locals: { question: @question } + render partial: 'question', locals: { question: @question, can_show_order: true } else @errors = [] @question.errors.each do |attribute, erro| diff --git a/app/models/concerns/sys_log.rb b/app/models/concerns/sys_log.rb index eabfdcf6c..cc4ceb421 100644 --- a/app/models/concerns/sys_log.rb +++ b/app/models/concerns/sys_log.rb @@ -10,62 +10,49 @@ module Actions extend ActiveSupport::Concern included do - after_action :log_create, unless: Proc.new {|c| request.get? }, except: [:change_participant, :import, :export, :annul, :remove_record] + after_action :log_create, unless: Proc.new {|c| request.get? }, except: [:change_participant, :import, :export, :annul, :publish, :remove_record] end def log_create - model = self.class.to_s.sub("Controller", "") - sobj = model.tableize - objs = eval("@#{sobj}") # created/updated/destroyied objects could be a list - sobj = sobj.singularize - obj = eval("@#{sobj}") - objs = [eval("@#{sobj}")].compact unless obj.nil? # only if obj doesn't exist, use objs list - ignored_attrs = %w[id created_at updated_at attachment_updated_at] + model_name = self.class.to_s.sub("Controller", "") + sobj = model_name.tableize.singularize - # if some error happened, don't save log + obj = instance_variable_get("@#{sobj}") + objs = instance_variable_get("@#{model_name.tableize}") - response_status = JSON.parse(response.body) rescue nil + Rails.logger.info("\n\n Log Info Obj \n\n #{model_name} \n #{sobj} \n #{obj} \n #{objs} \n\n") - Rails.logger.info("\n\n\n #{model} \n #{sobj} \n #{objs} \n #{obj}") - - return if ((!(response_status.nil?) && response_status.has_key?("success") && response_status["success"] == false) || (params.include?(:success) && params[:success] == false)) - - if !(objs.nil?) && !(objs.empty?) - objs.each do |obj| - - # general rule for creating a log description - all_associations = eval("#{model.singularize}").reflect_on_all_associations(:has_many).map(&:name) - - log_payload = if obj.respond_to?(:log_description) - obj.log_description + target_objects = if obj.present? + [obj] + elsif objs.present? && objs.is_a?(Enumerable) + objs else - obj.attributes.except(*ignored_attrs) + [] end - all_associations.each do |association| - if(obj.respond_to?(association) && obj.send(association).any?) - association_data = obj.send(association).map {|a| a.attributes.except("attachment_updated_at") } - - log_payload = log_payload.merge("#{association.to_s}" => association_data) if log_payload.is_a?(Hash) - end - end - - description = "#{sobj.singularize}: #{obj.id}#{changed_attributes(obj, ignored_attrs)}, #{log_payload.to_json}" - - if ((obj.respond_to?(:academic_allocations) && !obj.try(:academic_allocations).empty?) || obj.respond_to?(:academic_allocation)) - allocation_tag_id = params[:allocation_tag_id] || active_tab[:url][:allocation_tag_id] || obj.allocation_tag.id rescue nil - - [(obj.respond_to?(:academic_allocations) ? obj.academic_allocations : obj.academic_allocation)].flatten.each do |al| - LogAction.create(log_type: LogAction::TYPE[request_method(request.request_method)], user_id: current_user.id, academic_allocation_id: al.id, allocation_tag_id: (allocation_tag_id || al.allocation_tag_id), ip: get_remote_ip, description: description) - end - elsif (obj.respond_to?(:allocation_tag) && !(obj.allocation_tag.nil?)) - LogAction.create(log_type: LogAction::TYPE[request_method(request.request_method)], user_id: current_user.id, allocation_tag_id: obj.allocation_tag.id, ip: get_remote_ip, description: description) - else # generic log - generic_log(sobj, obj) + return if request_failed? + + if target_objects.any? + target_objects.each do |obj| + next if obj.new_record? && params.include?(:digital_classes) + description = general_log_description(obj, sobj) + resolved_log_targets = log_targets(obj) + + resolved_log_targets.each do |target| + LogAction.create( + log_type: LogAction::TYPE[request_method(request.request_method)], + user_id: current_user.id, + ip: get_remote_ip, + description: description, + academic_allocation_id: target[:allocation_id], + allocation_tag_id: target[:tag_id], + ) end end else - generic_log(sobj) + # generic log(fallback) + Rails.logger.info("\n\n Entrou no fallback \n\n") + fallback_log end rescue => error @@ -81,6 +68,103 @@ def self.log_info(msg = nil, &block) private + def request_failed? + response_status = JSON.parse(response.body) rescue nil + + return true if response_status&.key?("success") && response_status["success"] == false + return true if (params.include?(:success) && params[:success] == false) + false + end + + def general_log_description(obj, sobj) + ignored_attrs = %w[id created_at updated_at attachment_updated_at] + + log_payload = obj.respond_to?(:log_description) ? obj.log_description : obj.attributes.except(*ignored_attrs) + + log_payload = log_payload.as_json unless log_payload.is_a?(Hash) + + all_associations = obj.class.reflect_on_all_associations(:has_many).map(&:name) + + all_associations.each do |association| + if((obj.respond_to?(association) && obj.send(association).any?) && !(obj.respond_to?(:log_description))) + + association_data = obj.send(association).map {|a| a.attributes.except("attachment_updated_at") } + + log_payload[association.to_s] = association_data + end + end + + "#{sobj.singularize}: #{obj.id}#{changed_attributes(obj, ignored_attrs)}, #{log_payload.to_json}" + end + + def log_targets(obj) # academic_allocations and allocation_tag to get allocation_tag_id + targets = [] + allocation_tag_id = params[:allocation_tag_id] || active_tab[:url][:allocation_tag_id] || (obj.allocation_tag.id rescue nil) + + if obj.respond_to?(:academic_allocations) && obj.academic_allocations.present? + obj.academic_allocations.each do |al| + targets << { + allocation_id: al.id, + tag_id: (allocation_tag_id || al.try(:allocation_tag_id)) + } + end + elsif obj.respond_to?(:academic_allocation) && obj.academic_allocation.present? + al = obj.academic_allocation + targets << { + allocation_id: al.id, + tag_id: (allocation_tag_id || al.try(:allocation_tag_id)) + } + elsif obj.respond_to?(:allocation_tag) && obj.allocation_tag.present? + targets << { allocation_id: nil, tag_id: obj.allocation_tag.id } + else + targets << { allocation_id: nil, tag_id: allocation_tag_id } + end + + targets + end + + def fallback_log + return if params.include?(:digital_classes) + + description = nil + + if params[:id].present? && params.except(:controller, :action, :id).empty? + description = "#{params[:controller].singularize}: #{params[:id]}" + elsif params[:id].present? + info = params.except(:controller, :action, :id).to_json + description = "#{params[:controller].singularize}: #{params[:id]}, #{info}" + else + d = [] + variables = self.instance_variable_names.map(&:to_s).reject do |v| + v.start_with?("@_") || ["@current_user", "@current_ability"].include?(v) + end + + academic_allocation_id = nil + + variables.each do |v| + o = instance_variable_get(v) + next if ["Array", "String", "NilClass"].include?(o.class.to_s) + + if o.respond_to?(:academic_allocation) && o.academic_allocation.respond_to?(:id) + academic_allocation_id = o.academic_allocation.id + end + + d << %{#{v.sub("@", "")}: #{o.as_json}} + end + + description = d.any? ? d.join(', ') : "#{params[:controller]}: #{params.except('controller').to_json}" + end + + LogAction.create( + log_type: LogAction::TYPE[request_method(request.request_method)], + user_id: current_user.id, + ip: get_remote_ip, + description: description, + academic_allocation_id: academic_allocation_id, + allocation_tag_id: (active_tab[:url][:allocation_tag_id] rescue nil), + ) + end + def changed_attributes(obj, ignored) return '' unless obj.saved_changes? @@ -102,39 +186,6 @@ def request_method(rm) end end - def generic_log(sobj, obj = nil) - return if params.include?(:digital_classes) - return if !obj.nil? && obj.new_record?# && !params.include?(:digital_classes) # not saved - - # academic_allocation_id = obj.try(:academic_allocation).try(:id) - academic_allocation_id = nil - tbname = obj.try(:class).try(:table_name).to_s.singularize.to_sym if obj.try(:class).respond_to?(:table_name) - description = if !tbname.nil? && (params.has_key?(tbname) || params.size <= 3) && !obj.nil? - - obj_attrs = (obj.respond_to?(:log_description) ? obj.log_description : obj.attributes.except('attachment_updated_at', 'created_at', 'updated_at')) - obj_attrs.merge!({'files' => obj.files.map {|f| f.attributes.except('attachment_updated_at') } }) if obj.respond_to?(:files) && obj.files.any? - obj_attrs = ActiveSupport::JSON.encode(obj_attrs) - - "#{sobj}: #{obj.id}, changed: #{obj.changed}, #{obj_attrs}" - elsif params[:id].present? - # gets any extra information if exists - info = ActiveSupport::JSON.encode(params.except(:controller, :action, :id)) - "#{sobj}: #{[params[:id], info].compact.join(", ")}" - else # controllers saving other objects. ex: assingments -> student files - d = [] - variables = self.instance_variable_names.to_ary.delete_if { |v| v.to_s.start_with?("@_") || ["@current_user", "@current_ability"].include?(v) } - variables.each do |v| - o = eval(v) - academic_allocation_id = o.academic_allocation.id if o.respond_to?(:academic_allocation) # assignment_file - d << %{#{v.sub("@", "")}: #{o.as_json}} unless ["Array", "String"].include?(o.class) - end - d.join(', ') - d = "#{params[:controller]}: #{params.except('controller').to_s}" if d.blank? - end - - LogAction.create(log_type: LogAction::TYPE[request_method(request.request_method)], user_id: current_user.id, ip: get_remote_ip, academic_allocation_id: academic_allocation_id, description: description, allocation_tag_id: (active_tab[:url][:allocation_tag_id] rescue nil)) unless description.nil? - end - end # Actions module Devise diff --git a/app/models/exam.rb b/app/models/exam.rb index 19e18ca1a..988acdfb6 100644 --- a/app/models/exam.rb +++ b/app/models/exam.rb @@ -417,13 +417,17 @@ def responses_question_user(acu_id, id) def log_description desc = {} - - desc.merge!(question.attributes.except('attachment_updated_at', 'updated_at', 'created_at')) - desc.merge!(exam_id: exam.id) + desc.merge!(exam_id: id) desc.merge!(attributes.except('attachment_updated_at', 'updated_at', 'created_at')) - desc.merge!(images: question.question_images.collect{|img| img.attributes.except('image_updated_at' 'question_id')}) - desc.merge!(items: question.question_items.collect{|item| item.attributes.except('question_id', 'item_image_updated_at')}) - desc.merge!(labels: question.question_labels.collect{|label| label.attributes.except('created_at', 'updated_at')}) + desc.merge!(schedules: schedule.attributes.except('id', 'updated_at', 'created_at')) + + questions.each do |question| + desc.merge!(questions: question.attributes.except('attachment_updated_at', 'updated_at', 'created_at')) + desc.merge!(items: question.question_items.collect{|item| item.attributes.except('question_id', 'item_image_updated_at')}) + desc.merge!(images: question.question_images.collect{|img| img.attributes.except('image_updated_at' 'question_id')}) + desc.merge!(labels: question.question_labels.collect{|label| label.attributes.except('created_at', 'updated_at')}) + end + return desc end def set_random_questions