From 6cbecb5b397730af25ff2453c90180917a160727 Mon Sep 17 00:00:00 2001 From: Sebastian Serth Date: Fri, 14 May 2021 10:51:44 +0200 Subject: [PATCH] Apply automatic rubocop fixes --- Rakefile | 4 +- Vagrantfile | 6 +- app/channels/application_cable/channel.rb | 2 + app/channels/application_cable/connection.rb | 8 +- app/channels/la_exercises_channel.rb | 4 +- app/controllers/admin/dashboard_controller.rb | 2 + app/controllers/application_controller.rb | 5 +- .../code_ocean/files_controller.rb | 12 +- .../codeharbor_links_controller.rb | 3 +- app/controllers/comments_controller.rb | 32 +- app/controllers/concerns/common_behavior.rb | 8 +- app/controllers/concerns/file_parameters.rb | 3 +- app/controllers/concerns/lti.rb | 52 ++- .../concerns/remote_evaluation_parameters.rb | 9 +- .../concerns/submission_parameters.rb | 7 +- .../concerns/submission_scoring.rb | 17 +- app/controllers/consumers_controller.rb | 8 +- .../error_template_attributes_controller.rb | 37 +- app/controllers/error_templates_controller.rb | 22 +- .../execution_environments_controller.rb | 41 +- .../exercise_collections_controller.rb | 31 +- app/controllers/exercises_controller.rb | 74 ++-- app/controllers/external_users_controller.rb | 24 +- app/controllers/file_templates_controller.rb | 23 +- app/controllers/file_types_controller.rb | 18 +- app/controllers/flowr_controller.rb | 11 +- app/controllers/internal_users_controller.rb | 3 +- app/controllers/proxy_exercises_controller.rb | 28 +- .../remote_evaluation_controller.rb | 12 +- .../request_for_comments_controller.rb | 61 +-- app/controllers/sessions_controller.rb | 9 +- app/controllers/statistics_controller.rb | 26 +- app/controllers/study_groups_controller.rb | 8 +- app/controllers/submissions_controller.rb | 226 +++++----- app/controllers/subscriptions_controller.rb | 44 +- app/controllers/tags_controller.rb | 8 +- app/controllers/tips_controller.rb | 12 +- .../user_exercise_feedbacks_controller.rb | 26 +- app/helpers/action_cable_helper.rb | 19 +- app/helpers/admin/dashboard_helper.rb | 2 + app/helpers/application_helper.rb | 25 +- .../error_template_attributes_helper.rb | 2 + app/helpers/error_templates_helper.rb | 2 + app/helpers/exercise_helper.rb | 6 +- app/helpers/lti_helper.rb | 2 + app/helpers/pagedown_form_builder.rb | 13 +- app/helpers/statistics_helper.rb | 371 ++++++++-------- app/helpers/time_helper.rb | 6 +- app/mailers/user_mailer.rb | 22 +- app/models/anomaly_notification.rb | 2 + app/models/code_ocean/file.rb | 31 +- app/models/codeharbor_link.rb | 6 +- app/models/concerns/context.rb | 2 + app/models/concerns/creation.rb | 2 + app/models/concerns/default_values.rb | 2 + app/models/consumer.rb | 2 + app/models/error_template.rb | 2 + app/models/error_template_attribute.rb | 2 + app/models/event.rb | 2 + app/models/execution_environment.rb | 17 +- app/models/exercise.rb | 80 ++-- app/models/exercise_collection.rb | 13 +- app/models/exercise_collection_item.rb | 2 + app/models/exercise_tag.rb | 11 +- app/models/exercise_tip.rb | 8 +- app/models/external_user.rb | 9 +- app/models/file_template.rb | 5 +- app/models/file_type.rb | 12 +- app/models/internal_user.rb | 4 +- app/models/intervention.rb | 8 +- app/models/lti_parameter.rb | 14 +- app/models/proxy_exercise.rb | 411 +++++++++--------- app/models/request_for_comment.rb | 4 +- app/models/search.rb | 4 +- app/models/structured_error.rb | 8 +- app/models/structured_error_attribute.rb | 11 +- app/models/study_group_membership.rb | 2 +- app/models/submission.rb | 34 +- app/models/subscription.rb | 2 + app/models/tag.rb | 12 +- app/models/testrun.rb | 6 +- app/models/tip.rb | 9 +- app/models/user.rb | 7 +- app/models/user_exercise_feedback.rb | 8 +- app/models/user_exercise_intervention.rb | 6 +- app/models/user_proxy_exercise_exercise.rb | 8 +- app/policies/admin/dashboard_policy.rb | 2 + app/policies/admin_only_policy.rb | 4 +- app/policies/admin_or_author_policy.rb | 6 +- app/policies/application_policy.rb | 8 +- app/policies/code_ocean/file_policy.rb | 4 +- app/policies/codeharbor_link_policy.rb | 2 + app/policies/comment_policy.rb | 4 +- app/policies/consumer_policy.rb | 3 +- .../error_template_attribute_policy.rb | 3 +- app/policies/error_template_policy.rb | 2 + app/policies/event_policy.rb | 4 +- app/policies/execution_environment_policy.rb | 4 +- app/policies/exercise_collection_policy.rb | 4 +- app/policies/external_user_policy.rb | 2 + app/policies/file_template_policy.rb | 4 +- app/policies/file_type_policy.rb | 3 +- app/policies/internal_user_policy.rb | 2 + app/policies/proxy_exercise_policy.rb | 6 +- app/policies/search_policy.rb | 6 +- app/policies/statistics_policy.rb | 6 +- app/policies/study_group_policy.rb | 4 +- app/policies/submission_policy.rb | 6 +- app/policies/subscription_policy.rb | 2 + app/policies/tag_policy.rb | 4 +- app/policies/tip_policy.rb | 4 +- app/policies/user_exercise_feedback_policy.rb | 4 +- .../exercise_service/check_external.rb | 5 +- .../exercise_service/push_external.rb | 2 +- .../convert_exercise_to_task.rb | 26 +- .../convert_task_to_exercise.rb | 8 +- app/services/proforma_service/import.rb | 4 +- app/uploaders/file_uploader.rb | 2 + app/views/code_ocean/files/show.json.jbuilder | 2 + app/views/comments/index.json.jbuilder | 2 + app/views/comments/show.json.jbuilder | 2 + app/views/exercises/reload.json.jbuilder | 2 + app/views/file_types/show.json.jbuilder | 2 + .../proxy_exercises/reload.json.jbuilder | 2 + .../request_for_comments/index.json.jbuilder | 2 + .../request_for_comments/show.json.jbuilder | 2 + app/views/submissions/show.json.jbuilder | 5 +- config.ru | 4 +- config/application.rb | 6 +- config/boot.rb | 2 + config/environment.rb | 2 + config/environments/development.rb | 4 +- config/environments/production.rb | 2 +- config/environments/test.rb | 4 +- .../application_controller_renderer.rb | 1 + config/initializers/assets.rb | 2 +- config/initializers/backtrace_silencers.rb | 4 +- config/initializers/cookies_serializer.rb | 2 + .../initializers/filter_parameter_logging.rb | 6 +- config/initializers/inflections.rb | 1 - config/initializers/mime_types.rb | 1 + config/initializers/monkey_patches.rb | 6 +- config/initializers/permissions_policy.rb | 1 + config/initializers/prometheus.rb | 2 +- config/initializers/rails_admin.rb | 11 +- config/initializers/session_store.rb | 2 + config/initializers/sorcery.rb | 56 +-- config/initializers/will_paginate.rb | 2 + config/initializers/wrap_parameters.rb | 2 + config/puma.rb | 14 +- config/schedule.rb | 4 +- config/spring.rb | 10 +- db/migrate/20140625134118_create_exercises.rb | 2 + ...626143132_create_execution_environments.rb | 2 + .../20140626144036_create_submissions.rb | 2 + ...d_reference_implementation_to_exercises.rb | 2 + ...d_indent_size_to_execution_environments.rb | 2 + db/migrate/20140701120126_create_consumers.rb | 2 + db/migrate/20140701122345_create_users.rb | 2 + ...140702100130_add_oauth_key_to_consumers.rb | 2 + ...703070749_add_oauth_secret_to_consumers.rb | 2 + .../20140716153147_add_role_to_users.rb | 2 + ...20140717074902_add_user_id_to_exercises.rb | 2 + ...d_run_command_to_execution_environments.rb | 2 + ..._test_command_to_execution_environments.rb | 2 + ...140723135747_add_test_code_to_exercises.rb | 2 + ...20140724155359_add_cause_to_submissions.rb | 2 + ...343_add_template_test_code_to_exercises.rb | 2 + ...upports_user_defined_tests_to_exercises.rb | 2 + ...ing_framework_to_execution_environments.rb | 2 + .../20140812102114_create_file_types.rb | 2 + db/migrate/20140812144733_create_files.rb | 2 + ...ted_columns_from_execution_environments.rb | 2 + ...ove_file_related_columns_from_exercises.rb | 2 + ...0813091722_remove_code_from_submissions.rb | 2 + ...820170039_add_instructions_to_exercises.rb | 2 + ...140821064318_add_published_to_exercises.rb | 2 + ...0823172643_add_executable_to_file_types.rb | 2 + ...0823173923_add_renderable_to_file_types.rb | 2 + .../20140825121336_create_external_users.rb | 2 + .../20140825125801_create_internal_users.rb | 2 + db/migrate/20140825154202_drop_users.rb | 2 + ...140825161350_add_user_type_to_exercises.rb | 2 + ...40825161358_add_user_type_to_file_types.rb | 2 + ...0825161406_add_user_type_to_submissions.rb | 2 + db/migrate/20140826073318_sorcery_core.rb | 2 + ...26073319_sorcery_brute_force_protection.rb | 2 + .../20140826073320_sorcery_remember_me.rb | 2 + .../20140826073321_sorcery_reset_password.rb | 2 + .../20140826073322_sorcery_user_activation.rb | 2 + ...20140827065359_add_binary_to_file_types.rb | 2 + ...20140827083957_add_native_file_to_files.rb | 2 + db/migrate/20140829141913_create_hints.rb | 2 + ...ot_null_constraints_from_internal_users.rb | 2 + db/migrate/20140903165113_create_errors.rb | 2 + .../20140904082810_add_token_to_exercises.rb | 2 + ...20140909115430_add_file_id_to_exercises.rb | 2 + .../20140915095420_add_role_to_files.rb | 2 + ...915122846_remove_file_id_from_exercises.rb | 2 + ...40918063522_add_hashed_content_to_files.rb | 2 + ...922161120_add_feedback_message_to_files.rb | 2 + .../20140922161226_add_weight_to_files.rb | 2 + ...2729_add_help_to_execution_environments.rb | 2 + ...exposed_ports_to_execution_environments.rb | 2 + ...xecution_time_to_execution_environments.rb | 2 + ...and_user_type_to_execution_environments.rb | 2 + ...141017110211_rename_published_to_public.rb | 2 + .../20141031161603_add_path_to_files.rb | 2 + db/migrate/20141119131607_create_comments.rb | 2 + db/migrate/20150128083123_create_teams.rb | 2 + ...50128084834_create_internal_users_teams.rb | 2 + ...20150128093003_add_team_id_to_exercises.rb | 2 + ...add_pool_size_to_execution_environments.rb | 2 + ..._file_type_id_to_execution_environments.rb | 2 + ..._memory_limit_to_execution_environments.rb | 2 + ...twork_enabled_to_execution_environments.rb | 2 + ...50327141740_create_request_for_comments.rb | 8 +- .../20150408155923_add_submission_to_error.rb | 2 + .../20150421074734_add_file_index_to_files.rb | 4 +- ...4_add_user_type_to_request_for_comments.rb | 2 + .../20150818142251_correct_column_names.rb | 8 +- ...ove_requestor_from_request_for_comments.rb | 2 + ...2125415_add_hide_file_tree_to_exercises.rb | 2 + ...20160204094409_create_code_harbor_links.rb | 2 + ...0204111716_add_user_to_code_harbor_link.rb | 4 +- db/migrate/20160302133540_create_testruns.rb | 2 + ...51_add_question_to_request_for_comments.rb | 2 + ...41_add_allow_file_creation_to_exercises.rb | 2 + ...comment_text_attribute_to_text_datatype.rb | 3 + .../20160609185708_create_file_templates.rb | 2 + ...0160610111602_add_file_template_to_file.rb | 2 + ...0951_add_solved_to_request_for_comments.rb | 2 + ..._add_submission_to_request_for_comments.rb | 54 +-- ..._requested_at_from_request_for_comments.rb | 2 + db/migrate/20160704143402_remove_teams.rb | 2 + ..._add_allow_auto_completion_to_exercises.rb | 2 + .../20170112151637_create_lti_parameters.rb | 4 +- ...70437_create_remote_evaluation_mappings.rb | 14 +- ...70205163247_create_exercise_collections.rb | 3 +- .../20170205165450_create_proxy_exercises.rb | 2 + .../20170205210357_create_interventions.rb | 5 +- db/migrate/20170206141210_add_tags.rb | 4 +- .../20170206152503_add_user_feedback.rb | 2 + db/migrate/20170228165741_add_search.rb | 2 + ..._reason_to_user_proxy_exercise_exercise.rb | 2 + ...20170323130756_add_index_to_submissions.rb | 2 + ..._default_for_request_for_comment_solved.rb | 4 +- .../20170411090543_improve_user_feedback.rb | 2 + ..._thank_you_note_to_request_for_comments.rb | 2 + .../20170703075832_create_error_templates.rb | 2 + ...075959_create_error_template_attributes.rb | 2 + ...20170703080205_create_structured_errors.rb | 2 + ...0355_create_structured_error_attributes.rb | 2 + ..._description_and_hint_to_error_template.rb | 2 + ...mplate_attribute_relationship_to_n_to_m.rb | 2 + ...add_match_to_structured_error_attribute.rb | 2 + .../20170830083601_add_cause_to_testruns.rb | 8 +- .../20170906124500_create_subscriptions.rb | 2 + ...20170913054203_rename_subscription_type.rb | 2 + ...70920145852_add_deleted_to_subscription.rb | 2 + ...1002131135_remove_expected_working_time.rb | 2 + ...y_detection_flag_to_exercise_collection.rb | 4 +- ...d_timestamps_to_user_exercise_feedbacks.rb | 6 +- .../20171122124222_add_index_to_exercises.rb | 2 + ...0172208_add_user_to_exercise_collection.rb | 4 +- ...645_add_submission_to_structured_errors.rb | 2 + ...ached_full_score_to_request_for_comment.rb | 8 +- ..._times_featured_to_request_for_comments.rb | 2 + ...180222145909_fix_timestamps_on_feedback.rb | 6 +- ...0226131340_create_anomaly_notifications.rb | 2 + ...0_remove_file_id_from_structured_errors.rb | 2 + ...125302_create_exercise_collection_items.rb | 2 + db/migrate/20180814145059_create_events.rb | 2 + ...14154055_rename_events_type_to_category.rb | 2 + .../20180815115351_remove_event_indices.rb | 4 +- ...317_add_index_for_testrun_submission_id.rb | 2 + ...dex_for_lti_parameters_external_user_id.rb | 2 + ...181116143743_add_role_to_external_users.rb | 2 + ...181119161514_add_user_to_proxy_exercise.rb | 4 +- .../20181122084546_create_study_groups.rb | 5 +- ...22090243_create_study_group_memberships.rb | 2 + ...122090244_add_study_group_to_submission.rb | 2 + ...user_type_to_remote_evaluation_mappings.rb | 2 + db/migrate/20181127160857_drop_hints.rb | 2 + db/migrate/20181129093207_drop_errors.rb | 12 +- ...02_add_indices_for_request_for_comments.rb | 2 + ...e_code_harbor_links_to_codeharbor_links.rb | 2 + ..._rename_oauth2token_in_codeharbor_links.rb | 2 + .../20190830142809_add_uuid_to_exercise.rb | 2 + ...91008163045_add_unpublished_to_exercise.rb | 2 + ...dd_container_execution_time_to_testruns.rb | 2 + ...0200506093054_add_deadline_to_exercises.rb | 2 + ...nd_submission_to_user_exercise_feedback.rb | 8 +- .../20201026184633_create_linter_checks.rb | 2 + db/migrate/20201208095929_add_index_to_rfc.rb | 4 +- ...2844_add_index_to_unpublished_exercises.rb | 2 + ...01210113500_add_index_to_exercise_title.rb | 2 + ..._to_active_storage_blobs.active_storage.rb | 16 +- ..._storage_variant_records.active_storage.rb | 4 +- db/seeds.rb | 4 +- db/seeds/audio_video/index.html_spec.rb | 2 + db/seeds/development.rb | 2 +- db/seeds/fibonacci/exercise.rb | 5 +- db/seeds/fibonacci/exercise_spec_1.rb | 2 + db/seeds/fibonacci/exercise_spec_2.rb | 4 +- db/seeds/fibonacci/exercise_spec_3.rb | 2 + db/seeds/fibonacci/reference.rb | 2 + db/seeds/files/exercise.rb | 2 + db/seeds/files/exercise_spec.rb | 2 + db/seeds/hello_world/exercise_spec.rb | 2 + db/seeds/production.rb | 4 +- db/seeds/sql_select/comparator.rb | 2 + db/seeds/tdd/exercise_spec.rb | 2 + db/seeds/web_app/app.rb | 2 + .../validations/boolean_presence_validator.rb | 2 + lib/assessor.rb | 10 +- lib/code_ocean/config.rb | 6 +- lib/cpp_catch2_adapter.rb | 44 +- lib/docker_client.rb | 164 +++---- lib/docker_container_mixin.rb | 11 +- lib/docker_container_pool.rb | 31 +- lib/file_tree.rb | 16 +- .../testing_framework_adapter_generator.rb | 38 +- lib/junit_adapter.rb | 10 +- lib/mocha_adapter.rb | 8 +- lib/nonce_store.rb | 4 +- lib/port_pool.rb | 4 +- lib/prometheus/controller.rb | 22 +- lib/py_lint_adapter.rb | 19 +- lib/py_unit_adapter.rb | 14 +- lib/py_unit_and_py_lint_adapter.rb | 3 +- lib/python20_course_week.rb | 27 +- lib/r_script_adapter.rb | 6 +- lib/rspec_adapter.rb | 4 +- lib/seeds_helper.rb | 2 + lib/sql_result_set_comparator_adapter.rb | 6 +- lib/tasks/detect_exercise_anomalies.rake | 15 +- lib/tasks/docker.rake | 4 +- lib/tasks/write_displaynames.rake | 14 +- lib/testing_framework_adapter.rb | 4 +- spec/concerns/file_parameters_spec.rb | 2 +- spec/concerns/lti_spec.rb | 16 +- spec/concerns/submission_scoring_spec.rb | 10 +- .../admin/dashboard_controller_spec.rb | 8 +- .../application_controller_spec.rb | 18 +- .../code_ocean/files_controller_spec.rb | 17 +- spec/controllers/consumers_controller_spec.rb | 29 +- ...ror_template_attributes_controller_spec.rb | 29 +- .../error_templates_controller_spec.rb | 29 +- spec/controllers/events_controller_spec.rb | 18 +- .../execution_environments_controller_spec.rb | 47 +- spec/controllers/exercises_controller_spec.rb | 71 +-- .../external_users_controller_spec.rb | 9 +- .../controllers/file_types_controller_spec.rb | 29 +- .../internal_users_controller_spec.rb | 90 ++-- .../request_for_comments_controller_spec.rb | 6 +- spec/controllers/sessions_controller_spec.rb | 61 ++- .../controllers/statistics_controller_spec.rb | 18 +- .../submissions_controller_spec.rb | 83 ++-- spec/factories/code_ocean/file.rb | 2 + spec/factories/codeharbor_link.rb | 4 +- spec/factories/consumer.rb | 2 + spec/factories/error_template_attributes.rb | 6 +- spec/factories/error_templates.rb | 6 +- spec/factories/execution_environment.rb | 2 + spec/factories/exercise.rb | 6 +- spec/factories/external_user.rb | 2 + spec/factories/file_type.rb | 2 + spec/factories/lti_parameter.rb | 11 +- spec/factories/proxy_exercise.rb | 3 +- spec/factories/shared_traits.rb | 6 +- spec/factories/structured_error_attributes.rb | 4 +- spec/factories/structured_errors.rb | 2 + spec/factories/study_group.rb | 2 + spec/factories/submission.rb | 2 + spec/factories/user_exercise_feedback.rb | 3 +- spec/features/authentication_spec.rb | 4 +- spec/features/authorization_spec.rb | 9 +- spec/features/editor_spec.rb | 10 +- spec/features/factories_spec.rb | 2 + spec/features/prometheus/controller_spec.rb | 1 - .../request_for_comments_filter_spec.rb | 2 + spec/helpers/admin/dashboard_helper_spec.rb | 4 +- spec/helpers/application_helper_spec.rb | 2 + spec/helpers/exercise_helper_spec.rb | 2 + spec/helpers/yaml_spec.rb | 2 +- spec/lib/assessor_spec.rb | 8 +- spec/lib/code_ocean/config_spec.rb | 12 +- spec/lib/docker_client_spec.rb | 70 +-- spec/lib/docker_container_mixin_spec.rb | 2 + spec/lib/file_tree_spec.rb | 4 +- ...esting_framework_adapter_generator_spec.rb | 6 +- spec/lib/junit_adapter_spec.rb | 2 + spec/lib/mocha_adapter_spec.rb | 4 +- spec/lib/nonce_store_spec.rb | 2 + spec/lib/port_pool_spec.rb | 2 + spec/lib/py_unit_adapter_spec.rb | 2 + spec/lib/rspec_adapter_spec.rb | 2 + .../sql_result_set_comparator_adapter_spec.rb | 2 + spec/lib/testing_framework_adapter_spec.rb | 2 + spec/mailers/previews/user_mailer_preview.rb | 4 +- spec/mailers/user_mailer_spec.rb | 6 +- spec/models/code_ocean/file_spec.rb | 8 +- spec/models/codeharbor_link_spec.rb | 2 + spec/models/consumer_spec.rb | 2 + spec/models/execution_environment_spec.rb | 15 +- spec/models/exercise_spec.rb | 19 +- spec/models/external_user_spec.rb | 2 + spec/models/file_type_spec.rb | 8 +- spec/models/internal_user_spec.rb | 7 +- spec/models/submission_spec.rb | 33 +- spec/policies/admin/dashboard_policy_spec.rb | 2 + spec/policies/application_policy_spec.rb | 2 + spec/policies/code_ocean/file_policy_spec.rb | 10 +- spec/policies/consumer_policy_spec.rb | 6 +- .../execution_environment_policy_spec.rb | 10 +- spec/policies/exercise_policy_spec.rb | 21 +- spec/policies/external_user_policy_spec.rb | 6 +- spec/policies/file_type_policy_spec.rb | 6 +- spec/policies/internal_user_policy_spec.rb | 10 +- spec/policies/submission_policy_spec.rb | 8 +- spec/rails_helper.rb | 2 +- .../convert_exercise_to_task_spec.rb | 6 +- .../convert_task_to_exercise_spec.rb | 14 +- spec/services/proforma_service/import_spec.rb | 12 +- spec/spec_helper.rb | 6 +- spec/support/anonymous_controller.rb | 5 +- spec/support/authentication.rb | 2 + spec/support/controllers.rb | 14 +- spec/support/database_cleaner.rb | 1 - spec/support/docker.rb | 4 +- spec/support/expectations/equal_exercise.rb | 2 +- spec/support/factory_bot.rb | 2 + spec/support/features.rb | 2 + spec/support/selenium.rb | 2 + spec/support/silencer.rb | 2 + spec/support/wait_for_ajax.rb | 2 + spec/uploaders/file_uploader_spec.rb | 7 +- .../shell.html.slim_spec.rb | 4 +- .../exercises/implement.html.slim_spec.rb | 6 +- 440 files changed, 2705 insertions(+), 1853 deletions(-) diff --git a/Rakefile b/Rakefile index ba6b733d..e51cf0e1 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require File.expand_path('config/application', __dir__) Rails.application.load_tasks diff --git a/Vagrantfile b/Vagrantfile index 8b15904e..b4b9999b 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,9 +10,9 @@ Vagrant.configure(2) do |config| v.cpus = 4 end config.vm.network 'forwarded_port', - host_ip: ENV['LISTEN_ADDRESS'] || '127.0.0.1', - host: 7000, - guest: 7000 + host_ip: ENV['LISTEN_ADDRESS'] || '127.0.0.1', + host: 7000, + guest: 7000 config.vm.synced_folder '.', '/home/vagrant/codeocean' config.vm.synced_folder '../dockercontainerpool', '/home/vagrant/dockercontainerpool' config.vm.provision 'shell', path: 'provision/provision.vagrant.sh', privileged: false diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index d6726972..9aec2305 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index d277ba3e..f2bc6ed9 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :current_user @@ -20,11 +22,7 @@ module ApplicationCable def find_verified_user # Finding the current_user is similar to the code used in application_controller.rb#current_user current_user = ExternalUser.find_by(id: session[:external_user_id]) || InternalUser.find_by(id: session[:user_id]) - if current_user - current_user - else - reject_unauthorized_connection - end + current_user || reject_unauthorized_connection end end end diff --git a/app/channels/la_exercises_channel.rb b/app/channels/la_exercises_channel.rb index 363da89b..a8821896 100644 --- a/app/channels/la_exercises_channel.rb +++ b/app/channels/la_exercises_channel.rb @@ -1,5 +1,6 @@ -class LaExercisesChannel < ApplicationCable::Channel +# frozen_string_literal: true +class LaExercisesChannel < ApplicationCable::Channel def subscribed stream_from specific_channel end @@ -9,6 +10,7 @@ class LaExercisesChannel < ApplicationCable::Channel end private + def specific_channel reject unless StudyGroupPolicy.new(current_user, StudyGroup.find_by(id: params[:study_group_id])).stream_la? "la_exercises_#{params[:exercise_id]}_channel_study_group_#{params[:study_group_id]}" diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index d5bc9d6b..f509bd53 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Admin class DashboardController < ApplicationController include DashboardHelper diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a2927ef1..7bc90b9d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,7 +14,8 @@ class ApplicationController < ActionController::Base rescue_from ActionController::InvalidAuthenticityToken, with: :render_csrf_error def current_user - ::NewRelic::Agent.add_custom_attributes(external_user_id: session[:external_user_id], session_user_id: session[:user_id]) + ::NewRelic::Agent.add_custom_attributes(external_user_id: session[:external_user_id], +session_user_id: session[:user_id]) @current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources || nil end @@ -59,7 +60,7 @@ class ApplicationController < ActionController::Base respond_to do |format| format.html do # Prevent redirect loop - if request.url == request.referrer + if request.url == request.referer redirect_to :root, alert: message else redirect_back fallback_location: :root, allow_other_host: false, alert: message diff --git a/app/controllers/code_ocean/files_controller.rb b/app/controllers/code_ocean/files_controller.rb index dbced0b7..75bb8d0a 100644 --- a/app/controllers/code_ocean/files_controller.rb +++ b/app/controllers/code_ocean/files_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CodeOcean class FilesController < ApplicationController include CommonBehavior @@ -25,9 +27,10 @@ module CodeOcean if @object.save yield if block_given? path = options[:path].try(:call) || @object - respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), path: path, status: :created) + respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), +path: path, status: :created) else - filename = (@object.path || '') + '/' + (@object.name || '') + (@object.file_type.try(:file_extension) || '') + filename = "#{@object.path || ''}/#{@object.name || ''}#{@object.file_type.try(:file_extension) || ''}" format.html { redirect_to(options[:path]); flash[:danger] = t('files.error.filename', name: filename) } format.json { render(json: @object.errors, status: :unprocessable_entity) } end @@ -41,7 +44,10 @@ module CodeOcean end def file_params - params[:code_ocean_file].permit(file_attributes).merge(context_type: 'Submission', role: 'user_defined_file') if params[:code_ocean_file].present? + if params[:code_ocean_file].present? + params[:code_ocean_file].permit(file_attributes).merge(context_type: 'Submission', +role: 'user_defined_file') + end end private :file_params end diff --git a/app/controllers/codeharbor_links_controller.rb b/app/controllers/codeharbor_links_controller.rb index 087f2736..019366e8 100644 --- a/app/controllers/codeharbor_links_controller.rb +++ b/app/controllers/codeharbor_links_controller.rb @@ -7,7 +7,8 @@ class CodeharborLinksController < ApplicationController def new base_url = CodeOcean::Config.new(:code_ocean).read[:codeharbor][:url] || '' - @codeharbor_link = CodeharborLink.new(push_url: base_url + '/import_exercise', check_uuid_url: base_url + '/import_uuid_check') + @codeharbor_link = CodeharborLink.new(push_url: "#{base_url}/import_exercise", +check_uuid_url: "#{base_url}/import_uuid_check") authorize! end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index fcddf876..32c31229 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + class CommentsController < ApplicationController - before_action :set_comment, only: [:show, :edit, :update, :destroy] + before_action :set_comment, only: %i[show edit update destroy] # to disable authorization check: comment the line below back in - # skip_after_action :verify_authorized + # skip_after_action :verify_authorized def authorize! authorize(@comment || @comments) @@ -12,16 +14,16 @@ class CommentsController < ApplicationController # GET /comments.json def index file = CodeOcean::File.find(params[:file_id]) - #there might be no submission yet, so dont use find + # there might be no submission yet, so dont use find submission = Submission.find_by(id: file.context_id) if submission @comments = Comment.where(file_id: params[:file_id]) - @comments.map{|comment| + @comments.map do |comment| comment.username = comment.user.displayname comment.date = comment.created_at.strftime('%d.%m.%Y %k:%M') comment.updated = (comment.created_at != comment.updated_at) comment.editable = comment.user == current_user - } + end else @comments = [] end @@ -81,9 +83,10 @@ class CommentsController < ApplicationController # Never trust parameters from the scary internet, only allow the white list through. def comment_params - #params.require(:comment).permit(:user_id, :file_id, :row, :column, :text) + # params.require(:comment).permit(:user_id, :file_id, :row, :column, :text) # fuer production mode, damit böse menschen keine falsche user_id uebergeben: - params.require(:comment).permit(:file_id, :row, :column, :text, :request_id).merge(user_id: current_user.id, user_type: current_user.class.name) + params.require(:comment).permit(:file_id, :row, :column, :text, :request_id).merge(user_id: current_user.id, +user_type: current_user.class.name) end def send_mail_to_author(comment, request_for_comment) @@ -96,15 +99,14 @@ class CommentsController < ApplicationController request_for_comment.commenters.each do |commenter| already_sent_mail = false subscriptions = Subscription.where( - :request_for_comment_id => request_for_comment.id, - :user_id => commenter.id, :user_type => commenter.class.name, - :deleted => false) + request_for_comment_id: request_for_comment.id, + user_id: commenter.id, user_type: commenter.class.name, + deleted: false + ) subscriptions.each do |subscription| - if (subscription.subscription_type == 'author' and current_user == request_for_comment.user) or subscription.subscription_type == 'all' - unless subscription.user == current_user or already_sent_mail - UserMailer.got_new_comment_for_subscription(comment, subscription, current_user).deliver_now - already_sent_mail = true - end + if (((subscription.subscription_type == 'author') && (current_user == request_for_comment.user)) || (subscription.subscription_type == 'all')) && !((subscription.user == current_user) || already_sent_mail) + UserMailer.got_new_comment_for_subscription(comment, subscription, current_user).deliver_now + already_sent_mail = true end end end diff --git a/app/controllers/concerns/common_behavior.rb b/app/controllers/concerns/common_behavior.rb index a52c8b00..4c36cf63 100644 --- a/app/controllers/concerns/common_behavior.rb +++ b/app/controllers/concerns/common_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CommonBehavior def create_and_respond(options = {}) @object = options[:object] @@ -5,7 +7,8 @@ module CommonBehavior if @object.save yield if block_given? path = options[:path].try(:call) || @object - respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), path: path, status: :created) + respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), +path: path, status: :created) else respond_with_invalid_object(format, template: :new) end @@ -40,7 +43,8 @@ module CommonBehavior respond_to do |format| if @object.update(options[:params]) path = options[:path] || @object - respond_with_valid_object(format, notice: t('shared.object_updated', model: @object.class.model_name.human), path: path, status: :ok) + respond_with_valid_object(format, notice: t('shared.object_updated', model: @object.class.model_name.human), +path: path, status: :ok) else respond_with_invalid_object(format, template: :edit) end diff --git a/app/controllers/concerns/file_parameters.rb b/app/controllers/concerns/file_parameters.rb index 0236b1cb..0903ae74 100644 --- a/app/controllers/concerns/file_parameters.rb +++ b/app/controllers/concerns/file_parameters.rb @@ -15,7 +15,8 @@ module FileParameters private :reject_illegal_file_attributes def file_attributes - %w[content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight file_template_id] + %w[content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight + file_template_id] end private :file_attributes end diff --git a/app/controllers/concerns/lti.rb b/app/controllers/concerns/lti.rb index 6290d5a1..dbbc726f 100644 --- a/app/controllers/concerns/lti.rb +++ b/app/controllers/concerns/lti.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'oauth/request_proxy/rack_request' module Lti @@ -6,7 +8,7 @@ module Lti MAXIMUM_SCORE = 1 MAXIMUM_SESSION_AGE = 60.minutes - SESSION_PARAMETERS = %w(launch_presentation_return_url lis_outcome_service_url lis_result_sourcedid) + SESSION_PARAMETERS = %w[launch_presentation_return_url lis_outcome_service_url lis_result_sourcedid].freeze def build_tool_provider(options = {}) if options[:consumer] && options[:parameters] @@ -20,7 +22,7 @@ module Lti # exercise_id.exists? ==> the user has submitted the results of an exercise to the consumer. # Only the lti_parameters are deleted. def clear_lti_session_data(exercise_id = nil, user_id = nil) - if (exercise_id.nil?) + if exercise_id.nil? session.delete(:external_user_id) session.delete(:study_group_id) session.delete(:embed_options) @@ -48,27 +50,23 @@ module Lti def external_user_name(provider) # save person_name_full if supplied. this is the display_name, if it is set. # else only save the firstname, we don't want lastnames (family names) - if provider.lis_person_name_full - provider.lis_person_name_full - else - provider.lis_person_name_given - end + provider.lis_person_name_full || provider.lis_person_name_given end private :external_user_name def external_user_role(provider) result = 'learner' - unless provider.roles.blank? + if provider.roles.present? provider.roles.each do |role| case role.downcase - when 'administrator' - # We don't want anyone to get admin privileges through LTI - result = 'teacher' if result == 'learner' - when 'instructor' - result = 'teacher' if result == 'learner' - else # 'learner' - next + when 'administrator' + # We don't want anyone to get admin privileges through LTI + result = 'teacher' if result == 'learner' + when 'instructor' + result = 'teacher' if result == 'learner' + else # 'learner' + next end end end @@ -141,7 +139,9 @@ module Lti def send_score(submission) ::NewRelic::Agent.add_custom_attributes({score: submission.normalized_score, session: session}) - fail(Error, "Score #{submission.normalized_score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(submission.normalized_score) + unless (0..MAXIMUM_SCORE).cover?(submission.normalized_score) + raise Error.new("Score #{submission.normalized_score} must be between 0 and #{MAXIMUM_SCORE}!") + end if submission.user.consumer lti_parameter = LtiParameter.where(consumers_id: submission.user.consumer.id, @@ -155,12 +155,12 @@ module Lti {status: 'error'} elsif provider.outcome_service? Sentry.set_extras({ - provider: provider.inspect, + provider: provider.inspect, score: submission.normalized_score, lti_parameter: lti_parameter.inspect, session: session.to_hash, - exercise_id: submission.exercise_id - }) + exercise_id: submission.exercise_id, + }) normalized_lit_score = submission.normalized_score if submission.before_deadline? # Keep the full score @@ -170,11 +170,10 @@ module Lti elsif submission.after_late_deadline? # Reduce score by 100% normalized_lit_score *= 0.0 - else # no deadline - # Keep the full score end response = provider.post_replace_result!(normalized_lit_score) - {code: response.response_code, message: response.post_response.body, status: response.code_major, score_sent: normalized_lit_score} + {code: response.response_code, message: response.post_response.body, status: response.code_major, +score_sent: normalized_lit_score} else {status: 'unsupported'} end @@ -186,22 +185,21 @@ module Lti @current_user = ExternalUser.find_or_create_by(consumer_id: @consumer.id, external_id: @provider.user_id) external_role = external_user_role(@provider) internal_role = @current_user.role - desired_role = internal_role != 'admin' ? external_role : internal_role + desired_role = internal_role == 'admin' ? internal_role : external_role # Update user with new information but change the role only if he is no admin user @current_user.update(email: external_user_email(@provider), name: external_user_name(@provider), role: desired_role) end private :set_current_user - def set_study_group_membership - group = if not context_id? - StudyGroup.find_or_create_by(external_id: @provider.resource_link_id, consumer: @consumer) - else + group = if context_id? # Ensure to find the group independent of the name and set it only once. StudyGroup.find_or_create_by(external_id: @provider.context_id, consumer: @consumer) do |new_group| new_group.name = @provider.context_title end + else + StudyGroup.find_or_create_by(external_id: @provider.resource_link_id, consumer: @consumer) end group.external_users << @current_user unless group.external_users.include? @current_user group.save diff --git a/app/controllers/concerns/remote_evaluation_parameters.rb b/app/controllers/concerns/remote_evaluation_parameters.rb index a88ef7ea..0f0c9222 100644 --- a/app/controllers/concerns/remote_evaluation_parameters.rb +++ b/app/controllers/concerns/remote_evaluation_parameters.rb @@ -1,8 +1,13 @@ +# frozen_string_literal: true + module RemoteEvaluationParameters include FileParameters def remote_evaluation_params - remote_evaluation_params = params[:remote_evaluation].permit(:validation_token, files_attributes: file_attributes) if params[:remote_evaluation].present? + if params[:remote_evaluation].present? + remote_evaluation_params = params[:remote_evaluation].permit(:validation_token, + files_attributes: file_attributes) + end end private :remote_evaluation_params -end \ No newline at end of file +end diff --git a/app/controllers/concerns/submission_parameters.rb b/app/controllers/concerns/submission_parameters.rb index 1def6759..12a37ec0 100644 --- a/app/controllers/concerns/submission_parameters.rb +++ b/app/controllers/concerns/submission_parameters.rb @@ -4,7 +4,12 @@ module SubmissionParameters include FileParameters def submission_params - submission_params = params[:submission].present? ? params[:submission].permit(:cause, :exercise_id, files_attributes: file_attributes) : {} + submission_params = if params[:submission].present? + params[:submission].permit(:cause, :exercise_id, + files_attributes: file_attributes) + else + {} + end submission_params = merge_user(submission_params) files_attributes = submission_params[:files_attributes] exercise = Exercise.find_by(id: submission_params[:exercise_id]) diff --git a/app/controllers/concerns/submission_scoring.rb b/app/controllers/concerns/submission_scoring.rb index b04f0fe2..2fa4fae9 100644 --- a/app/controllers/concerns/submission_scoring.rb +++ b/app/controllers/concerns/submission_scoring.rb @@ -12,8 +12,8 @@ module SubmissionScoring output = execute_test_file(file, submission) assessment = assessor.assess(output) passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score]).positive?) - testrun_output = passed ? nil : 'status: ' + output[:status].to_s + "\n stdout: " + output[:stdout].to_s + "\n stderr: " + output[:stderr].to_s - unless testrun_output.blank? + testrun_output = passed ? nil : "status: #{output[:status]}\n stdout: #{output[:stdout]}\n stderr: #{output[:stderr]}" + if testrun_output.present? submission.exercise.execution_environment.error_templates.each do |template| pattern = Regexp.new(template.signature).freeze StructuredError.create_from_template(template, testrun_output, submission) if pattern.match(testrun_output) @@ -50,7 +50,8 @@ module SubmissionScoring private :collect_test_results def execute_test_file(file, submission) - DockerClient.new(execution_environment: file.context.execution_environment).execute_test_command(submission, file.name_with_extension) + DockerClient.new(execution_environment: file.context.execution_environment).execute_test_command(submission, + file.name_with_extension) end private :execute_test_file @@ -69,17 +70,21 @@ module SubmissionScoring def score_submission(submission) outputs = collect_test_results(submission) score = 0.0 - unless outputs.nil? || outputs.empty? + if outputs.present? outputs.each do |output| score += output[:score] * output[:weight] unless output.nil? - output[:stderr] += "\n\n#{t('exercises.editor.timeout', permitted_execution_time: submission.exercise.execution_environment.permitted_execution_time.to_s)}" if output.present? && output[:status] == :timeout + if output.present? && output[:status] == :timeout + output[:stderr] += "\n\n#{t('exercises.editor.timeout', + permitted_execution_time: submission.exercise.execution_environment.permitted_execution_time.to_s)}" + end end end submission.update(score: score) if submission.normalized_score == 1.0 Thread.new do - RequestForComment.where(exercise_id: submission.exercise_id, user_id: submission.user_id, user_type: submission.user_type).each do |rfc| + RequestForComment.where(exercise_id: submission.exercise_id, user_id: submission.user_id, +user_type: submission.user_type).each do |rfc| rfc.full_score_reached = true rfc.save end diff --git a/app/controllers/consumers_controller.rb b/app/controllers/consumers_controller.rb index 2a2f784a..a58424a0 100644 --- a/app/controllers/consumers_controller.rb +++ b/app/controllers/consumers_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ConsumersController < ApplicationController include CommonBehavior @@ -18,8 +20,7 @@ class ConsumersController < ApplicationController destroy_and_respond(object: @consumer) end - def edit - end + def edit; end def consumer_params params[:consumer].permit(:name, :oauth_key, :oauth_secret) if params[:consumer].present? @@ -42,8 +43,7 @@ class ConsumersController < ApplicationController end private :set_consumer - def show - end + def show; end def update update_and_respond(object: @consumer, params: consumer_params) diff --git a/app/controllers/error_template_attributes_controller.rb b/app/controllers/error_template_attributes_controller.rb index 283e5b03..425c69d4 100644 --- a/app/controllers/error_template_attributes_controller.rb +++ b/app/controllers/error_template_attributes_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class ErrorTemplateAttributesController < ApplicationController - before_action :set_error_template_attribute, only: [:show, :edit, :update, :destroy] + before_action :set_error_template_attribute, only: %i[show edit update destroy] def authorize! authorize(@error_template_attributes || @error_template_attribute) @@ -9,7 +11,8 @@ class ErrorTemplateAttributesController < ApplicationController # GET /error_template_attributes # GET /error_template_attributes.json def index - @error_template_attributes = ErrorTemplateAttribute.all.order('important DESC', :key, :id).paginate(page: params[:page]) + @error_template_attributes = ErrorTemplateAttribute.all.order('important DESC', :key, + :id).paginate(page: params[:page]) authorize! end @@ -38,7 +41,9 @@ class ErrorTemplateAttributesController < ApplicationController respond_to do |format| if @error_template_attribute.save - format.html { redirect_to @error_template_attribute, notice: 'Error template attribute was successfully created.' } + format.html do + redirect_to @error_template_attribute, notice: 'Error template attribute was successfully created.' + end format.json { render :show, status: :created, location: @error_template_attribute } else format.html { render :new } @@ -53,7 +58,9 @@ class ErrorTemplateAttributesController < ApplicationController authorize! respond_to do |format| if @error_template_attribute.update(error_template_attribute_params) - format.html { redirect_to @error_template_attribute, notice: 'Error template attribute was successfully updated.' } + format.html do + redirect_to @error_template_attribute, notice: 'Error template attribute was successfully updated.' + end format.json { render :show, status: :ok, location: @error_template_attribute } else format.html { render :edit } @@ -68,19 +75,25 @@ class ErrorTemplateAttributesController < ApplicationController authorize! @error_template_attribute.destroy respond_to do |format| - format.html { redirect_to error_template_attributes_url, notice: 'Error template attribute was successfully destroyed.' } + format.html do + redirect_to error_template_attributes_url, notice: 'Error template attribute was successfully destroyed.' + end format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. - def set_error_template_attribute - @error_template_attribute = ErrorTemplateAttribute.find(params[:id]) - end - # Never trust parameters from the scary internet, only allow the white list through. - def error_template_attribute_params - params[:error_template_attribute].permit(:key, :description, :regex, :important) if params[:error_template_attribute].present? + # Use callbacks to share common setup or constraints between actions. + def set_error_template_attribute + @error_template_attribute = ErrorTemplateAttribute.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def error_template_attribute_params + if params[:error_template_attribute].present? + params[:error_template_attribute].permit(:key, :description, :regex, + :important) end + end end diff --git a/app/controllers/error_templates_controller.rb b/app/controllers/error_templates_controller.rb index bec956d8..654f97a7 100644 --- a/app/controllers/error_templates_controller.rb +++ b/app/controllers/error_templates_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class ErrorTemplatesController < ApplicationController - before_action :set_error_template, only: [:show, :edit, :update, :destroy, :add_attribute, :remove_attribute] + before_action :set_error_template, only: %i[show edit update destroy add_attribute remove_attribute] def authorize! authorize(@error_templates || @error_template) @@ -92,13 +94,17 @@ class ErrorTemplatesController < ApplicationController end private - # Use callbacks to share common setup or constraints between actions. - def set_error_template - @error_template = ErrorTemplate.find(params[:id]) - end - # Never trust parameters from the scary internet, only allow the white list through. - def error_template_params - params[:error_template].permit(:name, :execution_environment_id, :signature, :description, :hint) if params[:error_template].present? + # Use callbacks to share common setup or constraints between actions. + def set_error_template + @error_template = ErrorTemplate.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def error_template_params + if params[:error_template].present? + params[:error_template].permit(:name, :execution_environment_id, :signature, :description, + :hint) end + end end diff --git a/app/controllers/execution_environments_controller.rb b/app/controllers/execution_environments_controller.rb index b373926a..eff99068 100644 --- a/app/controllers/execution_environments_controller.rb +++ b/app/controllers/execution_environments_controller.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class ExecutionEnvironmentsController < ApplicationController include CommonBehavior - before_action :set_docker_images, only: [:create, :edit, :new, :update] - before_action :set_execution_environment, only: MEMBER_ACTIONS + [:execute_command, :shell, :statistics] - before_action :set_testing_framework_adapters, only: [:create, :edit, :new, :update] + before_action :set_docker_images, only: %i[create edit new update] + before_action :set_execution_environment, only: MEMBER_ACTIONS + %i[execute_command shell statistics] + before_action :set_testing_framework_adapters, only: %i[create edit new update] def authorize! authorize(@execution_environment || @execution_environments) @@ -20,17 +22,15 @@ class ExecutionEnvironmentsController < ApplicationController destroy_and_respond(object: @execution_environment) end - def edit - end + def edit; end def execute_command @docker_client = DockerClient.new(execution_environment: @execution_environment) render(json: @docker_client.execute_arbitrary_command(params[:command])) end - def working_time_query - """ + " SELECT exercise_id, avg(working_time) as average_time, stddev_samp(extract('epoch' from working_time)) * interval '1 second' as stddev_time FROM ( @@ -52,11 +52,11 @@ class ExecutionEnvironmentsController < ApplicationController GROUP BY exercise_id, user_id, id) AS foo) AS bar GROUP BY user_id, exercise_id ) AS baz GROUP BY exercise_id; - """ + " end def user_query - """ + " SELECT id AS exercise_id, COUNT(DISTINCT user_id) AS users, @@ -79,7 +79,7 @@ class ExecutionEnvironmentsController < ApplicationController GROUP BY e.id, s.user_id) AS inner_query GROUP BY id; - """ + " end def statistics @@ -87,21 +87,25 @@ class ExecutionEnvironmentsController < ApplicationController user_statistics = {} ApplicationRecord.connection.execute(working_time_query).each do |tuple| - working_time_statistics[tuple["exercise_id"].to_i] = tuple + working_time_statistics[tuple['exercise_id'].to_i] = tuple end ApplicationRecord.connection.execute(user_query).each do |tuple| - user_statistics[tuple["exercise_id"].to_i] = tuple + user_statistics[tuple['exercise_id'].to_i] = tuple end render locals: { working_time_statistics: working_time_statistics, - user_statistics: user_statistics + user_statistics: user_statistics, } end def execution_environment_params - params[:execution_environment].permit(:docker_image, :exposed_ports, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :name, :network_enabled, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:execution_environment].present? + if params[:execution_environment].present? + params[:execution_environment].permit(:docker_image, :exposed_ports, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :name, :network_enabled, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework).merge( +user_id: current_user.id, user_type: current_user.class.name +) + end end private :execution_environment_params @@ -118,10 +122,10 @@ class ExecutionEnvironmentsController < ApplicationController def set_docker_images DockerClient.check_availability! @docker_images = DockerClient.image_tags.sort - rescue DockerClient::Error => error + rescue DockerClient::Error => e @docker_images = [] - flash[:warning] = error.message - Sentry.capture_exception(error) + flash[:warning] = e.message + Sentry.capture_exception(e) end private :set_docker_images @@ -139,8 +143,7 @@ class ExecutionEnvironmentsController < ApplicationController end private :set_testing_framework_adapters - def shell - end + def shell; end def show if @execution_environment.testing_framework? diff --git a/app/controllers/exercise_collections_controller.rb b/app/controllers/exercise_collections_controller.rb index 3e13a3af..b61d0334 100644 --- a/app/controllers/exercise_collections_controller.rb +++ b/app/controllers/exercise_collections_controller.rb @@ -1,15 +1,16 @@ +# frozen_string_literal: true + class ExerciseCollectionsController < ApplicationController include CommonBehavior - before_action :set_exercise_collection, only: [:show, :edit, :update, :destroy, :statistics] + before_action :set_exercise_collection, only: %i[show edit update destroy statistics] def index - @exercise_collections = ExerciseCollection.all.paginate(:page => params[:page]) + @exercise_collections = ExerciseCollection.all.paginate(page: params[:page]) authorize! end - def show - end + def show; end def new @exercise_collection = ExerciseCollection.new @@ -28,16 +29,14 @@ class ExerciseCollectionsController < ApplicationController destroy_and_respond(object: @exercise_collection) end - def edit - end + def edit; end def update authorize! update_and_respond(object: @exercise_collection, params: exercise_collection_params) end - def statistics - end + def statistics; end private @@ -51,8 +50,18 @@ class ExerciseCollectionsController < ApplicationController end def exercise_collection_params - sanitized_params = params[:exercise_collection].present? ? params[:exercise_collection].permit(:name, :use_anomaly_detection, :user_id, :user_type, :exercise_ids => []).merge(user_type: InternalUser.name) : {} - sanitized_params[:exercise_ids] = sanitized_params[:exercise_ids].reject {|v| v.nil? or v == ''} - sanitized_params.tap {|p| p[:exercise_collection_items] = p[:exercise_ids].map.with_index {|_id, index| ExerciseCollectionItem.find_or_create_by(exercise_id: _id, exercise_collection_id: @exercise_collection.id, position: index)}; p.delete(:exercise_ids)} + sanitized_params = if params[:exercise_collection].present? + params[:exercise_collection].permit(:name, + :use_anomaly_detection, :user_id, :user_type, exercise_ids: []).merge(user_type: InternalUser.name) + else + {} + end + sanitized_params[:exercise_ids] = sanitized_params[:exercise_ids].reject {|v| v.nil? or v == '' } + sanitized_params.tap do |p| + p[:exercise_collection_items] = p[:exercise_ids].map.with_index do |_id, index| + ExerciseCollectionItem.find_or_create_by(exercise_id: _id, exercise_collection_id: @exercise_collection.id, position: index) + end + p.delete(:exercise_ids) + end end end diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index b26ee75b..07a75fd9 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -9,15 +9,19 @@ class ExercisesController < ApplicationController before_action :handle_file_uploads, only: %i[create update] before_action :set_execution_environments, only: %i[create edit new update] - before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + %i[clone implement working_times intervention search run statistics submit reload feedback requests_for_comments study_group_dashboard export_external_check export_external_confirm] + before_action :set_exercise_and_authorize, + only: MEMBER_ACTIONS + %i[clone implement working_times intervention search run statistics submit reload feedback + requests_for_comments study_group_dashboard export_external_check export_external_confirm] before_action :set_external_user_and_authorize, only: [:statistics] before_action :set_file_types, only: %i[create edit new update] before_action :set_course_token, only: [:implement] before_action :set_available_tips, only: %i[implement show new edit] - skip_before_action :verify_authenticity_token, only: %i[import_exercise import_uuid_check export_external_confirm export_external_check] + skip_before_action :verify_authenticity_token, + only: %i[import_exercise import_uuid_check export_external_confirm export_external_check] skip_after_action :verify_authorized, only: %i[import_exercise import_uuid_check export_external_confirm] - skip_after_action :verify_policy_scoped, only: %i[import_exercise import_uuid_check export_external_confirm], raise: false + skip_after_action :verify_policy_scoped, only: %i[import_exercise import_uuid_check export_external_confirm], +raise: false def authorize! authorize(@exercise || @exercises) @@ -72,8 +76,8 @@ class ExercisesController < ApplicationController return if performed? myparam = exercise_params.presence || {} - checked_exercise_tags = @exercise_tags.select { |et| myparam[:tag_ids].include? et.tag.id.to_s } - removed_exercise_tags = @exercise_tags.reject { |et| myparam[:tag_ids].include? et.tag.id.to_s } + checked_exercise_tags = @exercise_tags.select {|et| myparam[:tag_ids].include? et.tag.id.to_s } + removed_exercise_tags = @exercise_tags.reject {|et| myparam[:tag_ids].include? et.tag.id.to_s } checked_exercise_tags.each do |et| et.factor = params[:tag_factors][et.tag_id.to_s][:factor] @@ -106,7 +110,8 @@ class ExercisesController < ApplicationController end def export_external_check - codeharbor_check = ExerciseService::CheckExternal.call(uuid: @exercise.uuid, codeharbor_link: current_user.codeharbor_link) + codeharbor_check = ExerciseService::CheckExternal.call(uuid: @exercise.uuid, +codeharbor_link: current_user.codeharbor_link) render json: { message: codeharbor_check[:message], actions: render_to_string( @@ -116,9 +121,9 @@ class ExercisesController < ApplicationController exercise_found: codeharbor_check[:exercise_found], update_right: codeharbor_check[:update_right], error: codeharbor_check[:error], - exported: false + exported: false, } - ) + ), }, status: :ok end @@ -133,14 +138,16 @@ class ExercisesController < ApplicationController render json: { status: 'success', message: t('exercises.export_codeharbor.successfully_exported', id: @exercise.id, title: @exercise.title), - actions: render_to_string(partial: 'export_actions', locals: {exercise: @exercise, exported: true, error: error}) + actions: render_to_string(partial: 'export_actions', +locals: {exercise: @exercise, exported: true, error: error}), } @exercise.save else render json: { status: 'fail', message: t('exercises.export_codeharbor.export_failed', id: @exercise.id, title: @exercise.title, error: error), - actions: render_to_string(partial: 'export_actions', locals: {exercise: @exercise, exported: true, error: error}) + actions: render_to_string(partial: 'export_actions', +locals: {exercise: @exercise, exported: true, error: error}), } end end @@ -177,7 +184,7 @@ class ExercisesController < ApplicationController render json: t('exercises.import_codeharbor.import_errors.invalid'), status: :bad_request rescue StandardError => e Sentry.capture_exception(e) - render json: t('exercises.import_codeharbor.import_errors.internal_error'), status: 500 + render json: t('exercises.import_codeharbor.import_errors.internal_error'), status: :internal_server_error end def user_from_api_key @@ -194,7 +201,11 @@ class ExercisesController < ApplicationController private :user_by_codeharbor_token def exercise_params - params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :submission_deadline, :late_submission_deadline, :public, :unpublished, :hide_file_tree, :allow_file_creation, :allow_auto_completion, :title, :expected_difficulty, :tips, files_attributes: file_attributes, tag_ids: []).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:exercise].present? + if params[:exercise].present? + params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :submission_deadline, :late_submission_deadline, :public, :unpublished, :hide_file_tree, :allow_file_creation, :allow_auto_completion, :title, :expected_difficulty, :tips, files_attributes: file_attributes, tag_ids: []).merge( +user_id: current_user.id, user_type: current_user.class.name +) + end end private :exercise_params @@ -261,8 +272,10 @@ class ExercisesController < ApplicationController redirect_to(@exercise, alert: t('exercises.implement.unpublished')) if @exercise.unpublished? && current_user.role != 'admin' && current_user.role != 'teacher' # TODO: TESTESTEST redirect_to(@exercise, alert: t('exercises.implement.no_files')) unless @exercise.files.visible.exists? user_solved_exercise = @exercise.has_user_solved(current_user) - count_interventions_today = UserExerciseIntervention.where(user: current_user).where('created_at >= ?', Time.zone.now.beginning_of_day).count - user_got_intervention_in_exercise = UserExerciseIntervention.where(user: current_user, exercise: @exercise).size >= max_intervention_count_per_exercise + count_interventions_today = UserExerciseIntervention.where(user: current_user).where('created_at >= ?', + Time.zone.now.beginning_of_day).count + user_got_intervention_in_exercise = UserExerciseIntervention.where(user: current_user, +exercise: @exercise).size >= max_intervention_count_per_exercise (user_got_enough_interventions = count_interventions_today >= max_intervention_count_per_day) || user_got_intervention_in_exercise if @embed_options[:disable_interventions] @@ -331,14 +344,15 @@ class ExercisesController < ApplicationController end # Return an array with top-level tips - @tips = nested_tips.values.select { |tip| tip.parent_exercise_tip_id.nil? } + @tips = nested_tips.values.select {|tip| tip.parent_exercise_tip_id.nil? } end private :set_available_tips def working_times working_time_accumulated = @exercise.accumulated_working_time_for_only(current_user) working_time_75_percentile = @exercise.get_quantiles([0.75]).first - render(json: {working_time_75_percentile: working_time_75_percentile, working_time_accumulated: working_time_accumulated}) + render(json: {working_time_75_percentile: working_time_75_percentile, +working_time_accumulated: working_time_accumulated}) end def intervention @@ -436,7 +450,9 @@ class ExercisesController < ApplicationController checked_exercise_tags = @exercise.exercise_tags checked_tags = checked_exercise_tags.collect(&:tag).to_set unchecked_tags = Tag.all.to_set.subtract checked_tags - @exercise_tags = checked_exercise_tags + unchecked_tags.collect { |tag| ExerciseTag.new(exercise: @exercise, tag: tag) } + @exercise_tags = checked_exercise_tags + unchecked_tags.collect do |tag| + ExerciseTag.new(exercise: @exercise, tag: tag) + end end private :collect_set_and_unset_exercise_tags @@ -453,8 +469,10 @@ class ExercisesController < ApplicationController # Render statistics page for one specific external user authorize(@external_user, :statistics?) if policy(@exercise).detailed_statistics? - @submissions = Submission.where(user: @external_user, exercise_id: @exercise.id).in_study_group_of(current_user).order('created_at') - interventions = UserExerciseIntervention.where('user_id = ? AND exercise_id = ?', @external_user.id, @exercise.id) + @submissions = Submission.where(user: @external_user, +exercise_id: @exercise.id).in_study_group_of(current_user).order('created_at') + interventions = UserExerciseIntervention.where('user_id = ? AND exercise_id = ?', @external_user.id, + @exercise.id) @all_events = (@submissions + interventions).sort_by(&:created_at) @deltas = @all_events.map.with_index do |item, index| delta = item.created_at - @all_events[index - 1].created_at if index.positive? @@ -465,7 +483,8 @@ class ExercisesController < ApplicationController @working_times_until.push((format_time_difference(@deltas[0..index].inject(:+)) if index.positive?)) end else - final_submissions = Submission.where(user: @external_user, exercise_id: @exercise.id).in_study_group_of(current_user).final + final_submissions = Submission.where(user: @external_user, +exercise_id: @exercise.id).in_study_group_of(current_user).final @submissions = [] %i[before_deadline within_grace_period after_late_deadline].each do |filter| relevant_submission = final_submissions.send(filter).latest @@ -492,7 +511,7 @@ class ExercisesController < ApplicationController user_statistics[tuple['user_id'].to_i] = tuple end render locals: { - user_statistics: user_statistics + user_statistics: user_statistics, } end end @@ -508,7 +527,8 @@ class ExercisesController < ApplicationController end def transmit_lti_score - ::NewRelic::Agent.add_custom_attributes({submission: @submission.id, normalized_score: @submission.normalized_score}) + ::NewRelic::Agent.add_custom_attributes({submission: @submission.id, +normalized_score: @submission.normalized_score}) response = send_score(@submission) if response[:status] == 'success' @@ -533,8 +553,8 @@ class ExercisesController < ApplicationController return if performed? myparam = exercise_params - checked_exercise_tags = @exercise_tags.select { |et| myparam[:tag_ids].include? et.tag.id.to_s } - removed_exercise_tags = @exercise_tags.reject { |et| myparam[:tag_ids].include? et.tag.id.to_s } + checked_exercise_tags = @exercise_tags.select {|et| myparam[:tag_ids].include? et.tag.id.to_s } + removed_exercise_tags = @exercise_tags.reject {|et| myparam[:tag_ids].include? et.tag.id.to_s } checked_exercise_tags.each do |et| et.factor = params[:tag_factors][et.tag_id.to_s][:factor] @@ -624,9 +644,9 @@ class ExercisesController < ApplicationController authorize! @study_group_id = params[:study_group_id] @request_for_comments = RequestForComment - .where(exercise: @exercise).includes(:submission) - .where(submissions: {study_group_id: @study_group_id}) - .order(created_at: :desc) + .where(exercise: @exercise).includes(:submission) + .where(submissions: {study_group_id: @study_group_id}) + .order(created_at: :desc) @graph_data = @exercise.get_working_times_for_study_group(@study_group_id) end diff --git a/app/controllers/external_users_controller.rb b/app/controllers/external_users_controller.rb index 7b3e1a91..b5609c9e 100644 --- a/app/controllers/external_users_controller.rb +++ b/app/controllers/external_users_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExternalUsersController < ApplicationController before_action :require_user! @@ -17,8 +19,8 @@ class ExternalUsersController < ApplicationController authorize! end - def working_time_query(tag=nil) - """ + def working_time_query(tag = nil) + " SELECT user_id, bar.exercise_id, max(score) as maximum_score, @@ -43,16 +45,16 @@ class ExternalUsersController < ApplicationController FROM submissions WHERE user_id = #{@user.id} AND user_type = 'ExternalUser' - #{!current_user.admin? ? "AND study_group_id IN (#{current_user.study_groups.pluck(:id).join(', ')}) AND cause = 'submit'" : ''} + #{current_user.admin? ? '' : "AND study_group_id IN (#{current_user.study_groups.pluck(:id).join(', ')}) AND cause = 'submit'"} GROUP BY exercise_id, user_id, id ) AS foo ) AS bar - #{tag.nil? ? '' : ' JOIN exercise_tags et ON et.exercise_id = bar.exercise_id AND et.tag_id = ' + tag + ' '} + #{tag.nil? ? '' : " JOIN exercise_tags et ON et.exercise_id = bar.exercise_id AND et.tag_id = #{tag} "} GROUP BY user_id, bar.exercise_id; - """ + " end def statistics @@ -62,11 +64,11 @@ class ExternalUsersController < ApplicationController statistics = {} ApplicationRecord.connection.execute(working_time_query(params[:tag])).each do |tuple| - statistics[tuple["exercise_id"].to_i] = tuple + statistics[tuple['exercise_id'].to_i] = tuple end render locals: { - statistics: statistics + statistics: statistics, } end @@ -75,15 +77,15 @@ class ExternalUsersController < ApplicationController authorize! statistics = [] - tags = ProxyExercise.new().get_user_knowledge_and_max_knowledge(@user, @user.participations.uniq.compact) + tags = ProxyExercise.new.get_user_knowledge_and_max_knowledge(@user, @user.participations.uniq.compact) tags[:user_topic_knowledge].each_pair do |tag, value| - statistics.append({key: tag.name.to_s, value: (100.0 / tags[:max_topic_knowledge][tag] * value).round, id: tag.id}) + statistics.append({key: tag.name.to_s, value: (100.0 / tags[:max_topic_knowledge][tag] * value).round, +id: tag.id}) end - statistics.sort_by! {|item| -item[:value]} + statistics.sort_by! {|item| -item[:value] } respond_to do |format| format.json { render(json: statistics) } end end - end diff --git a/app/controllers/file_templates_controller.rb b/app/controllers/file_templates_controller.rb index 04c2a98a..da1ae5b1 100644 --- a/app/controllers/file_templates_controller.rb +++ b/app/controllers/file_templates_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class FileTemplatesController < ApplicationController - before_action :set_file_template, only: [:show, :edit, :update, :destroy] + before_action :set_file_template, only: %i[show edit update destroy] def authorize! authorize(@file_template || @file_templates) @@ -7,7 +9,7 @@ class FileTemplatesController < ApplicationController private :authorize! def by_file_type - @file_templates = FileTemplate.where(:file_type_id => params[:file_type_id]) + @file_templates = FileTemplate.where(file_type_id: params[:file_type_id]) authorize! respond_to do |format| format.json { render :show, status: :ok, json: @file_templates.to_json } @@ -82,13 +84,14 @@ class FileTemplatesController < ApplicationController end private - # Use callbacks to share common setup or constraints between actions. - def set_file_template - @file_template = FileTemplate.find(params[:id]) - end - # Never trust parameters from the scary internet, only allow the white list through. - def file_template_params - params[:file_template].permit(:name, :file_type_id, :content) if params[:file_template].present? - end + # Use callbacks to share common setup or constraints between actions. + def set_file_template + @file_template = FileTemplate.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def file_template_params + params[:file_template].permit(:name, :file_type_id, :content) if params[:file_template].present? + end end diff --git a/app/controllers/file_types_controller.rb b/app/controllers/file_types_controller.rb index d450df3d..53228ce6 100644 --- a/app/controllers/file_types_controller.rb +++ b/app/controllers/file_types_controller.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class FileTypesController < ApplicationController include CommonBehavior - before_action :set_editor_modes, only: [:create, :edit, :new, :update] + before_action :set_editor_modes, only: %i[create edit new update] before_action :set_file_type, only: MEMBER_ACTIONS def authorize! @@ -19,11 +21,14 @@ class FileTypesController < ApplicationController destroy_and_respond(object: @file_type) end - def edit - end + def edit; end def file_type_params - params[:file_type].permit(:binary, :editor_mode, :executable, :file_extension, :name, :indent_size, :renderable).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:file_type].present? + if params[:file_type].present? + params[:file_type].permit(:binary, :editor_mode, :executable, :file_extension, :name, :indent_size, :renderable).merge( +user_id: current_user.id, user_type: current_user.class.name +) + end end private :file_type_params @@ -39,7 +44,7 @@ class FileTypesController < ApplicationController def set_editor_modes @editor_modes = Dir.glob('vendor/assets/javascripts/ace/mode-*.js').sort.map do |filename| - name = filename.gsub(/\w+\/|mode-|.js$/, '') + name = filename.gsub(%r{\w+/|mode-|.js$}, '') [name, "ace/mode/#{name}"] end end @@ -51,8 +56,7 @@ class FileTypesController < ApplicationController end private :set_file_type - def show - end + def show; end def update update_and_respond(object: @file_type, params: file_type_params) diff --git a/app/controllers/flowr_controller.rb b/app/controllers/flowr_controller.rb index 310d91d2..b507d174 100644 --- a/app/controllers/flowr_controller.rb +++ b/app/controllers/flowr_controller.rb @@ -1,11 +1,12 @@ -class FlowrController < ApplicationController +# frozen_string_literal: true +class FlowrController < ApplicationController def insights require_user! # get the latest submission for this user that also has a test run (i.e. structured_errors if applicable) submission = Submission.joins(:testruns) - .where(submissions: {user_id: current_user.id, user_type: current_user.class.name}) - .order('testruns.created_at DESC').first + .where(submissions: {user_id: current_user.id, user_type: current_user.class.name}) + .order('testruns.created_at DESC').first # Return if no submission was found if submission.blank? || @embed_options[:disable_hints] || @embed_options[:hide_test_results] @@ -26,8 +27,8 @@ class FlowrController < ApplicationController end # once the programming language model becomes available, the language name can be added to the query to # produce more relevant results - query = attributes.map{|att| att.value}.join(' ') - { submission: submission, error: error, attributes: attributes, query: query } + query = attributes.map(&:value).join(' ') + {submission: submission, error: error, attributes: attributes, query: query} end # Always return JSON diff --git a/app/controllers/internal_users_controller.rb b/app/controllers/internal_users_controller.rb index 90c390e1..c57de79f 100644 --- a/app/controllers/internal_users_controller.rb +++ b/app/controllers/internal_users_controller.rb @@ -93,7 +93,8 @@ class InternalUsersController < ApplicationController private :require_reset_password_token def require_token(type) - @user = InternalUser.send(:"load_from_#{type}_token", params[:token] || params[:internal_user].try(:[], :"#{type}_token")) + @user = InternalUser.send(:"load_from_#{type}_token", + params[:token] || params[:internal_user].try(:[], :"#{type}_token")) render_not_authorized unless @user end private :require_token diff --git a/app/controllers/proxy_exercises_controller.rb b/app/controllers/proxy_exercises_controller.rb index b5c7eccd..565e6079 100644 --- a/app/controllers/proxy_exercises_controller.rb +++ b/app/controllers/proxy_exercises_controller.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class ProxyExercisesController < ApplicationController include CommonBehavior - before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :reload] + before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + %i[clone reload] def authorize! authorize(@proxy_exercise || @proxy_exercises) @@ -9,10 +11,11 @@ class ProxyExercisesController < ApplicationController private :authorize! def clone - proxy_exercise = @proxy_exercise.duplicate(public: false, token: nil, exercises: @proxy_exercise.exercises, user: current_user) + proxy_exercise = @proxy_exercise.duplicate(public: false, token: nil, exercises: @proxy_exercise.exercises, +user: current_user) proxy_exercise.send(:generate_token) if proxy_exercise.save - redirect_to(proxy_exercise, notice: t('shared.object_cloned', model: ProxyExercise.model_name.human)) + redirect_to(proxy_exercise, notice: t('shared.object_cloned', model: ProxyExercise.model_name.human)) else flash[:danger] = t('shared.message_failure') redirect_to(@proxy_exercise) @@ -21,7 +24,7 @@ class ProxyExercisesController < ApplicationController def create myparams = proxy_exercise_params - myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject { |c| c.empty? }) + myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject(&:empty?)) @proxy_exercise = ProxyExercise.new(myparams) authorize! @@ -39,7 +42,10 @@ class ProxyExercisesController < ApplicationController end def proxy_exercise_params - params[:proxy_exercise].permit(:description, :title, :public, :exercise_ids => []).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:proxy_exercise].present? + if params[:proxy_exercise].present? + params[:proxy_exercise].permit(:description, :title, :public, exercise_ids: []).merge(user_id: current_user.id, +user_type: current_user.class.name) + end end private :proxy_exercise_params @@ -50,7 +56,7 @@ class ProxyExercisesController < ApplicationController end def new - @proxy_exercise = ProxyExercise.new + @proxy_exercise = ProxyExercise.new @search = policy_scope(Exercise).ransack(params[:q]) @exercises = @search.result.order(:title) authorize! @@ -64,17 +70,15 @@ class ProxyExercisesController < ApplicationController def show @search = @proxy_exercise.exercises.ransack - @exercises = @proxy_exercise.exercises.ransack.result.order(:title) #@search.result.order(:title) + @exercises = @proxy_exercise.exercises.ransack.result.order(:title) # @search.result.order(:title) end - #we might want to think about auth here - def reload - end + # we might want to think about auth here + def reload; end def update myparams = proxy_exercise_params - myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject { |c| c.blank? }) + myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject(&:blank?)) update_and_respond(object: @proxy_exercise, params: myparams) end - end diff --git a/app/controllers/remote_evaluation_controller.rb b/app/controllers/remote_evaluation_controller.rb index 4c35c2aa..2dd3bee7 100644 --- a/app/controllers/remote_evaluation_controller.rb +++ b/app/controllers/remote_evaluation_controller.rb @@ -26,7 +26,7 @@ class RemoteEvaluationController < ApplicationController if @submission.present? score_achieved_percentage = @submission.normalized_score result = try_lti - result.merge!({score: score_achieved_percentage * 100}) unless result[:score] + result[:score] = score_achieved_percentage * 100 unless result[:score] status = result[:status] end @@ -38,7 +38,9 @@ class RemoteEvaluationController < ApplicationController lti_response = send_score(@submission) process_lti_response(lti_response) else - {message: "Your submission was successfully scored with #{@submission.normalized_score}%. However, your score could not be sent to the e-Learning platform. Please reopen the exercise through the e-Learning platform and try again.", status: 410} + { + message: "Your submission was successfully scored with #{@submission.normalized_score}%. However, your score could not be sent to the e-Learning platform. Please reopen the exercise through the e-Learning platform and try again.", status: 410 + } end end private :try_lti @@ -48,7 +50,8 @@ class RemoteEvaluationController < ApplicationController # Score has been reduced due to the passed deadline {message: I18n.t('exercises.submit.too_late'), status: 207, score: lti_response[:score_sent] * 100} elsif lti_response[:status] == 'success' - {message: I18n.t('sessions.destroy_through_lti.success_with_outcome', consumer: @submission.user.consumer.name), status: 202} + {message: I18n.t('sessions.destroy_through_lti.success_with_outcome', consumer: @submission.user.consumer.name), +status: 202} else {message: I18n.t('exercises.submit.failure'), status: 424} end @@ -77,7 +80,8 @@ class RemoteEvaluationController < ApplicationController submission_params[:study_group_id] = remote_evaluation_mapping.study_group_id submission_params[:cause] = cause submission_params[:user_type] = remote_evaluation_mapping.user_type - submission_params[:files_attributes] = reject_illegal_file_attributes(remote_evaluation_mapping.exercise, files_attributes) + submission_params[:files_attributes] = + reject_illegal_file_attributes(remote_evaluation_mapping.exercise, files_attributes) submission_params end private :build_submission_params diff --git a/app/controllers/request_for_comments_controller.rb b/app/controllers/request_for_comments_controller.rb index 128a5690..9330f0e0 100644 --- a/app/controllers/request_for_comments_controller.rb +++ b/app/controllers/request_for_comments_controller.rb @@ -5,7 +5,8 @@ class RequestForCommentsController < ApplicationController before_action :require_user! before_action :set_request_for_comment, only: %i[show mark_as_solved set_thank_you_note] - before_action :set_study_group_grouping, only: %i[index get_my_comment_requests get_rfcs_with_my_comments get_rfcs_for_exercise] + before_action :set_study_group_grouping, + only: %i[index get_my_comment_requests get_rfcs_with_my_comments get_rfcs_for_exercise] def authorize! authorize(@request_for_comments || @request_for_comment) @@ -16,15 +17,15 @@ class RequestForCommentsController < ApplicationController # GET /request_for_comments.json def index @search = RequestForComment - .last_per_user(2) - .with_last_activity - .ransack(params[:q]) + .last_per_user(2) + .with_last_activity + .ransack(params[:q]) @request_for_comments = @search.result - .joins(:exercise) - .where(exercises: {unpublished: false}) - .includes(submission: [:study_group]) - .order('created_at DESC') - .paginate(page: params[:page], total_entries: @search.result.length) + .joins(:exercise) + .where(exercises: {unpublished: false}) + .includes(submission: [:study_group]) + .order('created_at DESC') + .paginate(page: params[:page], total_entries: @search.result.length) authorize! end @@ -32,12 +33,12 @@ class RequestForCommentsController < ApplicationController # GET /my_request_for_comments def get_my_comment_requests @search = RequestForComment - .with_last_activity - .where(user: current_user) - .ransack(params[:q]) + .with_last_activity + .where(user: current_user) + .ransack(params[:q]) @request_for_comments = @search.result - .order('created_at DESC') - .paginate(page: params[:page]) + .order('created_at DESC') + .paginate(page: params[:page]) authorize! render 'index' end @@ -45,13 +46,13 @@ class RequestForCommentsController < ApplicationController # GET /my_rfc_activity def get_rfcs_with_my_comments @search = RequestForComment - .with_last_activity - .joins(:comments) # we don't need to outer join here, because we know the user has commented on these - .where(comments: {user_id: current_user.id}) - .ransack(params[:q]) + .with_last_activity + .joins(:comments) # we don't need to outer join here, because we know the user has commented on these + .where(comments: {user_id: current_user.id}) + .ransack(params[:q]) @request_for_comments = @search.result - .order('last_comment DESC') - .paginate(page: params[:page]) + .order('last_comment DESC') + .paginate(page: params[:page]) authorize! render 'index' end @@ -60,13 +61,13 @@ class RequestForCommentsController < ApplicationController def get_rfcs_for_exercise exercise = Exercise.find(params[:exercise_id]) @search = RequestForComment - .with_last_activity - .where(exercise_id: exercise.id) - .ransack(params[:q]) + .with_last_activity + .where(exercise_id: exercise.id) + .ransack(params[:q]) @request_for_comments = @search.result - .joins(:exercise) - .order('last_comment DESC') - .paginate(page: params[:page]) + .joins(:exercise) + .order('last_comment DESC') + .paginate(page: params[:page]) # let the exercise decide, whether its rfcs should be visible authorize(exercise) render 'index' @@ -91,7 +92,7 @@ class RequestForCommentsController < ApplicationController @request_for_comment.thank_you_note = params[:note] commenters = @request_for_comment.commenters - commenters.each { |commenter| UserMailer.send_thank_you_note(@request_for_comment, commenter).deliver_now } + commenters.each {|commenter| UserMailer.send_thank_you_note(@request_for_comment, commenter).deliver_now } respond_to do |format| if @request_for_comment.save @@ -143,14 +144,16 @@ class RequestForCommentsController < ApplicationController # Never trust parameters from the scary internet, only allow the white list through. def request_for_comment_params # The study_group_id might not be present in the session (e.g. for internal users), resulting in session[:study_group_id] = nil which is intended. - params.require(:request_for_comment).permit(:exercise_id, :file_id, :question, :requested_at, :solved, :submission_id).merge(user_id: current_user.id, user_type: current_user.class.name) + params.require(:request_for_comment).permit(:exercise_id, :file_id, :question, :requested_at, :solved, :submission_id).merge( +user_id: current_user.id, user_type: current_user.class.name +) end # The index page requires the grouping of the study groups # The study groups are grouped by the current study group and other study groups of the user def set_study_group_grouping current_study_group = StudyGroup.find_by(id: session[:study_group_id]) - my_study_groups = current_user.study_groups.reject { |group| group == current_study_group } + my_study_groups = current_user.study_groups.reject {|group| group == current_study_group } @study_groups_grouping = [[t('request_for_comments.index.study_groups.current'), Array(current_study_group)], [t('request_for_comments.index.study_groups.my'), my_study_groups]] end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 7cfe0e41..4a9b16c6 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + class SessionsController < ApplicationController include Lti - [:require_oauth_parameters, :require_valid_consumer_key, :require_valid_oauth_signature, :require_unique_oauth_nonce, :set_current_user, :require_valid_exercise_token, :set_study_group_membership, :set_embedding_options].each do |method_name| + %i[require_oauth_parameters require_valid_consumer_key require_valid_oauth_signature require_unique_oauth_nonce + set_current_user require_valid_exercise_token set_study_group_membership set_embedding_options].each do |method_name| before_action(method_name, only: :create_through_lti) end @@ -24,8 +27,8 @@ class SessionsController < ApplicationController redirect_to(params[:custom_redirect_target]) else redirect_to(implement_exercise_path(@exercise), - notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id) ? 'with' : 'without'}_outcome", - consumer: @consumer)) + notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id) ? 'with' : 'without'}_outcome", + consumer: @consumer)) end end diff --git a/app/controllers/statistics_controller.rb b/app/controllers/statistics_controller.rb index 00c969f0..48572463 100644 --- a/app/controllers/statistics_controller.rb +++ b/app/controllers/statistics_controller.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + class StatisticsController < ApplicationController include StatisticsHelper - before_action :authorize!, only: [:show, :graphs, :user_activity, :user_activity_history, :rfc_activity, - :rfc_activity_history] + before_action :authorize!, only: %i[show graphs user_activity user_activity_history rfc_activity + rfc_activity_history] def policy_class StatisticsPolicy @@ -15,8 +17,7 @@ class StatisticsController < ApplicationController end end - def graphs - end + def graphs; end def user_activity respond_to do |format| @@ -27,7 +28,7 @@ class StatisticsController < ApplicationController def user_activity_history respond_to do |format| format.html { render('activity_history', locals: {resource: :user}) } - format.json { render_ranged_data :ranged_user_data} + format.json { render_ranged_data :ranged_user_data } end end @@ -46,14 +47,21 @@ class StatisticsController < ApplicationController def render_ranged_data(data_source) interval = params[:interval].to_s.empty? ? 'year' : params[:interval] - from = DateTime.strptime(params[:from], '%Y-%m-%d') rescue DateTime.new(0) - to = DateTime.strptime(params[:to], '%Y-%m-%d') rescue DateTime.now - render(json: self.send(data_source, interval, from, to)) + from = begin + DateTime.strptime(params[:from], '%Y-%m-%d') + rescue StandardError + DateTime.new(0) + end + to = begin + DateTime.strptime(params[:to], '%Y-%m-%d') + rescue StandardError + DateTime.now + end + render(json: send(data_source, interval, from, to)) end def authorize! authorize self end private :authorize! - end diff --git a/app/controllers/study_groups_controller.rb b/app/controllers/study_groups_controller.rb index ce7a49f3..1bd3a4fa 100644 --- a/app/controllers/study_groups_controller.rb +++ b/app/controllers/study_groups_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StudyGroupsController < ApplicationController include CommonBehavior @@ -20,7 +22,8 @@ class StudyGroupsController < ApplicationController def update myparams = study_group_params - myparams[:external_users] = StudyGroupMembership.find(myparams[:study_group_membership_ids].reject(&:empty?)).map(&:user) + myparams[:external_users] = + StudyGroupMembership.find(myparams[:study_group_membership_ids].reject(&:empty?)).map(&:user) myparams.delete(:study_group_membership_ids) update_and_respond(object: @study_group, params: myparams) end @@ -30,7 +33,7 @@ class StudyGroupsController < ApplicationController end def study_group_params - params[:study_group].permit(:id, :name, :study_group_membership_ids => []) if params[:study_group].present? + params[:study_group].permit(:id, :name, study_group_membership_ids: []) if params[:study_group].present? end private :study_group_params @@ -44,5 +47,4 @@ class StudyGroupsController < ApplicationController authorize(@study_groups || @study_group) end private :authorize! - end diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index 5b62c322..09c85239 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SubmissionsController < ApplicationController include ActionController::Live include CommonBehavior @@ -6,15 +8,16 @@ class SubmissionsController < ApplicationController include SubmissionScoring include Tubesock::Hijack - before_action :set_submission, only: [:download, :download_file, :render_file, :run, :score, :extract_errors, :show, :statistics, :stop, :test] - before_action :set_docker_client, only: [:run, :test] - before_action :set_files, only: [:download, :download_file, :render_file, :show, :run] - before_action :set_file, only: [:download_file, :render_file, :run] - before_action :set_mime_type, only: [:download_file, :render_file] - skip_before_action :verify_authenticity_token, only: [:download_file, :render_file] + before_action :set_submission, + only: %i[download download_file render_file run score extract_errors show statistics stop test] + before_action :set_docker_client, only: %i[run test] + before_action :set_files, only: %i[download download_file render_file show run] + before_action :set_file, only: %i[download_file render_file run] + before_action :set_mime_type, only: %i[download_file render_file] + skip_before_action :verify_authenticity_token, only: %i[download_file render_file] def max_run_output_buffer_size - if(@submission.cause == 'requestComments') + if @submission.cause == 'requestComments' 5000 else 500 @@ -34,30 +37,30 @@ class SubmissionsController < ApplicationController end def command_substitutions(filename) - {class_name: File.basename(filename, File.extname(filename)).camelize, filename: filename, module_name: File.basename(filename, File.extname(filename)).underscore} + {class_name: File.basename(filename, File.extname(filename)).camelize, filename: filename, +module_name: File.basename(filename, File.extname(filename)).underscore} end private :command_substitutions def copy_comments # copy each annotation and set the target_file.id - unless(params[:annotations_arr].nil?) - params[:annotations_arr].each do | annotation | - #comment = Comment.new(annotation[1].permit(:user_id, :file_id, :user_type, :row, :column, :text, :created_at, :updated_at)) - comment = Comment.new(:user_id => annotation[1][:user_id], :file_id => annotation[1][:file_id], :user_type => current_user.class.name, :row => annotation[1][:row], :column => annotation[1][:column], :text => annotation[1][:text]) - source_file = CodeOcean::File.find(annotation[1][:file_id]) + params[:annotations_arr]&.each do |annotation| + # comment = Comment.new(annotation[1].permit(:user_id, :file_id, :user_type, :row, :column, :text, :created_at, :updated_at)) + comment = Comment.new(user_id: annotation[1][:user_id], file_id: annotation[1][:file_id], +user_type: current_user.class.name, row: annotation[1][:row], column: annotation[1][:column], text: annotation[1][:text]) + source_file = CodeOcean::File.find(annotation[1][:file_id]) - # retrieve target file - target_file = @submission.files.detect do |file| - # file_id has to be that of a the former iteration OR of the initial file (if this is the first run) - file.file_id == source_file.file_id || file.file_id == source_file.id #seems to be needed here: (check this): || file.file_id == source_file.id ; yes this is needed, for comments on templates as well as comments on files added by users. - end - - #save to assign an id - target_file.save! - - comment.file_id = target_file.id - comment.save! + # retrieve target file + target_file = @submission.files.detect do |file| + # file_id has to be that of a the former iteration OR of the initial file (if this is the first run) + file.file_id == source_file.file_id || file.file_id == source_file.id # seems to be needed here: (check this): || file.file_id == source_file.id ; yes this is needed, for comments on templates as well as comments on files added by users. end + + # save to assign an id + target_file.save! + + comment.file_id = target_file.id + comment.save! end end @@ -75,30 +78,35 @@ class SubmissionsController < ApplicationController require 'zip' stringio = Zip::OutputStream.write_buffer do |zio| @files.each do |file| - zio.put_next_entry(file.path.to_s == '' ? file.name_with_extension : File.join(file.path, file.name_with_extension)) - zio.write(file.content.present? ? file.content : file.native_file.read) + zio.put_next_entry(if file.path.to_s == '' + file.name_with_extension + else + File.join(file.path, + file.name_with_extension) + end) + zio.write(file.content.presence || file.native_file.read) end # zip exercise description - zio.put_next_entry(t('activerecord.models.exercise.one') + '.txt') - zio.write(@submission.exercise.title + "\r\n======================\r\n") + zio.put_next_entry("#{t('activerecord.models.exercise.one')}.txt") + zio.write("#{@submission.exercise.title}\r\n======================\r\n") zio.write(@submission.exercise.description) # zip .co file - zio.put_next_entry(".co") - zio.write(File.read id_file) + zio.put_next_entry('.co') + zio.write(File.read(id_file)) File.delete(id_file) if File.exist?(id_file) # zip client scripts scripts_path = 'app/assets/remote_scripts' Dir.foreach(scripts_path) do |file| - next if file == '.' or file == '..' - zio.put_next_entry(File.join('.scripts', File.basename(file))) - zio.write(File.read File.join(scripts_path, file)) - end + next if (file == '.') || (file == '..') + zio.put_next_entry(File.join('.scripts', File.basename(file))) + zio.write(File.read(File.join(scripts_path, file))) + end end - send_data(stringio.string, filename: @submission.exercise.title.tr(" ", "_") + ".zip") + send_data(stringio.string, filename: "#{@submission.exercise.title.tr(' ', '_')}.zip") end def download_file @@ -128,7 +136,7 @@ class SubmissionsController < ApplicationController end def run - # TODO reimplement SSEs with websocket commands + # TODO: reimplement SSEs with websocket commands # with_server_sent_events do |server_sent_event| # output = @docker_client.execute_run_command(@submission, sanitize_filename) @@ -155,56 +163,54 @@ class SubmissionsController < ApplicationController end end - # socket is the socket into the container, tubesock is the socket to the client # give the docker_client the tubesock object, so that it can send messages (timeout) @docker_client.tubesock = tubesock - container_request_time = Time.now + container_request_time = Time.zone.now result = @docker_client.execute_run_command(@submission, sanitize_filename) tubesock.send_data JSON.dump({'cmd' => 'status', 'status' => result[:status]}) - @waiting_for_container_time = Time.now - container_request_time + @waiting_for_container_time = Time.zone.now - container_request_time if result[:status] == :container_running socket = result[:socket] command = result[:command] socket.on :message do |event| - Rails.logger.info( Time.now.getutc.to_s + ": Docker sending: " + event.data) + Rails.logger.info("#{Time.zone.now.getutc}: Docker sending: #{event.data}") handle_message(event.data, tubesock, result[:container]) end - socket.on :close do |event| + socket.on :close do |_event| kill_socket(tubesock) end tubesock.onmessage do |data| - Rails.logger.info(Time.now.getutc.to_s + ": Client sending: " + data) + Rails.logger.info("#{Time.zone.now.getutc}: Client sending: #{data}") # Check whether the client send a JSON command and kill container # if the command is 'client_kill', send it to docker otherwise. begin - parsed = JSON.parse(data) unless data == "\n" - if parsed.class == Hash && parsed['cmd'] == 'client_kill' - Rails.logger.debug("Client exited container.") + if parsed.instance_of?(Hash) && parsed['cmd'] == 'client_kill' + Rails.logger.debug('Client exited container.') @docker_client.kill_container(result[:container]) else socket.send data - Rails.logger.debug('Sent the received client data to docker:' + data) + Rails.logger.debug("Sent the received client data to docker:#{data}") end - rescue JSON::ParserError => error + rescue JSON::ParserError => e socket.send data - Rails.logger.debug('Rescued parsing error, sent the received client data to docker:' + data) + Rails.logger.debug("Rescued parsing error, sent the received client data to docker:#{data}") Sentry.set_extras(data: data) end end # Send command after all listeners are attached. # Newline required to flush - @execution_request_time = Time.now - socket.send command + "\n" - Rails.logger.info('Sent command: ' + command.to_s) + @execution_request_time = Time.zone.now + socket.send "#{command}\n" + Rails.logger.info("Sent command: #{command}") else kill_socket(tubesock) end @@ -212,7 +218,7 @@ class SubmissionsController < ApplicationController end def kill_socket(tubesock) - @container_execution_time = Time.now - @execution_request_time unless @execution_request_time.blank? + @container_execution_time = Time.zone.now - @execution_request_time if @execution_request_time.present? # search for errors and save them as StructuredError (for scoring runs see submission_scoring.rb) errors = extract_errors send_hints(tubesock, errors) @@ -225,7 +231,7 @@ class SubmissionsController < ApplicationController if @run_output.blank? || @run_output&.strip == '{"cmd":"exit"}' || @run_output&.strip == 'timeout:' @raw_output ||= '' @run_output ||= '' - parse_message t('exercises.implement.no_output', timestamp: l(Time.now, format: :short)), 'stdout', tubesock + parse_message t('exercises.implement.no_output', timestamp: l(Time.zone.now, format: :short)), 'stdout', tubesock end # Hijacked connection needs to be notified correctly @@ -237,25 +243,26 @@ class SubmissionsController < ApplicationController @raw_output ||= '' @run_output ||= '' # Handle special commands first - if /^#exit|{"cmd": "exit"}/.match(message) - # Just call exit_container on the docker_client. - # Do not call kill_socket for the websocket to the client here. - # @docker_client.exit_container closes the socket to the container, - # kill_socket is called in the "on close handler" of the websocket to the container - @docker_client.exit_container(container) - elsif /^#timeout/.match(message) - @run_output = 'timeout: ' + @run_output # add information that this run timed out to the buffer - else - # Filter out information about run_command, test_command, user or working directory - run_command = @submission.execution_environment.run_command % command_substitutions(sanitize_filename) - test_command = @submission.execution_environment.test_command % command_substitutions(sanitize_filename) - if test_command.blank? - # If no test command is set, use the run_command for the RegEx below. Otherwise, no output will be displayed! - test_command = run_command - end - unless /root@|:\/workspace|#{run_command}|#{test_command}|bash: cmd:canvasevent: command not found/.match(message) - parse_message(message, 'stdout', tubesock, container) - end + case message + when /^#exit|{"cmd": "exit"}/ + # Just call exit_container on the docker_client. + # Do not call kill_socket for the websocket to the client here. + # @docker_client.exit_container closes the socket to the container, + # kill_socket is called in the "on close handler" of the websocket to the container + @docker_client.exit_container(container) + when /^#timeout/ + @run_output = "timeout: #{@run_output}" # add information that this run timed out to the buffer + else + # Filter out information about run_command, test_command, user or working directory + run_command = @submission.execution_environment.run_command % command_substitutions(sanitize_filename) + test_command = @submission.execution_environment.test_command % command_substitutions(sanitize_filename) + if test_command.blank? + # If no test command is set, use the run_command for the RegEx below. Otherwise, no output will be displayed! + test_command = run_command + end + unless %r{root@|:/workspace|#{run_command}|#{test_command}|bash: cmd:canvasevent: command not found}.match?(message) + parse_message(message, 'stdout', tubesock, container) + end end end @@ -263,58 +270,58 @@ class SubmissionsController < ApplicationController parsed = '' begin parsed = JSON.parse(message) - if parsed.class == Hash and parsed.key?('cmd') + if parsed.instance_of?(Hash) && parsed.key?('cmd') socket.send_data message - Rails.logger.info('parse_message sent: ' + message) + Rails.logger.info("parse_message sent: #{message}") @docker_client.exit_container(container) if container && parsed['cmd'] == 'exit' else - parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>message} + parsed = {'cmd' => 'write', 'stream' => output_stream, 'data' => message} socket.send_data JSON.dump(parsed) - Rails.logger.info('parse_message sent: ' + JSON.dump(parsed)) + Rails.logger.info("parse_message sent: #{JSON.dump(parsed)}") end rescue JSON::ParserError => e # Check wether the message contains multiple lines, if true try to parse each line - if recursive and message.include? "\n" - for part in message.split("\n") - self.parse_message(part,output_stream,socket, container, false) + if recursive && message.include?("\n") + message.split("\n").each do |part| + parse_message(part, output_stream, socket, container, false) end elsif message.include?('') + # Rails.logger.info('Starting to buffer') + elsif @buffering && message.include?('/>') @buffer += message - parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>@buffer} + parsed = {'cmd' => 'write', 'stream' => output_stream, 'data' => @buffer} socket.send_data JSON.dump(parsed) - #socket.send_data @buffer + # socket.send_data @buffer @buffering = false - #Rails.logger.info('Sent complete buffer') - elsif @buffering and message.end_with?("}\r") + # Rails.logger.info('Sent complete buffer') + elsif @buffering && message.end_with?("}\r") @buffer += message socket.send_data @buffer @buffering = false - #Rails.logger.info('Sent complete buffer') + # Rails.logger.info('Sent complete buffer') elsif @buffering @buffer += message - #Rails.logger.info('Appending to buffer') + # Rails.logger.info('Appending to buffer') else - #Rails.logger.info('else') - parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>message} + # Rails.logger.info('else') + parsed = {'cmd' => 'write', 'stream' => output_stream, 'data' => message} socket.send_data JSON.dump(parsed) - Rails.logger.info('parse_message sent: ' + JSON.dump(parsed)) + Rails.logger.info("parse_message sent: #{JSON.dump(parsed)}") end ensure - @raw_output += parsed['data'].to_s if parsed.class == Hash and parsed.key? 'data' + @raw_output += parsed['data'].to_s if parsed.instance_of?(Hash) && parsed.key?('data') # save the data that was send to the run_output if there is enough space left. this will be persisted as a testrun with cause "run" @run_output += JSON.dump(parsed).to_s if @run_output.size <= max_run_output_buffer_size end end def save_run_output - unless @run_output.blank? - @run_output = @run_output[(0..max_run_output_buffer_size-1)] # trim the string to max_message_buffer_size chars + if @run_output.present? + @run_output = @run_output[(0..max_run_output_buffer_size - 1)] # trim the string to max_message_buffer_size chars Testrun.create( file: @file, cause: 'run', @@ -328,7 +335,7 @@ class SubmissionsController < ApplicationController def extract_errors results = [] - unless @raw_output.blank? + if @raw_output.present? @submission.exercise.execution_environment.error_templates.each do |template| pattern = Regexp.new(template.signature).freeze if pattern.match(@raw_output) @@ -361,7 +368,7 @@ class SubmissionsController < ApplicationController tubesock.send_data JSON.dump(score_submission(@submission)) # To enable hints when scoring a submission, uncomment the next line: - #send_hints(tubesock, StructuredError.where(submission: @submission)) + # send_hints(tubesock, StructuredError.where(submission: @submission)) tubesock.send_data JSON.dump({'cmd' => 'exit'}) ensure @@ -372,8 +379,9 @@ class SubmissionsController < ApplicationController def send_hints(tubesock, errors) return if @embed_options[:disable_hints] - errors = errors.to_a.uniq { |e| e.hint} - errors.each do | error | + + errors = errors.to_a.uniq(&:hint) + errors.each do |error| tubesock.send_data JSON.dump({cmd: 'hint', hint: error.hint, description: error.error_template.description}) end end @@ -384,7 +392,7 @@ class SubmissionsController < ApplicationController private :set_docker_client def set_file - @file = @files.detect { |file| file.name_with_extension == sanitize_filename } + @file = @files.detect {|file| file.name_with_extension == sanitize_filename } head :not_found unless @file end private :set_file @@ -406,11 +414,9 @@ class SubmissionsController < ApplicationController end private :set_submission - def show - end + def show; end - def statistics - end + def statistics; end def test hijack do |tubesock| @@ -436,10 +442,10 @@ class SubmissionsController < ApplicationController server_sent_event.write(nil, event: 'start') yield(server_sent_event) if block_given? server_sent_event.write({code: 200}, event: 'close') - rescue => exception - Sentry.capture_exception(exception) - logger.error(exception.message) - logger.error(exception.backtrace.join("\n")) + rescue StandardError => e + Sentry.capture_exception(e) + logger.error(e.message) + logger.error(e.backtrace.join("\n")) server_sent_event.write({code: 500}, event: 'close') ensure server_sent_event.close @@ -457,16 +463,16 @@ class SubmissionsController < ApplicationController ) # create .co file - path = "tmp/" + user.id.to_s + ".co" + path = "tmp/#{user.id}.co" # parse validation token content = "#{remote_evaluation_mapping.validation_token}\n" # parse remote request url content += "#{request.base_url}/evaluate\n" @submission.files.each do |file| file_path = file.path.to_s == '' ? file.name_with_extension : File.join(file.path, file.name_with_extension) - content += "#{file_path}=#{file.file_id.to_s}\n" + content += "#{file_path}=#{file.file_id}\n" end - File.open(path, "w+") do |f| + File.open(path, 'w+') do |f| f.write(content) end path diff --git a/app/controllers/subscriptions_controller.rb b/app/controllers/subscriptions_controller.rb index f86431e2..508bdcd6 100644 --- a/app/controllers/subscriptions_controller.rb +++ b/app/controllers/subscriptions_controller.rb @@ -1,5 +1,6 @@ -class SubscriptionsController < ApplicationController +# frozen_string_literal: true +class SubscriptionsController < ApplicationController def authorize! authorize(@subscription || @subscriptions) end @@ -21,28 +22,26 @@ class SubscriptionsController < ApplicationController # DELETE /subscriptions/1 # DELETE /subscriptions/1.json def destroy - begin - @subscription = Subscription.find(params[:id]) - rescue - skip_authorization + @subscription = Subscription.find(params[:id]) + rescue StandardError + skip_authorization + respond_to do |format| + format.html { redirect_to request_for_comments_url, alert: t('subscriptions.subscription_not_existent') } + format.json { render json: {message: t('subscriptions.subscription_not_existent')}, status: :not_found } + end + else + authorize! + rfc = @subscription.try(:request_for_comment) + @subscription.deleted = true + if @subscription.save respond_to do |format| - format.html { redirect_to request_for_comments_url, alert: t('subscriptions.subscription_not_existent') } - format.json { render json: {message: t('subscriptions.subscription_not_existent')}, status: :not_found } + format.html { redirect_to request_for_comment_url(rfc), notice: t('subscriptions.successfully_unsubscribed') } + format.json { render json: {message: t('subscriptions.successfully_unsubscribed')}, status: :ok } end else - authorize! - rfc = @subscription.try(:request_for_comment) - @subscription.deleted = true - if @subscription.save - respond_to do |format| - format.html { redirect_to request_for_comment_url(rfc), notice: t('subscriptions.successfully_unsubscribed') } - format.json { render json: {message: t('subscriptions.successfully_unsubscribed')}, status: :ok} - end - else - respond_to do |format| - format.html { redirect_to request_for_comment_url(rfc), :flash => { :danger => t('shared.message_failure') } } - format.json { render json: {message: t('shared.message_failure')}, status: :internal_server_error} - end + respond_to do |format| + format.html { redirect_to request_for_comment_url(rfc), flash: {danger: t('shared.message_failure')} } + format.json { render json: {message: t('shared.message_failure')}, status: :internal_server_error } end end end @@ -56,7 +55,10 @@ class SubscriptionsController < ApplicationController def subscription_params current_user_id = current_user.try(:id) current_user_class_name = current_user.try(:class).try(:name) - params[:subscription].permit(:request_for_comment_id, :subscription_type).merge(user_id: current_user_id, user_type: current_user_class_name, deleted: false) if params[:subscription].present? + if params[:subscription].present? + params[:subscription].permit(:request_for_comment_id, :subscription_type).merge(user_id: current_user_id, +user_type: current_user_class_name, deleted: false) + end end private :subscription_params end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index ac462653..5b95df11 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TagsController < ApplicationController include CommonBehavior @@ -18,8 +20,7 @@ class TagsController < ApplicationController destroy_and_respond(object: @tag) end - def edit - end + def edit; end def tag_params params[:tag].permit(:name) if params[:tag].present? @@ -42,8 +43,7 @@ class TagsController < ApplicationController end private :set_tag - def show - end + def show; end def update update_and_respond(object: @tag, params: tag_params) diff --git a/app/controllers/tips_controller.rb b/app/controllers/tips_controller.rb index 9fa5170c..7afb4baf 100644 --- a/app/controllers/tips_controller.rb +++ b/app/controllers/tips_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TipsController < ApplicationController include CommonBehavior @@ -19,15 +21,14 @@ class TipsController < ApplicationController destroy_and_respond(object: @tip) end - def edit - end + def edit; end def tip_params - return unless params[:tip].present? + return if params[:tip].blank? params[:tip] .permit(:title, :description, :example, :file_type_id) - .each { |_key, value| value.strip! unless value.is_a?(Array) } + .each {|_key, value| value.strip! unless value.is_a?(Array) } .merge(user_id: current_user.id, user_type: current_user.class.name) end private :tip_params @@ -48,8 +49,7 @@ class TipsController < ApplicationController end private :set_tip - def show - end + def show; end def update update_and_respond(object: @tip, params: tip_params) diff --git a/app/controllers/user_exercise_feedbacks_controller.rb b/app/controllers/user_exercise_feedbacks_controller.rb index e2e8a941..a4545c45 100644 --- a/app/controllers/user_exercise_feedbacks_controller.rb +++ b/app/controllers/user_exercise_feedbacks_controller.rb @@ -28,10 +28,10 @@ class UserExerciseFeedbacksController < ApplicationController @exercise = Exercise.find(uef_params[:exercise_id]) rfc = RequestForComment.unsolved.where(exercise_id: @exercise.id, user_id: current_user.id).first submission = begin - current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first - rescue StandardError - nil - end + current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first + rescue StandardError + nil + end if @exercise @uef = UserExerciseFeedback.find_or_initialize_by(user: current_user, exercise: @exercise) @@ -74,10 +74,10 @@ class UserExerciseFeedbacksController < ApplicationController def update submission = begin - current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first - rescue StandardError - nil - end + current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first + rescue StandardError + nil + end rfc = RequestForComment.unsolved.where(exercise_id: @exercise.id, user_id: current_user.id).first authorize! if @exercise && validate_inputs(uef_params) @@ -115,7 +115,7 @@ class UserExerciseFeedbacksController < ApplicationController end def uef_params - return unless params[:user_exercise_feedback].present? + return if params[:user_exercise_feedback].blank? exercise_id = if params[:user_exercise_feedback].nil? params[:exercise_id] @@ -126,8 +126,8 @@ class UserExerciseFeedbacksController < ApplicationController user_id = current_user.id user_type = current_user.class.name latest_submission = Submission - .where(user_id: user_id, user_type: user_type, exercise_id: exercise_id) - .order(created_at: :desc).first + .where(user_id: user_id, user_type: user_type, exercise_id: exercise_id) + .order(created_at: :desc).first params[:user_exercise_feedback] .permit(:feedback_text, :difficulty, :exercise_id, :user_estimated_worktime) @@ -140,10 +140,8 @@ class UserExerciseFeedbacksController < ApplicationController def validate_inputs(uef_params) if uef_params[:difficulty].to_i.negative? || uef_params[:difficulty].to_i >= comment_presets.size false - elsif uef_params[:user_estimated_worktime].to_i.negative? || uef_params[:user_estimated_worktime].to_i >= time_presets.size - false else - true + !(uef_params[:user_estimated_worktime].to_i.negative? || uef_params[:user_estimated_worktime].to_i >= time_presets.size) end rescue StandardError false diff --git a/app/helpers/action_cable_helper.rb b/app/helpers/action_cable_helper.rb index 01fa00d9..d09c5e0e 100644 --- a/app/helpers/action_cable_helper.rb +++ b/app/helpers/action_cable_helper.rb @@ -1,15 +1,17 @@ # frozen_string_literal: true + module ActionCableHelper def trigger_rfc_action_cable Thread.new do # Context: RfC if submission.study_group_id.present? ActionCable.server.broadcast( - "la_exercises_#{exercise_id}_channel_study_group_#{submission.study_group_id}", - type: :rfc, - id: id, - html: ApplicationController.render(partial: 'request_for_comments/list_entry', - locals: {request_for_comment: self})) + "la_exercises_#{exercise_id}_channel_study_group_#{submission.study_group_id}", + type: :rfc, + id: id, + html: ApplicationController.render(partial: 'request_for_comments/list_entry', + locals: {request_for_comment: self}) + ) end ensure ActiveRecord::Base.connection_pool.release_connection @@ -26,9 +28,10 @@ module ActionCableHelper # Context: Submission if study_group_id.present? ActionCable.server.broadcast( - "la_exercises_#{exercise_id}_channel_study_group_#{study_group_id}", - type: :working_times, - working_time_data: exercise.get_working_times_for_study_group(study_group_id, user)) + "la_exercises_#{exercise_id}_channel_study_group_#{study_group_id}", + type: :working_times, + working_time_data: exercise.get_working_times_for_study_group(study_group_id, user) + ) end ensure ActiveRecord::Base.connection_pool.release_connection diff --git a/app/helpers/admin/dashboard_helper.rb b/app/helpers/admin/dashboard_helper.rb index 4b84627a..791b430d 100644 --- a/app/helpers/admin/dashboard_helper.rb +++ b/app/helpers/admin/dashboard_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Admin module DashboardHelper def dashboard_data diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 20b89244..23439b01 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationHelper APPLICATION_NAME = 'CodeOcean' @@ -7,8 +9,8 @@ module ApplicationHelper def code_tag(code, language = nil) if code.present? - content_tag(:pre) do - content_tag(:code, code, class: "language-#{language}") + tag.pre do + tag.code(code, class: "language-#{language}") end else empty @@ -16,12 +18,12 @@ module ApplicationHelper end def empty - content_tag(:i, nil, class: 'empty fa fa-minus') + tag.i(nil, class: 'empty fa fa-minus') end def label_column(label) - content_tag(:div, class: 'col-sm-3') do - content_tag(:strong) do + tag.div(class: 'col-sm-3') do + tag.strong do I18n.translation_present?("activerecord.attributes.#{label}") ? t("activerecord.attributes.#{label}") : t(label) end end @@ -29,12 +31,13 @@ module ApplicationHelper private :label_column def no - content_tag(:i, nil, class: 'fa fa-times') + tag.i(nil, class: 'fa fa-times') end def progress_bar(value) - content_tag(:div, class: value ? 'progress' : 'disabled progress') do - content_tag(:div, value ? "#{value}%" : '', :'aria-valuemax' => 100, :'aria-valuemin' => 0, :'aria-valuenow' => value, class: 'progress-bar progress-bar-striped', role: 'progressbar', style: "width: #{[value || 0, 100].min}%;") + tag.div(class: value ? 'progress' : 'disabled progress') do + tag.div(value ? "#{value}%" : '', 'aria-valuemax': 100, 'aria-valuemin': 0, +'aria-valuenow': value, class: 'progress-bar progress-bar-striped', role: 'progressbar', style: "width: #{[value || 0, 100].min}%;") end end @@ -43,7 +46,7 @@ module ApplicationHelper end def row(options = {}, &block) - content_tag(:div, class: 'attribute-row row') do + tag.div(class: 'attribute-row row') do label_column(options[:label]) + value_column(options[:value], &block) end end @@ -61,13 +64,13 @@ module ApplicationHelper end def value_column(value) - content_tag(:div, class: 'col-sm-9') do + tag.div(class: 'col-sm-9') do block_given? ? yield : symbol_for(value) end end private :value_column def yes - content_tag(:i, nil, class: 'fa fa-check') + tag.i(nil, class: 'fa fa-check') end end diff --git a/app/helpers/error_template_attributes_helper.rb b/app/helpers/error_template_attributes_helper.rb index 9046f407..708ba2c4 100644 --- a/app/helpers/error_template_attributes_helper.rb +++ b/app/helpers/error_template_attributes_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ErrorTemplateAttributesHelper end diff --git a/app/helpers/error_templates_helper.rb b/app/helpers/error_templates_helper.rb index f42cf302..99320810 100644 --- a/app/helpers/error_templates_helper.rb +++ b/app/helpers/error_templates_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ErrorTemplatesHelper end diff --git a/app/helpers/exercise_helper.rb b/app/helpers/exercise_helper.rb index 190a18f3..26343917 100644 --- a/app/helpers/exercise_helper.rb +++ b/app/helpers/exercise_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ExerciseHelper include LtiHelper @@ -6,7 +8,7 @@ module ExerciseHelper end def qa_js_tag - javascript_include_tag qa_url + "/assets/qa_api.js" + javascript_include_tag "#{qa_url}/assets/qa_api.js" end def qa_url @@ -15,8 +17,6 @@ module ExerciseHelper if enabled config.read[:code_pilot][:url] - else - return nil end end end diff --git a/app/helpers/lti_helper.rb b/app/helpers/lti_helper.rb index 9d2f56b5..a398a7ea 100644 --- a/app/helpers/lti_helper.rb +++ b/app/helpers/lti_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'oauth/request_proxy/action_controller_request' # Rails 5 changed `Rack::Request` to `ActionDispatch::Request` module LtiHelper diff --git a/app/helpers/pagedown_form_builder.rb b/app/helpers/pagedown_form_builder.rb index d38407f2..6b1ec5c6 100644 --- a/app/helpers/pagedown_form_builder.rb +++ b/app/helpers/pagedown_form_builder.rb @@ -16,20 +16,19 @@ class PagedownFormBuilder < ActionView::Helpers::FormBuilder private def wmd_button_bar - @template.content_tag :div, nil, id: "wmd-button-bar-#{base_id}" + @template.tag.div(nil, id: "wmd-button-bar-#{base_id}") end def wmd_textarea @template.text_area @object_name, @attribute_name, - **@input_html_options, - class: 'form-control wmd-input', - id: "wmd-input-#{base_id}" + **@input_html_options, + class: 'form-control wmd-input', + id: "wmd-input-#{base_id}" end def wmd_preview - @template.content_tag :div, nil, - class: 'wmd-preview', - id: "wmd-preview-#{base_id}" + @template.tag.div(nil, class: 'wmd-preview', + id: "wmd-preview-#{base_id}") end def show_wmd_preview? diff --git a/app/helpers/statistics_helper.rb b/app/helpers/statistics_helper.rb index 76135219..57ddd57d 100644 --- a/app/helpers/statistics_helper.rb +++ b/app/helpers/statistics_helper.rb @@ -1,226 +1,231 @@ -module StatisticsHelper +# frozen_string_literal: true +module StatisticsHelper WORKING_TIME_DELTA_IN_SECONDS = 5.minutes WORKING_TIME_DELTA_IN_SQL_INTERVAL = "'0:05:00'" # yes, a string with quotes def statistics_data [ - { - key: 'users', - name: t('statistics.sections.users'), - entries: user_statistics - }, - { - key: 'exercises', - name: t('statistics.sections.exercises'), - entries: exercise_statistics - }, - { - key: 'request_for_comments', - name: t('statistics.sections.request_for_comments'), - entries: rfc_statistics - } + { + key: 'users', + name: t('statistics.sections.users'), + entries: user_statistics, + }, + { + key: 'exercises', + name: t('statistics.sections.exercises'), + entries: exercise_statistics, + }, + { + key: 'request_for_comments', + name: t('statistics.sections.request_for_comments'), + entries: rfc_statistics, + }, ] end def user_statistics [ - { - key: 'internal_users', - name: t('activerecord.models.internal_user.other'), - data: InternalUser.count, - url: internal_users_path - }, - { - key: 'external_users', - name: t('activerecord.models.external_user.other'), - data: ExternalUser.count, - url: external_users_path - }, - { - key: 'currently_active', - name: t('statistics.entries.users.currently_active'), - data: ExternalUser.joins(:submissions) - .where(['submissions.created_at >= ?', DateTime.now - 5.minutes]) - .distinct('external_users.id').count, - url: 'statistics/graphs' - } + { + key: 'internal_users', + name: t('activerecord.models.internal_user.other'), + data: InternalUser.count, + url: internal_users_path, + }, + { + key: 'external_users', + name: t('activerecord.models.external_user.other'), + data: ExternalUser.count, + url: external_users_path, + }, + { + key: 'currently_active', + name: t('statistics.entries.users.currently_active'), + data: ExternalUser.joins(:submissions) + .where(['submissions.created_at >= ?', DateTime.now - 5.minutes]) + .distinct('external_users.id').count, + url: 'statistics/graphs', + }, ] end def exercise_statistics [ - { - key: 'exercises', - name: t('activerecord.models.exercise.other'), - data: Exercise.count, - url: exercises_path - }, - { - key: 'average_submissions', - name: t('statistics.entries.exercises.average_number_of_submissions'), - data: (Submission.count.to_f / Exercise.count).round(2) - }, - { - key: 'submissions_per_minute', - name: t('statistics.entries.exercises.submissions_per_minute'), - data: (Submission.where('created_at >= ?', DateTime.now - 1.hours).count.to_f / 60).round(2), - unit: '/min', - url: statistics_graphs_path - }, - { - key: 'autosaves_per_minute', - name: t('statistics.entries.exercises.autosaves_per_minute'), - data: (Submission.where('created_at >= ?', DateTime.now - 1.hours).where(cause: 'autosave').count.to_f / 60).round(2), - unit: '/min' - }, - { - key: 'container_requests_per_minute', - name: t('statistics.entries.exercises.container_requests_per_minute'), - data: (Testrun.where('created_at >= ?', DateTime.now - 1.hours).count.to_f / 60).round(2), - unit: '/min' - }, - { - key: 'execution_environments', - name: t('activerecord.models.execution_environment.other'), - data: ExecutionEnvironment.count, - url: execution_environments_path - }, - { - key: 'exercise_collections', - name: t('activerecord.models.exercise_collection.other'), - data: ExerciseCollection.count, - url: exercise_collections_path - } + { + key: 'exercises', + name: t('activerecord.models.exercise.other'), + data: Exercise.count, + url: exercises_path, + }, + { + key: 'average_submissions', + name: t('statistics.entries.exercises.average_number_of_submissions'), + data: (Submission.count.to_f / Exercise.count).round(2), + }, + { + key: 'submissions_per_minute', + name: t('statistics.entries.exercises.submissions_per_minute'), + data: (Submission.where('created_at >= ?', DateTime.now - 1.hour).count.to_f / 60).round(2), + unit: '/min', + url: statistics_graphs_path, + }, + { + key: 'autosaves_per_minute', + name: t('statistics.entries.exercises.autosaves_per_minute'), + data: (Submission.where('created_at >= ?', + DateTime.now - 1.hour).where(cause: 'autosave').count.to_f / 60).round(2), + unit: '/min', + }, + { + key: 'container_requests_per_minute', + name: t('statistics.entries.exercises.container_requests_per_minute'), + data: (Testrun.where('created_at >= ?', DateTime.now - 1.hour).count.to_f / 60).round(2), + unit: '/min', + }, + { + key: 'execution_environments', + name: t('activerecord.models.execution_environment.other'), + data: ExecutionEnvironment.count, + url: execution_environments_path, + }, + { + key: 'exercise_collections', + name: t('activerecord.models.exercise_collection.other'), + data: ExerciseCollection.count, + url: exercise_collections_path, + }, ] end def rfc_statistics rfc_activity_data + [ - { - key: 'comments', - name: t('activerecord.models.comment.other'), - data: Comment.count - } + { + key: 'comments', + name: t('activerecord.models.comment.other'), + data: Comment.count, + }, ] end def user_activity_live_data [ - { - key: 'active_in_last_hour', - name: t('statistics.entries.users.currently_active'), - data: ExternalUser.joins(:submissions) - .where(['submissions.created_at >= ?', DateTime.now - 5.minutes]) - .distinct('external_users.id').count, - }, - { - key: 'submissions_per_minute', - name: t('statistics.entries.exercises.submissions_per_minute'), - data: (Submission.where('created_at >= ?', DateTime.now - 1.hours).count.to_f / 60).round(2), - unit: '/min', - axis: 'right' - } + { + key: 'active_in_last_hour', + name: t('statistics.entries.users.currently_active'), + data: ExternalUser.joins(:submissions) + .where(['submissions.created_at >= ?', DateTime.now - 5.minutes]) + .distinct('external_users.id').count, + }, + { + key: 'submissions_per_minute', + name: t('statistics.entries.exercises.submissions_per_minute'), + data: (Submission.where('created_at >= ?', DateTime.now - 1.hour).count.to_f / 60).round(2), + unit: '/min', + axis: 'right', + }, ] end - def rfc_activity_data(from=DateTime.new(0), to=DateTime.now) + def rfc_activity_data(from = DateTime.new(0), to = DateTime.now) [ - { - key: 'rfcs', - name: t('activerecord.models.request_for_comment.other'), - data: RequestForComment.in_range(from, to).count, - url: request_for_comments_path - }, - { - key: 'percent_solved', - name: t('statistics.entries.request_for_comments.percent_solved'), - data: (100.0 / RequestForComment.in_range(from, to).count * RequestForComment.in_range(from, to).where(solved: true).count).round(1), - unit: '%', - axis: 'right', - url: statistics_graphs_path - }, - { - key: 'percent_soft_solved', - name: t('statistics.entries.request_for_comments.percent_soft_solved'), - data: (100.0 / RequestForComment.in_range(from, to).count * RequestForComment.in_range(from, to).unsolved.where(full_score_reached: true).count).round(1), - unit: '%', - axis: 'right', - url: statistics_graphs_path - }, - { - key: 'percent_unsolved', - name: t('statistics.entries.request_for_comments.percent_unsolved'), - data: (100.0 / RequestForComment.in_range(from, to).count * RequestForComment.in_range(from, to).unsolved.count).round(1), - unit: '%', - axis: 'right', - url: statistics_graphs_path - }, - { - key: 'rfcs_with_comments', - name: t('statistics.entries.request_for_comments.with_comments'), - data: RequestForComment.in_range(from, to).joins('join "submissions" s on s.id = request_for_comments.submission_id + { + key: 'rfcs', + name: t('activerecord.models.request_for_comment.other'), + data: RequestForComment.in_range(from, to).count, + url: request_for_comments_path, + }, + { + key: 'percent_solved', + name: t('statistics.entries.request_for_comments.percent_solved'), + data: (100.0 / RequestForComment.in_range(from, + to).count * RequestForComment.in_range(from, to).where(solved: true).count).round(1), + unit: '%', + axis: 'right', + url: statistics_graphs_path, + }, + { + key: 'percent_soft_solved', + name: t('statistics.entries.request_for_comments.percent_soft_solved'), + data: (100.0 / RequestForComment.in_range(from, + to).count * RequestForComment.in_range(from, to).unsolved.where(full_score_reached: true).count).round(1), + unit: '%', + axis: 'right', + url: statistics_graphs_path, + }, + { + key: 'percent_unsolved', + name: t('statistics.entries.request_for_comments.percent_unsolved'), + data: (100.0 / RequestForComment.in_range(from, + to).count * RequestForComment.in_range(from, to).unsolved.count).round(1), + unit: '%', + axis: 'right', + url: statistics_graphs_path, + }, + { + key: 'rfcs_with_comments', + name: t('statistics.entries.request_for_comments.with_comments'), + data: RequestForComment.in_range(from, + to).joins('join "submissions" s on s.id = request_for_comments.submission_id join "files" f on f.context_id = s.id and f.context_type = \'Submission\' join "comments" c on c.file_id = f.id').group('request_for_comments.id').count.size, - url: statistics_graphs_path - } + url: statistics_graphs_path, + }, ] end - def ranged_rfc_data(interval='year', from=DateTime.new(0), to=DateTime.now) + def ranged_rfc_data(interval = 'year', from = DateTime.new(0), to = DateTime.now) [ - { - key: 'rfcs', - name: t('activerecord.models.request_for_comment.other'), - data: RequestForComment.in_range(from, to) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") - .group('key').order('key') - }, - { - key: 'rfcs_solved', - name: t('statistics.entries.request_for_comments.percent_solved'), - data: RequestForComment.in_range(from, to) - .where(solved: true) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") - .group('key').order('key') - }, - { - key: 'rfcs_soft_solved', - name: t('statistics.entries.request_for_comments.percent_soft_solved'), - data: RequestForComment.in_range(from, to).unsolved - .where(full_score_reached: true) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") - .group('key').order('key') - }, - { - key: 'rfcs_unsolved', - name: t('statistics.entries.request_for_comments.percent_unsolved'), - data: RequestForComment.in_range(from, to).unsolved - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") - .group('key').order('key') - } + { + key: 'rfcs', + name: t('activerecord.models.request_for_comment.other'), + data: RequestForComment.in_range(from, to) + .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .group('key').order('key'), + }, + { + key: 'rfcs_solved', + name: t('statistics.entries.request_for_comments.percent_solved'), + data: RequestForComment.in_range(from, to) + .where(solved: true) + .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .group('key').order('key'), + }, + { + key: 'rfcs_soft_solved', + name: t('statistics.entries.request_for_comments.percent_soft_solved'), + data: RequestForComment.in_range(from, to).unsolved + .where(full_score_reached: true) + .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .group('key').order('key'), + }, + { + key: 'rfcs_unsolved', + name: t('statistics.entries.request_for_comments.percent_unsolved'), + data: RequestForComment.in_range(from, to).unsolved + .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .group('key').order('key'), + }, ] end - def ranged_user_data(interval='year', from=DateTime.new(0), to=DateTime.now) + def ranged_user_data(interval = 'year', from = DateTime.new(0), to = DateTime.now) [ - { - key: 'active', - name: t('statistics.entries.users.active'), - data: ExternalUser.joins(:submissions) - .where(submissions: {created_at: from..to}) - .select("date_trunc('#{interval}', submissions.created_at) AS \"key\", count(distinct external_users.id) AS \"value\"") - .group('key').order('key') - }, - { - key: 'submissions', - name: t('statistics.entries.exercises.submissions'), - data: Submission.where(created_at: from..to) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") - .group('key').order('key'), - axis: 'right' - } + { + key: 'active', + name: t('statistics.entries.users.active'), + data: ExternalUser.joins(:submissions) + .where(submissions: {created_at: from..to}) + .select("date_trunc('#{interval}', submissions.created_at) AS \"key\", count(distinct external_users.id) AS \"value\"") + .group('key').order('key'), + }, + { + key: 'submissions', + name: t('statistics.entries.exercises.submissions'), + data: Submission.where(created_at: from..to) + .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .group('key').order('key'), + axis: 'right', + }, ] end - end diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb index ca93c0d8..6db718ba 100644 --- a/app/helpers/time_helper.rb +++ b/app/helpers/time_helper.rb @@ -1,5 +1,6 @@ -module TimeHelper +# frozen_string_literal: true +module TimeHelper # convert timestamps ('12:34:56.789') to seconds def time_to_f(timestamp) unless timestamp.nil? @@ -11,7 +12,6 @@ module TimeHelper # given a delta in seconds, return a "Hours:Minutes:Seconds" representation def format_time_difference(delta) - Time.at(delta).utc.strftime("%H:%M:%S") + Time.at(delta).utc.strftime('%H:%M:%S') end - end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 1f88c014..13c9c250 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,8 +1,9 @@ -class UserMailer < ActionMailer::Base +# frozen_string_literal: true +class UserMailer < ApplicationMailer def mail(*args) # used to prevent the delivery to pseudonymous users without a valid email address - super unless args.first[:to].blank? + super if args.first[:to].present? end def activation_needed_email(user) @@ -10,8 +11,7 @@ class UserMailer < ActionMailer::Base mail(subject: t('mailers.user_mailer.activation_needed.subject'), to: user.email) end - def activation_success_email(*) - end + def activation_success_email(*); end def reset_password_email(user) @reset_password_url = reset_password_internal_user_url(user, token: user.reset_password_token) @@ -19,12 +19,15 @@ class UserMailer < ActionMailer::Base end def got_new_comment(comment, request_for_comment, commenting_user) - # todo: check whether we can take the last known locale of the receiver? + # TODO: check whether we can take the last known locale of the receiver? @receiver_displayname = request_for_comment.user.displayname @commenting_user_displayname = commenting_user.displayname @comment_text = comment.text @rfc_link = request_for_comment_url(request_for_comment) - mail(subject: t('mailers.user_mailer.got_new_comment.subject', commenting_user_displayname: @commenting_user_displayname), to: request_for_comment.user.email) + mail( +subject: t('mailers.user_mailer.got_new_comment.subject', + commenting_user_displayname: @commenting_user_displayname), to: request_for_comment.user.email +) end def got_new_comment_for_subscription(comment, subscription, from_user) @@ -33,7 +36,10 @@ class UserMailer < ActionMailer::Base @comment_text = comment.text @rfc_link = request_for_comment_url(subscription.request_for_comment) @unsubscribe_link = unsubscribe_subscription_url(subscription) - mail(subject: t('mailers.user_mailer.got_new_comment_for_subscription.subject', author_displayname: @author_displayname), to: subscription.user.email) + mail( +subject: t('mailers.user_mailer.got_new_comment_for_subscription.subject', + author_displayname: @author_displayname), to: subscription.user.email +) end def send_thank_you_note(request_for_comments, receiver) @@ -43,7 +49,7 @@ class UserMailer < ActionMailer::Base @rfc_link = request_for_comment_url(request_for_comments) mail(subject: t('mailers.user_mailer.send_thank_you_note.subject', author: @author), to: receiver.email) end - + def exercise_anomaly_detected(exercise_collection, anomalies) @user = exercise_collection.user @receiver_displayname = exercise_collection.user.displayname diff --git a/app/models/anomaly_notification.rb b/app/models/anomaly_notification.rb index 8e9498fa..5bafbac9 100644 --- a/app/models/anomaly_notification.rb +++ b/app/models/anomaly_notification.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AnomalyNotification < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :exercise diff --git a/app/models/code_ocean/file.rb b/app/models/code_ocean/file.rb index 9c452200..205a37de 100644 --- a/app/models/code_ocean/file.rb +++ b/app/models/code_ocean/file.rb @@ -1,16 +1,15 @@ -require File.expand_path('../../../uploaders/file_uploader', __FILE__) -require File.expand_path('../../../../lib/active_model/validations/boolean_presence_validator', __FILE__) +# frozen_string_literal: true + +require File.expand_path('../../uploaders/file_uploader', __dir__) +require File.expand_path('../../../lib/active_model/validations/boolean_presence_validator', __dir__) module CodeOcean - class FileNameValidator < ActiveModel::Validator def validate(record) existing_files = File.where(name: record.name, path: record.path, file_type_id: record.file_type_id, context_id: record.context_id, context_type: record.context_type).to_a - unless existing_files.empty? - if (not record.context.is_a?(Exercise)) || (record.context.new_record?) - record.errors[:base] << 'Duplicate' - end + if !existing_files.empty? && (!record.context.is_a?(Exercise) || record.context.new_record?) + record.errors[:base] << 'Duplicate' end end end @@ -19,7 +18,8 @@ module CodeOcean include DefaultValues DEFAULT_WEIGHT = 1.0 - ROLES = %w[regular_file main_file reference_implementation executable_file teacher_defined_test user_defined_file user_defined_test teacher_defined_linter].freeze + ROLES = %w[regular_file main_file reference_implementation executable_file teacher_defined_test user_defined_file + user_defined_test teacher_defined_linter].freeze TEACHER_DEFINED_ROLES = ROLES - %w[user_defined_file] after_initialize :set_default_values @@ -29,13 +29,13 @@ module CodeOcean belongs_to :context, polymorphic: true belongs_to :file, class_name: 'CodeOcean::File', optional: true # This is only required for submissions and is validated below - alias_method :ancestor, :file + alias ancestor file belongs_to :file_type has_many :files, class_name: 'CodeOcean::File' has_many :testruns has_many :comments - alias_method :descendants, :files + alias descendants files mount_uploader :native_file, FileUploader @@ -61,7 +61,7 @@ module CodeOcean validates :weight, absence: true, unless: :teacher_defined_assessment? validates :file, presence: true if :context.is_a?(Submission) - validates_with FileNameValidator, fields: [:name, :path, :file_type_id] + validates_with FileNameValidator, fields: %i[name path file_type_id] ROLES.each do |role| define_method("#{role}?") { self.role == role } @@ -94,7 +94,12 @@ module CodeOcean end def hash_content - self.hashed_content = Digest::MD5.new.hexdigest(file_type.try(:binary?) ? ::File.new(native_file.file.path, 'r').read : content) + self.hashed_content = Digest::MD5.new.hexdigest(if file_type.try(:binary?) + ::File.new(native_file.file.path, + 'r').read + else + content + end) end private :hash_content @@ -108,7 +113,7 @@ module CodeOcean end def set_ancestor_values - [:feedback_message, :file_type_id, :hidden, :name, :path, :read_only, :role, :weight].each do |attribute| + %i[feedback_message file_type_id hidden name path read_only role weight].each do |attribute| send(:"#{attribute}=", ancestor.send(attribute)) end end diff --git a/app/models/codeharbor_link.rb b/app/models/codeharbor_link.rb index b35dc6cf..b0403ef4 100644 --- a/app/models/codeharbor_link.rb +++ b/app/models/codeharbor_link.rb @@ -5,9 +5,7 @@ class CodeharborLink < ApplicationRecord validates :check_uuid_url, presence: true validates :api_key, presence: true - belongs_to :user, foreign_key: :user_id, class_name: 'InternalUser' + belongs_to :user, class_name: 'InternalUser' - def to_s - id.to_s - end + delegate :to_s, to: :id end diff --git a/app/models/concerns/context.rb b/app/models/concerns/context.rb index 18cadab7..6b47b065 100644 --- a/app/models/concerns/context.rb +++ b/app/models/concerns/context.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Context extend ActiveSupport::Concern diff --git a/app/models/concerns/creation.rb b/app/models/concerns/creation.rb index f2070ff5..ec16164f 100644 --- a/app/models/concerns/creation.rb +++ b/app/models/concerns/creation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Creation extend ActiveSupport::Concern diff --git a/app/models/concerns/default_values.rb b/app/models/concerns/default_values.rb index e5c7f231..3fe789d4 100644 --- a/app/models/concerns/default_values.rb +++ b/app/models/concerns/default_values.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DefaultValues def set_default_values_if_present(options = {}) options.each do |attribute, value| diff --git a/app/models/consumer.rb b/app/models/consumer.rb index dcb06c0c..691daeba 100644 --- a/app/models/consumer.rb +++ b/app/models/consumer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Consumer < ApplicationRecord has_many :users diff --git a/app/models/error_template.rb b/app/models/error_template.rb index 83c2f360..f7624c12 100644 --- a/app/models/error_template.rb +++ b/app/models/error_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ErrorTemplate < ApplicationRecord belongs_to :execution_environment has_and_belongs_to_many :error_template_attributes diff --git a/app/models/error_template_attribute.rb b/app/models/error_template_attribute.rb index 42661132..3a213e1e 100644 --- a/app/models/error_template_attribute.rb +++ b/app/models/error_template_attribute.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ErrorTemplateAttribute < ApplicationRecord has_and_belongs_to_many :error_template diff --git a/app/models/event.rb b/app/models/event.rb index bab444df..52f3744a 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Event < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :exercise diff --git a/app/models/execution_environment.rb b/app/models/execution_environment.rb index 33d57868..e4d39a93 100644 --- a/app/models/execution_environment.rb +++ b/app/models/execution_environment.rb @@ -1,4 +1,6 @@ -require File.expand_path('../../../lib/active_model/validations/boolean_presence_validator', __FILE__) +# frozen_string_literal: true + +require File.expand_path('../../lib/active_model/validations/boolean_presence_validator', __dir__) class ExecutionEnvironment < ApplicationRecord include Creation @@ -17,7 +19,8 @@ class ExecutionEnvironment < ApplicationRecord validate :valid_test_setup? validate :working_docker_image?, if: :validate_docker_image? validates :docker_image, presence: true - validates :memory_limit, numericality: {greater_than_or_equal_to: DockerClient::MINIMUM_MEMORY_LIMIT, only_integer: true}, presence: true + validates :memory_limit, + numericality: {greater_than_or_equal_to: DockerClient::MINIMUM_MEMORY_LIMIT, only_integer: true}, presence: true validates :network_enabled, boolean_presence: true validates :name, presence: true validates :permitted_execution_time, numericality: {only_integer: true}, presence: true @@ -35,7 +38,9 @@ class ExecutionEnvironment < ApplicationRecord def valid_test_setup? if test_command? ^ testing_framework? - errors.add(:test_command, I18n.t('activerecord.errors.messages.together', attribute: I18n.t('activerecord.attributes.execution_environment.testing_framework'))) + errors.add(:test_command, + I18n.t('activerecord.errors.messages.together', + attribute: I18n.t('activerecord.attributes.execution_environment.testing_framework'))) end end private :valid_test_setup? @@ -46,11 +51,11 @@ class ExecutionEnvironment < ApplicationRecord private :validate_docker_image? def working_docker_image? - DockerClient.pull(docker_image) unless DockerClient.find_image_by_tag(docker_image).blank? + DockerClient.pull(docker_image) if DockerClient.find_image_by_tag(docker_image).present? output = DockerClient.new(execution_environment: self).execute_arbitrary_command(VALIDATION_COMMAND) errors.add(:docker_image, "error: #{output[:stderr]}") if output[:stderr].present? - rescue DockerClient::Error => error - errors.add(:docker_image, "error: #{error}") + rescue DockerClient::Error => e + errors.add(:docker_image, "error: #{e}") end private :working_docker_image? end diff --git a/app/models/exercise.rb b/app/models/exercise.rb index a06f4b13..369e403a 100644 --- a/app/models/exercise.rb +++ b/app/models/exercise.rb @@ -41,7 +41,7 @@ class Exercise < ApplicationRecord validates :unpublished, boolean_presence: true validates :title, presence: true validates :token, presence: true, uniqueness: true - validates_uniqueness_of :uuid, if: -> { uuid.present? } + validates :uuid, uniqueness: {if: -> { uuid.present? }} @working_time_statistics = nil attr_reader :working_time_statistics @@ -57,10 +57,10 @@ class Exercise < ApplicationRecord end def finishers_percentage - if users.distinct.count != 0 - (100.0 / users.distinct.count * finishers.count).round(2) - else + if users.distinct.count.zero? 0 + else + (100.0 / users.distinct.count * finishers.count).round(2) end end @@ -73,11 +73,11 @@ class Exercise < ApplicationRecord def average_number_of_submissions user_count = internal_users.distinct.count + external_users.distinct.count - user_count == 0 ? 0 : submissions.count / user_count.to_f + user_count.zero? ? 0 : submissions.count / user_count.to_f end def time_maximum_score(user) - submissions.where(user: user).where("cause IN ('submit','assess')").where('score IS NOT NULL').order('score DESC, created_at ASC').first.created_at + submissions.where(user: user).where("cause IN ('submit','assess')").where.not(score: nil).order('score DESC, created_at ASC').first.created_at rescue StandardError Time.zone.at(0) end @@ -107,7 +107,7 @@ class Exercise < ApplicationRecord end def study_group_working_time_query(exercise_id, study_group_id, additional_filter) - ''" + " WITH working_time_between_submissions AS ( SELECT submissions.user_id, submissions.user_type, @@ -200,7 +200,7 @@ class Exercise < ApplicationRecord FROM working_times_with_index JOIN internal_users ON user_type = 'InternalUser' AND user_id = internal_users.id ORDER BY index, score ASC; - "'' + " end def get_working_times_for_study_group(study_group_id, user = nil) @@ -217,7 +217,8 @@ class Exercise < ApplicationRecord results = ActiveRecord::Base.transaction do self.class.connection.execute("SET LOCAL intervalstyle = 'postgres'") - self.class.connection.execute(study_group_working_time_query(id, study_group_id, additional_filter)).each do |tuple| + self.class.connection.execute(study_group_working_time_query(id, study_group_id, + additional_filter)).each do |tuple| bucket = if maximum_score > 0.0 && tuple['score'] <= maximum_score (tuple['score'] / maximum_score * max_bucket).round else @@ -230,11 +231,12 @@ class Exercise < ApplicationRecord user_progress[bucket][tuple['index']] = tuple['working_time_per_score'] additional_user_data[bucket][tuple['index']] = {start_time: tuple['start_time'], score: tuple['score']} - additional_user_data[max_bucket + 1][tuple['index']] = {id: tuple['user_id'], type: tuple['user_type'], name: tuple['name']} + additional_user_data[max_bucket + 1][tuple['index']] = + {id: tuple['user_id'], type: tuple['user_type'], name: tuple['name']} end end - if results.ntuples > 0 + if results.ntuples.positive? first_index = results[0]['index'] last_index = results[results.ntuples - 1]['index'] buckets = last_index - first_index @@ -247,9 +249,9 @@ class Exercise < ApplicationRecord end def get_quantiles(quantiles) - quantiles_str = '[' + quantiles.join(',') + ']' + quantiles_str = "[#{quantiles.join(',')}]" result = ActiveRecord::Base.transaction do - self.class.connection.execute(''" + self.class.connection.execute(" SET LOCAL intervalstyle = 'iso_8601'; WITH working_time AS ( @@ -356,14 +358,14 @@ class Exercise < ApplicationRecord exercise_id ) SELECT unnest(percentile_cont(array#{quantiles_str}) within GROUP (ORDER BY working_time)) FROM result - "'') + ") end - if result.count > 0 - begin - quantiles.each_with_index.map { |_q, i| ActiveSupport::Duration.parse(result[i]['unnest']).to_f } - end + if result.count.positive? + + quantiles.each_with_index.map {|_q, i| ActiveSupport::Duration.parse(result[i]['unnest']).to_f } + else - quantiles.map { |_q| 0 } + quantiles.map {|_q| 0 } end end @@ -380,11 +382,11 @@ class Exercise < ApplicationRecord def average_working_time ActiveRecord::Base.transaction do self.class.connection.execute("SET LOCAL intervalstyle = 'postgres'") - self.class.connection.execute(''" + self.class.connection.execute(" SELECT avg(working_time) as average_time FROM (#{user_working_time_query}) AS baz; - "'').first['average_time'] + ").first['average_time'] end end @@ -397,7 +399,7 @@ class Exercise < ApplicationRecord user_type = user.external_user? ? 'ExternalUser' : 'InternalUser' begin result = ActiveRecord::Base.transaction do - self.class.connection.execute(''" + self.class.connection.execute(" SET LOCAL intervalstyle = 'iso_8601'; WITH WORKING_TIME AS (SELECT user_id, @@ -447,7 +449,7 @@ class Exercise < ApplicationRecord SELECT e.external_id AS external_user_id, f.user_id, exercise_id, MAX(max_score) AS max_score, sum(working_time_new) AS working_time FROM FILTERED_TIMES_UNTIL_MAX f, EXTERNAL_USERS e WHERE f.user_id = e.id GROUP BY e.external_id, f.user_id, exercise_id - "'') + ") end ActiveSupport::Duration.parse(result.first['working_time']).to_f rescue StandardError @@ -458,8 +460,8 @@ class Exercise < ApplicationRecord def duplicate(attributes = {}) exercise = dup exercise.attributes = attributes - exercise_tags.each { |et| exercise.exercise_tags << et.dup } - files.each { |file| exercise.files << file.dup } + exercise_tags.each {|et| exercise.exercise_tags << et.dup } + files.each {|file| exercise.files << file.dup } exercise end @@ -490,7 +492,7 @@ class Exercise < ApplicationRecord self.attributes = { title: task_node.xpath('p:meta-data/p:title/text()')[0].content, description: description, - instructions: description + instructions: description, } task_node.xpath('p:files/p:file').all? do |file| file_name_split = file.xpath('@filename').first.value.split('.') @@ -498,16 +500,16 @@ class Exercise < ApplicationRecord role = determine_file_role_from_proforma_file(task_node, file) feedback_message_nodes = task_node.xpath('p:tests/p:test/p:test-configuration/c:feedback-message/text()') files.build({ - name: file_name_split.first, + name: file_name_split.first, content: file.xpath('text()').first.content, read_only: false, hidden: file_class == 'internal', role: role, feedback_message: role == 'teacher_defined_test' ? feedback_message_nodes.first.content : nil, - file_type: FileType.where( + file_type: FileType.find_by( file_extension: ".#{file_name_split.second}" - ).take - }) + ), + }) end self.execution_environment_id = 1 end @@ -521,7 +523,7 @@ class Exercise < ApplicationRecord if user # FIXME: where(user: user) will not work here! begin - submissions.where(user: user).where("cause IN ('submit','assess')").where('score IS NOT NULL').order('score DESC').first.score || 0 + submissions.where(user: user).where("cause IN ('submit','assess')").where.not(score: nil).order('score DESC').first.score || 0 rescue StandardError 0 end @@ -539,7 +541,8 @@ class Exercise < ApplicationRecord end def finishers - ExternalUser.joins(:submissions).where(submissions: {exercise_id: id, score: maximum_score, cause: %w[submit assess remoteSubmit remoteAssess]}).distinct + ExternalUser.joins(:submissions).where(submissions: {exercise_id: id, score: maximum_score, +cause: %w[submit assess remoteSubmit remoteAssess]}).distinct end def set_default_values @@ -552,18 +555,25 @@ class Exercise < ApplicationRecord end def valid_main_file? - errors.add(:files, I18n.t('activerecord.errors.models.exercise.at_most_one_main_file')) if files.main_files.count > 1 + if files.main_files.count > 1 + errors.add(:files, + I18n.t('activerecord.errors.models.exercise.at_most_one_main_file')) + end end private :valid_main_file? def valid_submission_deadlines? return unless submission_deadline.present? || late_submission_deadline.present? - errors.add(:late_submission_deadline, I18n.t('activerecord.errors.models.exercise.late_submission_deadline_not_alone')) if late_submission_deadline.present? && submission_deadline.blank? + if late_submission_deadline.present? && submission_deadline.blank? + errors.add(:late_submission_deadline, + I18n.t('activerecord.errors.models.exercise.late_submission_deadline_not_alone')) + end if submission_deadline.present? && late_submission_deadline.present? && late_submission_deadline < submission_deadline - errors.add(:late_submission_deadline, I18n.t('activerecord.errors.models.exercise.late_submission_deadline_not_before_submission_deadline')) + errors.add(:late_submission_deadline, + I18n.t('activerecord.errors.models.exercise.late_submission_deadline_not_before_submission_deadline')) end end private :valid_submission_deadlines? diff --git a/app/models/exercise_collection.rb b/app/models/exercise_collection.rb index 98cc5a63..bc1e4fd9 100644 --- a/app/models/exercise_collection.rb +++ b/app/models/exercise_collection.rb @@ -1,15 +1,19 @@ +# frozen_string_literal: true + class ExerciseCollection < ApplicationRecord include TimeHelper has_many :exercise_collection_items, dependent: :delete_all - alias_method :items, :exercise_collection_items + alias items exercise_collection_items has_many :exercises, through: :exercise_collection_items, inverse_of: :exercise_collections belongs_to :user, polymorphic: true def collection_statistics statistics = {} exercise_collection_items.each do |item| - statistics[item.position] = {exercise_id: item.exercise.id, exercise_title: item.exercise.title, working_time: time_to_f(item.exercise.average_working_time)} + statistics[item.position] = + {exercise_id: item.exercise.id, exercise_title: item.exercise.title, +working_time: time_to_f(item.exercise.average_working_time)} end statistics end @@ -18,8 +22,8 @@ class ExerciseCollection < ApplicationRecord if exercises.empty? 0 else - values = collection_statistics.values.reject { |o| o[:working_time].nil?} - sum = values.reduce(0) {|sum, item| sum + item[:working_time]} + values = collection_statistics.values.reject {|o| o[:working_time].nil? } + sum = values.reduce(0) {|sum, item| sum + item[:working_time] } sum / values.size end end @@ -27,5 +31,4 @@ class ExerciseCollection < ApplicationRecord def to_s "#{I18n.t('activerecord.models.exercise_collection.one')}: #{name} (#{id})" end - end diff --git a/app/models/exercise_collection_item.rb b/app/models/exercise_collection_item.rb index 6147c3a0..e4112bc7 100644 --- a/app/models/exercise_collection_item.rb +++ b/app/models/exercise_collection_item.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExerciseCollectionItem < ApplicationRecord belongs_to :exercise_collection belongs_to :exercise diff --git a/app/models/exercise_tag.rb b/app/models/exercise_tag.rb index 9ead6f13..4edff966 100644 --- a/app/models/exercise_tag.rb +++ b/app/models/exercise_tag.rb @@ -1,13 +1,14 @@ -class ExerciseTag < ApplicationRecord +# frozen_string_literal: true +class ExerciseTag < ApplicationRecord belongs_to :tag belongs_to :exercise before_save :destroy_if_empty_exercise_or_tag private - def destroy_if_empty_exercise_or_tag - destroy if exercise_id.blank? || tag_id.blank? - end -end \ No newline at end of file + def destroy_if_empty_exercise_or_tag + destroy if exercise_id.blank? || tag_id.blank? + end +end diff --git a/app/models/exercise_tip.rb b/app/models/exercise_tip.rb index 20be149f..9d99abaa 100644 --- a/app/models/exercise_tip.rb +++ b/app/models/exercise_tip.rb @@ -13,6 +13,12 @@ class ExerciseTip < ApplicationRecord def tip_chain? # Ensure each referenced parent exercise tip is set for this exercise - errors.add :parent_exercise_tip, I18n.t('activerecord.errors.messages.together', attribute: I18n.t('activerecord.attributes.exercise_tip.tip')) unless ExerciseTip.exists?(exercise: exercise, id: parent_exercise_tip) + unless ExerciseTip.exists?( +exercise: exercise, id: parent_exercise_tip +) + errors.add :parent_exercise_tip, + I18n.t('activerecord.errors.messages.together', + attribute: I18n.t('activerecord.attributes.exercise_tip.tip')) + end end end diff --git a/app/models/external_user.rb b/app/models/external_user.rb index e19a269e..9081f850 100644 --- a/app/models/external_user.rb +++ b/app/models/external_user.rb @@ -1,13 +1,10 @@ -class ExternalUser < User +# frozen_string_literal: true +class ExternalUser < User validates :consumer_id, presence: true validates :external_id, presence: true def displayname - if name.blank? - "User " + id.to_s - else - name - end + name.presence || "User #{id}" end end diff --git a/app/models/file_template.rb b/app/models/file_template.rb index 2eba68be..794638b1 100644 --- a/app/models/file_template.rb +++ b/app/models/file_template.rb @@ -1,10 +1,9 @@ +# frozen_string_literal: true + class FileTemplate < ApplicationRecord - belongs_to :file_type - def to_s name end - end diff --git a/app/models/file_type.rb b/app/models/file_type.rb index cf128a62..a1d5a6e9 100644 --- a/app/models/file_type.rb +++ b/app/models/file_type.rb @@ -1,12 +1,14 @@ -require File.expand_path('../../../lib/active_model/validations/boolean_presence_validator', __FILE__) +# frozen_string_literal: true + +require File.expand_path('../../lib/active_model/validations/boolean_presence_validator', __dir__) class FileType < ApplicationRecord include Creation include DefaultValues - AUDIO_FILE_EXTENSIONS = %w(.aac .flac .m4a .mp3 .ogg .wav .wma) - IMAGE_FILE_EXTENSIONS = %w(.bmp .gif .jpeg .jpg .png) - VIDEO_FILE_EXTENSIONS = %w(.avi .flv .mkv .mp4 .m4v .ogv .webm) + AUDIO_FILE_EXTENSIONS = %w[.aac .flac .m4a .mp3 .ogg .wav .wma].freeze + IMAGE_FILE_EXTENSIONS = %w[.bmp .gif .jpeg .jpg .png].freeze + VIDEO_FILE_EXTENSIONS = %w[.avi .flv .mkv .mp4 .m4v .ogv .webm].freeze after_initialize :set_default_values @@ -21,7 +23,7 @@ class FileType < ApplicationRecord validates :name, presence: true validates :renderable, boolean_presence: true - [:audio, :image, :video].each do |type| + %i[audio image video].each do |type| define_method("#{type}?") do self.class.const_get("#{type.upcase}_FILE_EXTENSIONS").include?(file_extension) end diff --git a/app/models/internal_user.rb b/app/models/internal_user.rb index 9cef2cb4..bc848226 100644 --- a/app/models/internal_user.rb +++ b/app/models/internal_user.rb @@ -1,5 +1,6 @@ -class InternalUser < User +# frozen_string_literal: true +class InternalUser < User authenticates_with_sorcery! validates :email, presence: true, uniqueness: true @@ -22,5 +23,4 @@ class InternalUser < User def displayname name end - end diff --git a/app/models/intervention.rb b/app/models/intervention.rb index 43750626..39848f09 100644 --- a/app/models/intervention.rb +++ b/app/models/intervention.rb @@ -1,5 +1,6 @@ -class Intervention < ApplicationRecord +# frozen_string_literal: true +class Intervention < ApplicationRecord has_many :user_exercise_interventions has_many :users, through: :user_exercise_interventions, source_type: 'ExternalUser' @@ -8,9 +9,8 @@ class Intervention < ApplicationRecord end def self.createDefaultInterventions - %w(BreakIntervention QuestionIntervention).each do |name| + %w[BreakIntervention QuestionIntervention].each do |name| Intervention.find_or_create_by(name: name) end end - -end \ No newline at end of file +end diff --git a/app/models/lti_parameter.rb b/app/models/lti_parameter.rb index ab92165f..fe39dc75 100644 --- a/app/models/lti_parameter.rb +++ b/app/models/lti_parameter.rb @@ -1,9 +1,11 @@ -class LtiParameter < ApplicationRecord - belongs_to :consumer, foreign_key: "consumers_id" - belongs_to :exercise, foreign_key: "exercises_id" - belongs_to :external_user, foreign_key: "external_users_id" +# frozen_string_literal: true - scope :lis_outcome_service_url?, -> { +class LtiParameter < ApplicationRecord + belongs_to :consumer, foreign_key: 'consumers_id' + belongs_to :exercise, foreign_key: 'exercises_id' + belongs_to :external_user, foreign_key: 'external_users_id' + + scope :lis_outcome_service_url?, lambda { where("lti_parameters.lti_parameters ? 'lis_outcome_service_url'") } -end \ No newline at end of file +end diff --git a/app/models/proxy_exercise.rb b/app/models/proxy_exercise.rb index 96c143b7..91835f96 100644 --- a/app/models/proxy_exercise.rb +++ b/app/models/proxy_exercise.rb @@ -1,236 +1,245 @@ +# frozen_string_literal: true + class ProxyExercise < ApplicationRecord - include Creation - include DefaultValues + include Creation + include DefaultValues - after_initialize :generate_token - after_initialize :set_reason - after_initialize :set_default_values + after_initialize :generate_token + after_initialize :set_reason + after_initialize :set_default_values - has_and_belongs_to_many :exercises - has_many :user_proxy_exercise_exercises + has_and_belongs_to_many :exercises + has_many :user_proxy_exercise_exercises - validates :public, boolean_presence: true + validates :public, boolean_presence: true - def count_files - exercises.count - end + def count_files + exercises.count + end - def set_reason - @reason = {} - end + def set_reason + @reason = {} + end - def generate_token - self.token ||= SecureRandom.hex(4) - end - private :generate_token + def generate_token + self.token ||= SecureRandom.hex(4) + end + private :generate_token - def set_default_values - set_default_values_if_present(public: false) - end - private :set_default_values + def set_default_values + set_default_values_if_present(public: false) + end + private :set_default_values - def duplicate(attributes = {}) - proxy_exercise = dup - proxy_exercise.attributes = attributes - proxy_exercise - end + def duplicate(attributes = {}) + proxy_exercise = dup + proxy_exercise.attributes = attributes + proxy_exercise + end - def to_s - title - end + def to_s + title + end - def get_matching_exercise(user) - assigned_user_proxy_exercise = user_proxy_exercise_exercises.where(user: user).first - recommended_exercise = - if (assigned_user_proxy_exercise) - Rails.logger.debug("retrieved assigned exercise for user #{user.id}: Exercise #{assigned_user_proxy_exercise.exercise}" ) - assigned_user_proxy_exercise.exercise - else - Rails.logger.debug("find new matching exercise for user #{user.id}" ) - matching_exercise = - begin - find_matching_exercise(user) - rescue => e #fallback - Rails.logger.error("finding matching exercise failed. Fall back to random exercise! Error: #{$!}" ) - @reason[:reason] = "fallback because of error" - @reason[:error] = "#{$!}:\n\t#{e.backtrace.join("\n\t")}" - exercises.where("expected_difficulty > 1").shuffle.first # difficulty should be > 1 to prevent dummy exercise from being chosen. - end - user.user_proxy_exercise_exercises << UserProxyExerciseExercise.create(user: user, exercise: matching_exercise, proxy_exercise: self, reason: @reason.to_json) - matching_exercise + def get_matching_exercise(user) + assigned_user_proxy_exercise = user_proxy_exercise_exercises.where(user: user).first + if assigned_user_proxy_exercise + Rails.logger.debug("retrieved assigned exercise for user #{user.id}: Exercise #{assigned_user_proxy_exercise.exercise}") + assigned_user_proxy_exercise.exercise + else + Rails.logger.debug("find new matching exercise for user #{user.id}") + matching_exercise = + begin + find_matching_exercise(user) + rescue StandardError => e # fallback + Rails.logger.error("finding matching exercise failed. Fall back to random exercise! Error: #{$ERROR_INFO}") + @reason[:reason] = 'fallback because of error' + @reason[:error] = "#{$ERROR_INFO}:\n\t#{e.backtrace.join("\n\t")}" + exercises.where('expected_difficulty > 1').sample # difficulty should be > 1 to prevent dummy exercise from being chosen. end - recommended_exercise + user.user_proxy_exercise_exercises << UserProxyExerciseExercise.create(user: user, +exercise: matching_exercise, proxy_exercise: self, reason: @reason.to_json) + matching_exercise end + end - def find_matching_exercise(user) - exercises_user_has_accessed = user.submissions.where("cause IN ('submit','assess')").map{|s| s.exercise}.uniq.compact - tags_user_has_seen = exercises_user_has_accessed.map{|ex| ex.tags}.uniq.flatten - Rails.logger.debug("exercises_user_has_accessed #{exercises_user_has_accessed.map{|e|e.id}.join(",")}") + def find_matching_exercise(user) + exercises_user_has_accessed = user.submissions.where("cause IN ('submit','assess')").map(&:exercise).uniq.compact + tags_user_has_seen = exercises_user_has_accessed.map(&:tags).uniq.flatten + Rails.logger.debug("exercises_user_has_accessed #{exercises_user_has_accessed.map(&:id).join(',')}") - # find exercises - potential_recommended_exercises = [] - exercises.where("expected_difficulty >= 1").each do |ex| - ## find exercises which have only tags the user has already seen - if (ex.tags - tags_user_has_seen).empty? - potential_recommended_exercises << ex - end - end - Rails.logger.debug("potential_recommended_exercises: #{potential_recommended_exercises.map{|e|e.id}}") - # if all exercises contain tags which the user has never seen, recommend easiest exercise - if potential_recommended_exercises.empty? - Rails.logger.debug("matched easiest exercise in pool") - @reason[:reason] = "easiest exercise in pool. empty potential exercises" - select_easiest_exercise(exercises) - else - select_best_matching_exercise(user, exercises_user_has_accessed, potential_recommended_exercises) - end - end - private :find_matching_exercise - - def select_best_matching_exercise(user, exercises_user_has_accessed, potential_recommended_exercises) - topic_knowledge_user_and_max = get_user_knowledge_and_max_knowledge(user, exercises_user_has_accessed) - Rails.logger.debug("topic_knowledge_user_and_max: #{topic_knowledge_user_and_max}") - Rails.logger.debug("potential_recommended_exercises: #{potential_recommended_exercises.size}: #{potential_recommended_exercises.map{|p| p.id}}") - topic_knowledge_user = topic_knowledge_user_and_max[:user_topic_knowledge] - topic_knowledge_max = topic_knowledge_user_and_max[:max_topic_knowledge] - current_users_knowledge_lack = {} - topic_knowledge_max.keys.each do |tag| - current_users_knowledge_lack[tag] = topic_knowledge_user[tag] / topic_knowledge_max[tag] + # find exercises + potential_recommended_exercises = [] + exercises.where('expected_difficulty >= 1').find_each do |ex| + ## find exercises which have only tags the user has already seen + if (ex.tags - tags_user_has_seen).empty? + potential_recommended_exercises << ex end + end + Rails.logger.debug("potential_recommended_exercises: #{potential_recommended_exercises.map(&:id)}") + # if all exercises contain tags which the user has never seen, recommend easiest exercise + if potential_recommended_exercises.empty? + Rails.logger.debug('matched easiest exercise in pool') + @reason[:reason] = 'easiest exercise in pool. empty potential exercises' + select_easiest_exercise(exercises) + else + select_best_matching_exercise(user, exercises_user_has_accessed, potential_recommended_exercises) + end + end + private :find_matching_exercise - relative_knowledge_improvement = {} - potential_recommended_exercises.each do |potex| - tags = potex.tags - relative_knowledge_improvement[potex] = 0.0 - Rails.logger.debug("review potential exercise #{potex.id}") - tags.each do |tag| - tag_ratio = potex.exercise_tags.where(tag: tag).first.factor.to_f / potex.exercise_tags.inject(0){|sum, et| sum += et.factor }.to_f - max_topic_knowledge_ratio = potex.expected_difficulty * tag_ratio - old_relative_loss_tag = topic_knowledge_user[tag] / topic_knowledge_max[tag] - new_relative_loss_tag = topic_knowledge_user[tag] / (topic_knowledge_max[tag] + max_topic_knowledge_ratio) - Rails.logger.debug("tag #{tag} old_relative_loss_tag #{old_relative_loss_tag}, new_relative_loss_tag #{new_relative_loss_tag}, tag_ratio #{tag_ratio}") - relative_knowledge_improvement[potex] += old_relative_loss_tag - new_relative_loss_tag - end + def select_best_matching_exercise(user, exercises_user_has_accessed, potential_recommended_exercises) + topic_knowledge_user_and_max = get_user_knowledge_and_max_knowledge(user, exercises_user_has_accessed) + Rails.logger.debug("topic_knowledge_user_and_max: #{topic_knowledge_user_and_max}") + Rails.logger.debug("potential_recommended_exercises: #{potential_recommended_exercises.size}: #{potential_recommended_exercises.map(&:id)}") + topic_knowledge_user = topic_knowledge_user_and_max[:user_topic_knowledge] + topic_knowledge_max = topic_knowledge_user_and_max[:max_topic_knowledge] + current_users_knowledge_lack = {} + topic_knowledge_max.each_key do |tag| + current_users_knowledge_lack[tag] = topic_knowledge_user[tag] / topic_knowledge_max[tag] + end + + relative_knowledge_improvement = {} + potential_recommended_exercises.each do |potex| + tags = potex.tags + relative_knowledge_improvement[potex] = 0.0 + Rails.logger.debug("review potential exercise #{potex.id}") + tags.each do |tag| + tag_ratio = potex.exercise_tags.where(tag: tag).first.factor.to_f / potex.exercise_tags.inject(0) do |sum, et| + sum += et.factor + end + max_topic_knowledge_ratio = potex.expected_difficulty * tag_ratio + old_relative_loss_tag = topic_knowledge_user[tag] / topic_knowledge_max[tag] + new_relative_loss_tag = topic_knowledge_user[tag] / (topic_knowledge_max[tag] + max_topic_knowledge_ratio) + Rails.logger.debug("tag #{tag} old_relative_loss_tag #{old_relative_loss_tag}, new_relative_loss_tag #{new_relative_loss_tag}, tag_ratio #{tag_ratio}") + relative_knowledge_improvement[potex] += old_relative_loss_tag - new_relative_loss_tag end - - highest_difficulty_user_has_accessed = exercises_user_has_accessed.map{|e| e.expected_difficulty}.sort.last || 0 - best_matching_exercise = find_best_exercise(relative_knowledge_improvement, highest_difficulty_user_has_accessed) - @reason[:reason] = "best matching exercise" - @reason[:highest_difficulty_user_has_accessed] = highest_difficulty_user_has_accessed - @reason[:current_users_knowledge_lack] = current_users_knowledge_lack - @reason[:relative_knowledge_improvement] = relative_knowledge_improvement - - Rails.logger.debug("current users knowledge loss: " + current_users_knowledge_lack.map{|k,v| "#{k} => #{v}"}.to_s) - Rails.logger.debug("relative improvements #{relative_knowledge_improvement.map{|k,v| k.id.to_s + ':' + v.to_s}}") - best_matching_exercise end - private :select_best_matching_exercise - def find_best_exercise(relative_knowledge_improvement, highest_difficulty_user_has_accessed) - Rails.logger.debug("select most appropiate exercise for user. his highest difficulty was #{highest_difficulty_user_has_accessed}") - sorted_exercises = relative_knowledge_improvement.sort_by{|k,v| v}.reverse + highest_difficulty_user_has_accessed = exercises_user_has_accessed.map(&:expected_difficulty).max || 0 + best_matching_exercise = find_best_exercise(relative_knowledge_improvement, highest_difficulty_user_has_accessed) + @reason[:reason] = 'best matching exercise' + @reason[:highest_difficulty_user_has_accessed] = highest_difficulty_user_has_accessed + @reason[:current_users_knowledge_lack] = current_users_knowledge_lack + @reason[:relative_knowledge_improvement] = relative_knowledge_improvement - sorted_exercises.each do |ex,diff| - Rails.logger.debug("review exercise #{ex.id} diff: #{ex.expected_difficulty}") - if (ex.expected_difficulty - highest_difficulty_user_has_accessed) <= 1 - Rails.logger.debug("matched exercise #{ex.id}") - return ex - else - Rails.logger.debug("exercise #{ex.id} is too difficult") - end + Rails.logger.debug('current users knowledge loss: ' + current_users_knowledge_lack.map do |k, v| + "#{k} => #{v}" + end.to_s) + Rails.logger.debug("relative improvements #{relative_knowledge_improvement.map {|k, v| "#{k.id}:#{v}" }}") + best_matching_exercise + end + private :select_best_matching_exercise + + def find_best_exercise(relative_knowledge_improvement, highest_difficulty_user_has_accessed) + Rails.logger.debug("select most appropiate exercise for user. his highest difficulty was #{highest_difficulty_user_has_accessed}") + sorted_exercises = relative_knowledge_improvement.sort_by {|_k, v| v }.reverse + + sorted_exercises.each do |ex, _diff| + Rails.logger.debug("review exercise #{ex.id} diff: #{ex.expected_difficulty}") + if (ex.expected_difficulty - highest_difficulty_user_has_accessed) <= 1 + Rails.logger.debug("matched exercise #{ex.id}") + return ex + else + Rails.logger.debug("exercise #{ex.id} is too difficult") end - easiest_exercise = sorted_exercises.min_by{|k,v| v}.first - Rails.logger.debug("no match, select easiest exercise as fallback #{easiest_exercise.id}") - easiest_exercise end - private :find_best_exercise + easiest_exercise = sorted_exercises.min_by {|_k, v| v }.first + Rails.logger.debug("no match, select easiest exercise as fallback #{easiest_exercise.id}") + easiest_exercise + end + private :find_best_exercise - # [score][quantile] - def scoring_matrix - [ - [0 ,0 ,0 ,0 ,0 ], - [0.2,0.2,0.2,0.2,0.1], - [0.5,0.5,0.4,0.4,0.3], - [0.6,0.6,0.5,0.5,0.4], - [1 ,1 ,0.9,0.8,0.7], - ] + # [score][quantile] + def scoring_matrix + [ + [0, 0, 0, 0, 0], + [0.2, 0.2, 0.2, 0.2, 0.1], + [0.5, 0.5, 0.4, 0.4, 0.3], + [0.6, 0.6, 0.5, 0.5, 0.4], + [1, 1, 0.9, 0.8, 0.7], + ] + end + + def scoring_matrix_quantiles + [0.2, 0.4, 0.6, 0.8] + end + private :scoring_matrix_quantiles + + def score(user, ex) + max_score = ex.maximum_score.to_f + if max_score <= 0 + Rails.logger.debug("scoring user #{user.id} for exercise #{ex.id}: score: 0") + return 0.0 end - - def scoring_matrix_quantiles - [0.2,0.4,0.6,0.8] + points_ratio = ex.maximum_score(user) / max_score + if points_ratio == 0.0 + Rails.logger.debug("scoring user #{user.id} for exercise #{ex.id}: points_ratio=#{points_ratio} score: 0") + return 0.0 + elsif points_ratio > 1.0 + points_ratio = 1.0 # The score of the exercise was adjusted and is now lower than it was end - private :scoring_matrix_quantiles - - def score(user, ex) - max_score = ex.maximum_score.to_f - if max_score <= 0 - Rails.logger.debug("scoring user #{user.id} for exercise #{ex.id}: score: 0" ) - return 0.0 + points_ratio_index = ((scoring_matrix.size - 1) * points_ratio).to_i + working_time_user = ex.accumulated_working_time_for_only(user) + quantiles_working_time = ex.get_quantiles(scoring_matrix_quantiles) + quantile_index = quantiles_working_time.size + quantiles_working_time.each_with_index do |quantile_time, i| + if working_time_user <= quantile_time + quantile_index = i + break end - points_ratio = ex.maximum_score(user) / max_score - if points_ratio == 0.0 - Rails.logger.debug("scoring user #{user.id} for exercise #{ex.id}: points_ratio=#{points_ratio} score: 0" ) - return 0.0 - elsif points_ratio > 1.0 - points_ratio = 1.0 # The score of the exercise was adjusted and is now lower than it was - end - points_ratio_index = ((scoring_matrix.size - 1) * points_ratio).to_i - working_time_user = ex.accumulated_working_time_for_only(user) - quantiles_working_time = ex.get_quantiles(scoring_matrix_quantiles) - quantile_index = quantiles_working_time.size - quantiles_working_time.each_with_index do |quantile_time, i| - if working_time_user <= quantile_time - quantile_index = i - break - end - end - Rails.logger.debug( - "scoring user #{user.id} exercise #{ex.id}: worktime #{working_time_user}, points: #{points_ratio}" \ - "(index #{points_ratio_index}) quantiles #{quantiles_working_time} placed into quantile index #{quantile_index} " \ - "score: #{scoring_matrix[points_ratio_index][quantile_index]}") - scoring_matrix[points_ratio_index][quantile_index] end - private :score + Rails.logger.debug( + "scoring user #{user.id} exercise #{ex.id}: worktime #{working_time_user}, points: #{points_ratio}" \ + "(index #{points_ratio_index}) quantiles #{quantiles_working_time} placed into quantile index #{quantile_index} " \ + "score: #{scoring_matrix[points_ratio_index][quantile_index]}" + ) + scoring_matrix[points_ratio_index][quantile_index] + end + private :score - def get_user_knowledge_and_max_knowledge(user, exercises) - # initialize knowledge for each tag with 0 - all_used_tags_with_count = {} - exercises.each do |ex| - ex.tags.each do |t| - all_used_tags_with_count[t] ||= 0 - all_used_tags_with_count[t] += 1 - end + def get_user_knowledge_and_max_knowledge(user, exercises) + # initialize knowledge for each tag with 0 + all_used_tags_with_count = {} + exercises.each do |ex| + ex.tags.each do |t| + all_used_tags_with_count[t] ||= 0 + all_used_tags_with_count[t] += 1 end - tags_counter = all_used_tags_with_count.keys.map{|tag| [tag,0]}.to_h - topic_knowledge_loss_user = all_used_tags_with_count.keys.map{|t| [t, 0]}.to_h - topic_knowledge_max = all_used_tags_with_count.keys.map{|t| [t, 0]}.to_h - exercises_sorted = exercises.sort_by { |ex| ex.time_maximum_score(user)} - exercises_sorted.each do |ex| - Rails.logger.debug("exercise: #{ex.id}: #{ex}") - user_score_factor = score(user, ex) - ex.tags.each do |t| - tags_counter[t] += 1 - tag_diminishing_return_factor = tag_diminishing_return_function(tags_counter[t], all_used_tags_with_count[t]) - tag_ratio = ex.exercise_tags.where(tag: t).first.factor.to_f / ex.exercise_tags.inject(0){|sum, et| sum + et.factor }.to_f - Rails.logger.debug("tag: #{t}, factor: #{ex.exercise_tags.where(tag: t).first.factor}, sumall: #{ex.exercise_tags.inject(0){|sum, et| sum + et.factor }}") - Rails.logger.debug("tag #{t}, count #{tags_counter[t]}, max: #{all_used_tags_with_count[t]}, factor: #{tag_diminishing_return_factor}") - Rails.logger.debug("tag_ratio #{tag_ratio}") - topic_knowledge_ratio = ex.expected_difficulty * tag_ratio - Rails.logger.debug("topic_knowledge_ratio #{topic_knowledge_ratio}") - topic_knowledge_loss_user[t] += (1 - user_score_factor) * topic_knowledge_ratio * tag_diminishing_return_factor - topic_knowledge_max[t] += topic_knowledge_ratio * tag_diminishing_return_factor - end + end + tags_counter = all_used_tags_with_count.keys.index_with {|_tag| 0 } + topic_knowledge_loss_user = all_used_tags_with_count.keys.index_with {|_t| 0 } + topic_knowledge_max = all_used_tags_with_count.keys.index_with {|_t| 0 } + exercises_sorted = exercises.sort_by {|ex| ex.time_maximum_score(user) } + exercises_sorted.each do |ex| + Rails.logger.debug("exercise: #{ex.id}: #{ex}") + user_score_factor = score(user, ex) + ex.tags.each do |t| + tags_counter[t] += 1 + tag_diminishing_return_factor = tag_diminishing_return_function(tags_counter[t], all_used_tags_with_count[t]) + tag_ratio = ex.exercise_tags.where(tag: t).first.factor.to_f / ex.exercise_tags.inject(0) do |sum, et| + sum + et.factor + end + Rails.logger.debug("tag: #{t}, factor: #{ex.exercise_tags.where(tag: t).first.factor}, sumall: #{ex.exercise_tags.inject(0) do |sum, et| + sum + et.factor + end }") + Rails.logger.debug("tag #{t}, count #{tags_counter[t]}, max: #{all_used_tags_with_count[t]}, factor: #{tag_diminishing_return_factor}") + Rails.logger.debug("tag_ratio #{tag_ratio}") + topic_knowledge_ratio = ex.expected_difficulty * tag_ratio + Rails.logger.debug("topic_knowledge_ratio #{topic_knowledge_ratio}") + topic_knowledge_loss_user[t] += (1 - user_score_factor) * topic_knowledge_ratio * tag_diminishing_return_factor + topic_knowledge_max[t] += topic_knowledge_ratio * tag_diminishing_return_factor end - {user_topic_knowledge: topic_knowledge_loss_user, max_topic_knowledge: topic_knowledge_max} end + {user_topic_knowledge: topic_knowledge_loss_user, max_topic_knowledge: topic_knowledge_max} + end - def tag_diminishing_return_function(count_tag, total_count_tag) - total_count_tag += 1 # bonus exercise comes on top - 1 / (1 + (Math::E**(-3 / (0.5 * total_count_tag) * (count_tag - 0.5 * total_count_tag)))) - end - - def select_easiest_exercise(exercises) - exercises.order(:expected_difficulty).first - end + def tag_diminishing_return_function(count_tag, total_count_tag) + total_count_tag += 1 # bonus exercise comes on top + 1 / (1 + (Math::E**(-3 / (0.5 * total_count_tag) * (count_tag - 0.5 * total_count_tag)))) + end + def select_easiest_exercise(exercises) + exercises.order(:expected_difficulty).first + end end diff --git a/app/models/request_for_comment.rb b/app/models/request_for_comment.rb index 6dfb1ae4..e671492e 100644 --- a/app/models/request_for_comment.rb +++ b/app/models/request_for_comment.rb @@ -18,7 +18,7 @@ class RequestForComment < ApplicationRecord scope :unsolved, -> { where(solved: [false, nil]) } scope :in_range, ->(from, to) { where(created_at: from..to) } - scope :with_comments, -> { select { |rfc| rfc.comments.any? } } + scope :with_comments, -> { select {|rfc| rfc.comments.any? } } # after_save :trigger_rfc_action_cable @@ -44,7 +44,7 @@ class RequestForComment < ApplicationRecord end def comments_count - submission.files.map { |file| file.comments.size }.sum + submission.files.sum {|file| file.comments.size } end def commenters diff --git a/app/models/search.rb b/app/models/search.rb index bbb59e5b..06f34ba7 100644 --- a/app/models/search.rb +++ b/app/models/search.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + class Search < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :exercise -end \ No newline at end of file +end diff --git a/app/models/structured_error.rb b/app/models/structured_error.rb index 4d48b97c..46b5cb6e 100644 --- a/app/models/structured_error.rb +++ b/app/models/structured_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StructuredError < ApplicationRecord belongs_to :error_template belongs_to :submission @@ -5,8 +7,8 @@ class StructuredError < ApplicationRecord has_many :structured_error_attributes def self.create_from_template(template, message_buffer, submission) - instance = self.create(error_template: template, submission: submission) - template.error_template_attributes.each do | attribute | + instance = create(error_template: template, submission: submission) + template.error_template_attributes.each do |attribute| StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer) end instance @@ -14,7 +16,7 @@ class StructuredError < ApplicationRecord def hint content = error_template.hint - structured_error_attributes.each do | attribute | + structured_error_attributes.each do |attribute| content.sub! "{{#{attribute.error_template_attribute.key}}}", attribute.value if attribute.match end content diff --git a/app/models/structured_error_attribute.rb b/app/models/structured_error_attribute.rb index f5f7615b..7bf97a66 100644 --- a/app/models/structured_error_attribute.rb +++ b/app/models/structured_error_attribute.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class StructuredErrorAttribute < ApplicationRecord belongs_to :structured_error belongs_to :error_template_attribute @@ -5,11 +7,10 @@ class StructuredErrorAttribute < ApplicationRecord def self.create_from_template(attribute, structured_error, message_buffer) value = nil result = message_buffer.match(attribute.regex) - if result != nil - if result.captures.size > 0 - value = result.captures[0] - end + if !result.nil? && result.captures.size.positive? + value = result.captures[0] end - self.create(structured_error: structured_error, error_template_attribute: attribute, value: value, match: result != nil) + create(structured_error: structured_error, error_template_attribute: attribute, value: value, +match: !result.nil?) end end diff --git a/app/models/study_group_membership.rb b/app/models/study_group_membership.rb index 1f7aad91..efb9683f 100644 --- a/app/models/study_group_membership.rb +++ b/app/models/study_group_membership.rb @@ -4,5 +4,5 @@ class StudyGroupMembership < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :study_group - validates_uniqueness_of :user_id, :scope => [:user_type, :study_group_id] + validates :user_id, uniqueness: {scope: %i[user_type study_group_id]} end diff --git a/app/models/submission.rb b/app/models/submission.rb index 46c89ad1..accee1e8 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -1,9 +1,12 @@ +# frozen_string_literal: true + class Submission < ApplicationRecord include Context include Creation include ActionCableHelper - CAUSES = %w(assess download file render run save submit test autosave requestComments remoteAssess remoteSubmit) + CAUSES = %w[assess download file render run save submit test autosave requestComments remoteAssess + remoteSubmit].freeze FILENAME_URL_PLACEHOLDER = '{filename}' MAX_COMMENTS_ON_RECOMMENDED_RFC = 5 OLDEST_RFC_TO_SHOW = 6.months @@ -15,17 +18,27 @@ class Submission < ApplicationRecord has_many :structured_errors has_many :comments, through: :files - belongs_to :external_users, -> { where(submissions: {user_type: 'ExternalUser'}).includes(:submissions) }, foreign_key: :user_id, class_name: 'ExternalUser', optional: true - belongs_to :internal_users, -> { where(submissions: {user_type: 'InternalUser'}).includes(:submissions) }, foreign_key: :user_id, class_name: 'InternalUser', optional: true + belongs_to :external_users, lambda { + where(submissions: {user_type: 'ExternalUser'}).includes(:submissions) + }, foreign_key: :user_id, class_name: 'ExternalUser', optional: true + belongs_to :internal_users, lambda { + where(submissions: {user_type: 'InternalUser'}).includes(:submissions) + }, foreign_key: :user_id, class_name: 'InternalUser', optional: true delegate :execution_environment, to: :exercise scope :final, -> { where(cause: %w[submit remoteSubmit]) } scope :intermediate, -> { where.not(cause: 'submit') } - scope :before_deadline, -> { joins(:exercise).where('submissions.updated_at <= exercises.submission_deadline OR exercises.submission_deadline IS NULL') } - scope :within_grace_period, -> { joins(:exercise).where('(submissions.updated_at > exercises.submission_deadline) AND (submissions.updated_at <= exercises.late_submission_deadline OR exercises.late_submission_deadline IS NULL)') } - scope :after_late_deadline, -> { joins(:exercise).where('submissions.updated_at > exercises.late_submission_deadline') } + scope :before_deadline, lambda { + joins(:exercise).where('submissions.updated_at <= exercises.submission_deadline OR exercises.submission_deadline IS NULL') + } + scope :within_grace_period, lambda { + joins(:exercise).where('(submissions.updated_at > exercises.submission_deadline) AND (submissions.updated_at <= exercises.late_submission_deadline OR exercises.late_submission_deadline IS NULL)') + } + scope :after_late_deadline, lambda { + joins(:exercise).where('submissions.updated_at > exercises.late_submission_deadline') + } scope :latest, -> { order(updated_at: :desc).first } @@ -36,7 +49,6 @@ class Submission < ApplicationRecord # after_save :trigger_working_times_action_cable - def build_files_hash(files, attribute) files.map(&attribute.to_proc).zip(files).to_h end @@ -57,12 +69,12 @@ class Submission < ApplicationRecord # expects the full file path incl. file extension # Caution: There must be no unnecessary path prefix included. # Use `file.ext` rather than `./file.ext` - collect_files.detect { |file| file.filepath == file_path } + collect_files.detect {|file| file.filepath == file_path } end def normalized_score ::NewRelic::Agent.add_custom_attributes({unnormalized_score: score}) - if !score.nil? && !exercise.maximum_score.nil? && (exercise.maximum_score > 0) + if !score.nil? && !exercise.maximum_score.nil? && exercise.maximum_score.positive? score / exercise.maximum_score else 0 @@ -119,6 +131,8 @@ class Submission < ApplicationRecord end def unsolved_rfc - RequestForComment.unsolved.where(exercise_id: exercise).where.not(question: nil).where(created_at: OLDEST_RFC_TO_SHOW.ago..Time.current).order("RANDOM()").find { |rfc_element| ((rfc_element.comments_count < MAX_COMMENTS_ON_RECOMMENDED_RFC) && (!rfc_element.question.empty?)) } + RequestForComment.unsolved.where(exercise_id: exercise).where.not(question: nil).where(created_at: OLDEST_RFC_TO_SHOW.ago..Time.current).order('RANDOM()').find do |rfc_element| + ((rfc_element.comments_count < MAX_COMMENTS_ON_RECOMMENDED_RFC) && !rfc_element.question.empty?) + end end end diff --git a/app/models/subscription.rb b/app/models/subscription.rb index ed3f3a3e..ae9477ae 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Subscription < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :request_for_comment diff --git a/app/models/tag.rb b/app/models/tag.rb index b6de61bb..d3d9c86e 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -1,22 +1,22 @@ -class Tag < ApplicationRecord +# frozen_string_literal: true +class Tag < ApplicationRecord has_many :exercise_tags has_many :exercises, through: :exercise_tags - validates_uniqueness_of :name + validates :name, uniqueness: true def destroy - if (can_be_destroyed?) + if can_be_destroyed? super end end def can_be_destroyed? - !exercises.any? + exercises.none? end def to_s name end - -end \ No newline at end of file +end diff --git a/app/models/testrun.rb b/app/models/testrun.rb index 4d09d398..e8903e61 100644 --- a/app/models/testrun.rb +++ b/app/models/testrun.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + class Testrun < ApplicationRecord - belongs_to :file, class_name: 'CodeOcean::File', optional: true - belongs_to :submission + belongs_to :file, class_name: 'CodeOcean::File', optional: true + belongs_to :submission end diff --git a/app/models/tip.rb b/app/models/tip.rb index 85427f41..2b4e26fb 100644 --- a/app/models/tip.rb +++ b/app/models/tip.rb @@ -6,11 +6,16 @@ class Tip < ApplicationRecord has_many :exercise_tips has_many :exercises, through: :exercise_tips belongs_to :file_type, optional: true - validates_presence_of :file_type, if: :example? + validates :file_type, presence: {if: :example?} validate :content? def content? - errors.add :description, I18n.t('activerecord.errors.messages.at_least', attribute: I18n.t('activerecord.attributes.tip.example')) unless [description?, example?].include?(true) + unless [ + description?, example? + ].include?(true) + errors.add :description, + I18n.t('activerecord.errors.messages.at_least', attribute: I18n.t('activerecord.attributes.tip.example')) + end end def to_s diff --git a/app/models/user.rb b/app/models/user.rb index 668aa845..835a1617 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,7 +3,7 @@ class User < ApplicationRecord self.abstract_class = true - ROLES = %w(admin teacher learner) + ROLES = %w[admin teacher learner].freeze belongs_to :consumer has_many :study_group_memberships, as: :user @@ -19,10 +19,11 @@ class User < ApplicationRecord has_one :codeharbor_link, dependent: :destroy accepts_nested_attributes_for :user_proxy_exercise_exercises - scope :with_submissions, -> { where('id IN (SELECT user_id FROM submissions)') } - scope :in_study_group_of, ->(user) { joins(:study_group_memberships).where(study_group_memberships: {study_group_id: user.study_groups}) unless user.admin? } + scope :in_study_group_of, lambda {|user| + joins(:study_group_memberships).where(study_group_memberships: {study_group_id: user.study_groups}) unless user.admin? + } ROLES.each do |role| define_method("#{role}?") { try(:role) == role } diff --git a/app/models/user_exercise_feedback.rb b/app/models/user_exercise_feedback.rb index f236f0c0..79b9bf74 100644 --- a/app/models/user_exercise_feedback.rb +++ b/app/models/user_exercise_feedback.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UserExerciseFeedback < ApplicationRecord include Creation @@ -5,17 +7,17 @@ class UserExerciseFeedback < ApplicationRecord belongs_to :submission, optional: true has_one :execution_environment, through: :exercise - validates :user_id, uniqueness: { scope: [:exercise_id, :user_type] } + validates :user_id, uniqueness: {scope: %i[exercise_id user_type]} scope :intermediate, -> { where.not(normalized_score: 1.00) } scope :final, -> { where(normalized_score: 1.00) } def to_s - "User Exercise Feedback" + 'User Exercise Feedback' end def anomaly_notification AnomalyNotification.where({exercise_id: exercise.id, user_id: user_id, user_type: user_type}) - .where("created_at < ?", created_at).order("created_at DESC").to_a.first + .where('created_at < ?', created_at).order('created_at DESC').to_a.first end end diff --git a/app/models/user_exercise_intervention.rb b/app/models/user_exercise_intervention.rb index b3008206..e246ae80 100644 --- a/app/models/user_exercise_intervention.rb +++ b/app/models/user_exercise_intervention.rb @@ -1,5 +1,6 @@ -class UserExerciseIntervention < ApplicationRecord +# frozen_string_literal: true +class UserExerciseIntervention < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :intervention belongs_to :exercise @@ -7,5 +8,4 @@ class UserExerciseIntervention < ApplicationRecord validates :user, presence: true validates :exercise, presence: true validates :intervention, presence: true - -end \ No newline at end of file +end diff --git a/app/models/user_proxy_exercise_exercise.rb b/app/models/user_proxy_exercise_exercise.rb index 8a0cbb5d..971d7e72 100644 --- a/app/models/user_proxy_exercise_exercise.rb +++ b/app/models/user_proxy_exercise_exercise.rb @@ -1,5 +1,6 @@ -class UserProxyExerciseExercise < ApplicationRecord +# frozen_string_literal: true +class UserProxyExerciseExercise < ApplicationRecord belongs_to :user, polymorphic: true belongs_to :exercise belongs_to :proxy_exercise @@ -9,6 +10,5 @@ class UserProxyExerciseExercise < ApplicationRecord validates :exercise_id, presence: true validates :proxy_exercise_id, presence: true - validates :user_id, uniqueness: { scope: [:proxy_exercise_id, :user_type] } - -end \ No newline at end of file + validates :user_id, uniqueness: {scope: %i[proxy_exercise_id user_type]} +end diff --git a/app/policies/admin/dashboard_policy.rb b/app/policies/admin/dashboard_policy.rb index 673481bd..d8c6ef49 100644 --- a/app/policies/admin/dashboard_policy.rb +++ b/app/policies/admin/dashboard_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Admin class DashboardPolicy < AdminOnlyPolicy def dump_docker? diff --git a/app/policies/admin_only_policy.rb b/app/policies/admin_only_policy.rb index 1d646594..a577bf64 100644 --- a/app/policies/admin_only_policy.rb +++ b/app/policies/admin_only_policy.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class AdminOnlyPolicy < ApplicationPolicy - [:create?, :destroy?, :edit?, :index?, :new?, :show?, :update?].each do |action| + %i[create? destroy? edit? index? new? show? update?].each do |action| define_method(action) { admin? } end end diff --git a/app/policies/admin_or_author_policy.rb b/app/policies/admin_or_author_policy.rb index bf640bad..d510bdd9 100644 --- a/app/policies/admin_or_author_policy.rb +++ b/app/policies/admin_or_author_policy.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class AdminOrAuthorPolicy < ApplicationPolicy - [:create?, :index?, :new?].each do |action| + %i[create? index? new?].each do |action| define_method(action) { admin? || teacher? } end - [:destroy?, :edit?, :show?, :update?].each do |action| + %i[destroy? edit? show? update?].each do |action| define_method(action) { admin? || author? } end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index 1b913945..434b61c7 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationPolicy def admin? @user.admin? @@ -43,7 +45,7 @@ class ApplicationPolicy return false end - @user.study_groups.any?{|i| study_groups.include?(i) } + @user.study_groups.any? {|i| study_groups.include?(i) } end private :everyone_in_study_group @@ -59,7 +61,7 @@ class ApplicationPolicy end def require_user! - fail Pundit::NotAuthorizedError unless @user + raise Pundit::NotAuthorizedError unless @user end private :require_user! @@ -71,7 +73,7 @@ class ApplicationPolicy end def require_user! - fail Pundit::NotAuthorizedError unless @user + raise Pundit::NotAuthorizedError unless @user end private :require_user! end diff --git a/app/policies/code_ocean/file_policy.rb b/app/policies/code_ocean/file_policy.rb index 3d5ab473..c9faf30d 100644 --- a/app/policies/code_ocean/file_policy.rb +++ b/app/policies/code_ocean/file_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CodeOcean class FilePolicy < AdminOrAuthorPolicy def author? @@ -15,7 +17,7 @@ module CodeOcean def create? if @record.context.is_a?(Exercise) admin? || author? - elsif @record.context.is_a?(Submission) and @record.context.exercise.allow_file_creation + elsif @record.context.is_a?(Submission) && @record.context.exercise.allow_file_creation author? else no_one diff --git a/app/policies/codeharbor_link_policy.rb b/app/policies/codeharbor_link_policy.rb index b0dd9a8a..1785f77d 100644 --- a/app/policies/codeharbor_link_policy.rb +++ b/app/policies/codeharbor_link_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CodeharborLinkPolicy < ApplicationPolicy def index? false diff --git a/app/policies/comment_policy.rb b/app/policies/comment_policy.rb index 41caae9b..d71d5115 100644 --- a/app/policies/comment_policy.rb +++ b/app/policies/comment_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CommentPolicy < ApplicationPolicy def create? everyone @@ -7,7 +9,7 @@ class CommentPolicy < ApplicationPolicy everyone end - [:new?, :destroy?, :update?, :edit?].each do |action| + %i[new? destroy? update? edit?].each do |action| define_method(action) { admin? || author? } end diff --git a/app/policies/consumer_policy.rb b/app/policies/consumer_policy.rb index 8566473d..adbfcac1 100644 --- a/app/policies/consumer_policy.rb +++ b/app/policies/consumer_policy.rb @@ -1,3 +1,4 @@ -class ConsumerPolicy < AdminOnlyPolicy +# frozen_string_literal: true +class ConsumerPolicy < AdminOnlyPolicy end diff --git a/app/policies/error_template_attribute_policy.rb b/app/policies/error_template_attribute_policy.rb index eed0896d..b793a68f 100644 --- a/app/policies/error_template_attribute_policy.rb +++ b/app/policies/error_template_attribute_policy.rb @@ -1,3 +1,4 @@ -class ErrorTemplateAttributePolicy < AdminOnlyPolicy +# frozen_string_literal: true +class ErrorTemplateAttributePolicy < AdminOnlyPolicy end diff --git a/app/policies/error_template_policy.rb b/app/policies/error_template_policy.rb index 908be08e..ad9b17bf 100644 --- a/app/policies/error_template_policy.rb +++ b/app/policies/error_template_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ErrorTemplatePolicy < AdminOnlyPolicy def add_attribute? admin? diff --git a/app/policies/event_policy.rb b/app/policies/event_policy.rb index a648b901..54ae1241 100644 --- a/app/policies/event_policy.rb +++ b/app/policies/event_policy.rb @@ -1,7 +1,7 @@ -class EventPolicy < AdminOnlyPolicy +# frozen_string_literal: true +class EventPolicy < AdminOnlyPolicy def create? everyone end - end diff --git a/app/policies/execution_environment_policy.rb b/app/policies/execution_environment_policy.rb index 19da368e..9ed8522c 100644 --- a/app/policies/execution_environment_policy.rb +++ b/app/policies/execution_environment_policy.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class ExecutionEnvironmentPolicy < AdminOnlyPolicy - [:execute_command?, :shell?, :statistics?, :show?].each do |action| + %i[execute_command? shell? statistics? show?].each do |action| define_method(action) { admin? || author? } end diff --git a/app/policies/exercise_collection_policy.rb b/app/policies/exercise_collection_policy.rb index 3d6b725e..c53b7e8e 100644 --- a/app/policies/exercise_collection_policy.rb +++ b/app/policies/exercise_collection_policy.rb @@ -1,7 +1,7 @@ -class ExerciseCollectionPolicy < AdminOnlyPolicy +# frozen_string_literal: true +class ExerciseCollectionPolicy < AdminOnlyPolicy def statistics? admin? end - end diff --git a/app/policies/external_user_policy.rb b/app/policies/external_user_policy.rb index c35b1eb5..a2c31283 100644 --- a/app/policies/external_user_policy.rb +++ b/app/policies/external_user_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ExternalUserPolicy < AdminOnlyPolicy def index? admin? || teacher? diff --git a/app/policies/file_template_policy.rb b/app/policies/file_template_policy.rb index 67aad7c0..8467ca94 100644 --- a/app/policies/file_template_policy.rb +++ b/app/policies/file_template_policy.rb @@ -1,7 +1,7 @@ -class FileTemplatePolicy < AdminOnlyPolicy +# frozen_string_literal: true +class FileTemplatePolicy < AdminOnlyPolicy def by_file_type? everyone end - end diff --git a/app/policies/file_type_policy.rb b/app/policies/file_type_policy.rb index 57cd4940..957b9e8c 100644 --- a/app/policies/file_type_policy.rb +++ b/app/policies/file_type_policy.rb @@ -1,3 +1,4 @@ -class FileTypePolicy < AdminOnlyPolicy +# frozen_string_literal: true +class FileTypePolicy < AdminOnlyPolicy end diff --git a/app/policies/internal_user_policy.rb b/app/policies/internal_user_policy.rb index 639a653f..e5bdc6c7 100644 --- a/app/policies/internal_user_policy.rb +++ b/app/policies/internal_user_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class InternalUserPolicy < AdminOnlyPolicy def destroy? super && !@record.admin? diff --git a/app/policies/proxy_exercise_policy.rb b/app/policies/proxy_exercise_policy.rb index bc26df1b..92d6d58f 100644 --- a/app/policies/proxy_exercise_policy.rb +++ b/app/policies/proxy_exercise_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ProxyExercisePolicy < AdminOrAuthorPolicy def batch_update? admin? @@ -7,8 +9,8 @@ class ProxyExercisePolicy < AdminOrAuthorPolicy admin? || teacher_in_study_group? || teacher? && @record.public? || author? end - [:clone?, :destroy?, :edit?, :update?].each do |action| - define_method(action) { admin? || author?} + %i[clone? destroy? edit? update?].each do |action| + define_method(action) { admin? || author? } end [:reload?].each do |action| diff --git a/app/policies/search_policy.rb b/app/policies/search_policy.rb index 7f861c30..bbf11b53 100644 --- a/app/policies/search_policy.rb +++ b/app/policies/search_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SearchPolicy < AdminOrAuthorPolicy def batch_update? admin? @@ -7,8 +9,8 @@ class SearchPolicy < AdminOrAuthorPolicy admin? || teacher? end - [:clone?, :destroy?, :edit?, :update?].each do |action| - define_method(action) { admin? || author?} + %i[clone? destroy? edit? update?].each do |action| + define_method(action) { admin? || author? } end [:reload?].each do |action| diff --git a/app/policies/statistics_policy.rb b/app/policies/statistics_policy.rb index e04a5f66..f6d1be98 100644 --- a/app/policies/statistics_policy.rb +++ b/app/policies/statistics_policy.rb @@ -1,7 +1,7 @@ -class StatisticsPolicy < AdminOnlyPolicy +# frozen_string_literal: true - [:graphs?, :user_activity?, :user_activity_history?, :rfc_activity?, :rfc_activity_history?].each do |action| +class StatisticsPolicy < AdminOnlyPolicy + %i[graphs? user_activity? user_activity_history? rfc_activity? rfc_activity_history?].each do |action| define_method(action) { admin? } end - end diff --git a/app/policies/study_group_policy.rb b/app/policies/study_group_policy.rb index f19af1f1..325401bf 100644 --- a/app/policies/study_group_policy.rb +++ b/app/policies/study_group_policy.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class StudyGroupPolicy < AdminOnlyPolicy def index? admin? || teacher? end - [:show?, :destroy?, :edit?, :update?, :stream_la?].each do |action| + %i[show? destroy? edit? update? stream_la?].each do |action| define_method(action) { admin? || @user.teacher? && @record.present? && @user.study_groups.exists?(@record.id) } end diff --git a/app/policies/submission_policy.rb b/app/policies/submission_policy.rb index d6ca7830..63a7b2b7 100644 --- a/app/policies/submission_policy.rb +++ b/app/policies/submission_policy.rb @@ -1,10 +1,13 @@ +# frozen_string_literal: true + class SubmissionPolicy < ApplicationPolicy def create? everyone end # insights? is used in the flowr_controller.rb as we use it to authorize the user for a submission - [:download?, :download_file?, :render_file?, :run?, :score?, :show?, :statistics?, :stop?, :test?, :insights?].each do |action| + %i[download? download_file? render_file? run? score? show? statistics? stop? test? + insights?].each do |action| define_method(action) { admin? || author? } end @@ -12,7 +15,6 @@ class SubmissionPolicy < ApplicationPolicy admin? end - def show_study_group? admin? || teacher_in_study_group? end diff --git a/app/policies/subscription_policy.rb b/app/policies/subscription_policy.rb index 6c759837..8d71829b 100644 --- a/app/policies/subscription_policy.rb +++ b/app/policies/subscription_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SubscriptionPolicy < ApplicationPolicy def create? everyone diff --git a/app/policies/tag_policy.rb b/app/policies/tag_policy.rb index 88bb28c9..114bc6b0 100644 --- a/app/policies/tag_policy.rb +++ b/app/policies/tag_policy.rb @@ -1,5 +1,6 @@ -class TagPolicy < AdminOnlyPolicy +# frozen_string_literal: true +class TagPolicy < AdminOnlyPolicy class Scope < Scope def resolve if @user.admin? || @user.teacher? @@ -9,5 +10,4 @@ class TagPolicy < AdminOnlyPolicy end end end - end diff --git a/app/policies/tip_policy.rb b/app/policies/tip_policy.rb index b9a313ad..0cca305b 100644 --- a/app/policies/tip_policy.rb +++ b/app/policies/tip_policy.rb @@ -1,5 +1,6 @@ -class TipPolicy < AdminOnlyPolicy +# frozen_string_literal: true +class TipPolicy < AdminOnlyPolicy class Scope < Scope def resolve if @user.admin? || @user.teacher? @@ -9,5 +10,4 @@ class TipPolicy < AdminOnlyPolicy end end end - end diff --git a/app/policies/user_exercise_feedback_policy.rb b/app/policies/user_exercise_feedback_policy.rb index a570a28c..81861e92 100644 --- a/app/policies/user_exercise_feedback_policy.rb +++ b/app/policies/user_exercise_feedback_policy.rb @@ -1,5 +1,6 @@ -class UserExerciseFeedbackPolicy < AdminOrAuthorPolicy +# frozen_string_literal: true +class UserExerciseFeedbackPolicy < AdminOrAuthorPolicy def create? everyone end @@ -7,5 +8,4 @@ class UserExerciseFeedbackPolicy < AdminOrAuthorPolicy def new? everyone end - end diff --git a/app/services/exercise_service/check_external.rb b/app/services/exercise_service/check_external.rb index cf4a818e..2efc6f68 100644 --- a/app/services/exercise_service/check_external.rb +++ b/app/services/exercise_service/check_external.rb @@ -10,12 +10,13 @@ module ExerciseService def execute response = connection.post do |req| req.headers['Content-Type'] = 'application/json' - req.headers['Authorization'] = 'Bearer ' + @codeharbor_link.api_key + req.headers['Authorization'] = "Bearer #{@codeharbor_link.api_key}" req.body = {uuid: @uuid}.to_json end response_hash = JSON.parse(response.body, symbolize_names: true).slice(:exercise_found, :update_right) - {error: false, message: message(response_hash[:exercise_found], response_hash[:update_right])}.merge(response_hash) + {error: false, +message: message(response_hash[:exercise_found], response_hash[:update_right])}.merge(response_hash) rescue Faraday::Error, JSON::ParserError {error: true, message: I18n.t('exercises.export_codeharbor.error')} end diff --git a/app/services/exercise_service/push_external.rb b/app/services/exercise_service/push_external.rb index 3410a7ba..09b777c6 100644 --- a/app/services/exercise_service/push_external.rb +++ b/app/services/exercise_service/push_external.rb @@ -13,7 +13,7 @@ module ExerciseService response = connection.post do |request| request.headers['Content-Type'] = 'application/zip' request.headers['Content-Length'] = body.length.to_s - request.headers['Authorization'] = 'Bearer ' + @codeharbor_link.api_key + request.headers['Authorization'] = "Bearer #{@codeharbor_link.api_key}" request.body = body end diff --git a/app/services/proforma_service/convert_exercise_to_task.rb b/app/services/proforma_service/convert_exercise_to_task.rb index 4937acd3..ab91b6dc 100644 --- a/app/services/proforma_service/convert_exercise_to_task.rb +++ b/app/services/proforma_service/convert_exercise_to_task.rb @@ -26,7 +26,7 @@ module ProformaService tests: tests, uuid: uuid, language: DEFAULT_LANGUAGE, - model_solutions: model_solutions + model_solutions: model_solutions, }.compact ) end @@ -37,7 +37,7 @@ module ProformaService end def model_solutions - @exercise.files.filter { |file| file.role == 'reference_implementation' }.map do |file| + @exercise.files.filter {|file| file.role == 'reference_implementation' }.map do |file| Proforma::ModelSolution.new( id: "ms-#{file.id}", files: model_solution_file(file) @@ -50,18 +50,20 @@ module ProformaService task_file(file).tap do |ms_file| ms_file.used_by_grader = false ms_file.usage_by_lms = 'display' - end + end, ] end def tests - @exercise.files.filter { |file| file.role == 'teacher_defined_test' || file.role == 'teacher_defined_linter' }.map do |file| + @exercise.files.filter do |file| + file.role == 'teacher_defined_test' || file.role == 'teacher_defined_linter' + end.map do |file| Proforma::Test.new( id: file.id, title: file.name, files: test_file(file), meta_data: { - 'feedback-message' => file.feedback_message + 'feedback-message' => file.feedback_message, }.compact ) end @@ -72,13 +74,16 @@ module ProformaService task_file(file).tap do |t_file| t_file.used_by_grader = true t_file.internal_description = 'teacher_defined_test' - end + end, ] end def task_files @exercise.files - .filter { |file| !file.role.in? %w[reference_implementation teacher_defined_test teacher_defined_linter] }.map do |file| + .filter do |file| + !file.role.in? %w[reference_implementation teacher_defined_test + teacher_defined_linter] + end.map do |file| task_file(file) end end @@ -96,7 +101,12 @@ module ProformaService end def filename(file) - file.path.present? && file.path != '.' ? ::File.join(file.path, file.name_with_extension) : file.name_with_extension + if file.path.present? && file.path != '.' + ::File.join(file.path, + file.name_with_extension) + else + file.name_with_extension + end end def add_content_to_task_file(file, task_file) diff --git a/app/services/proforma_service/convert_task_to_exercise.rb b/app/services/proforma_service/convert_task_to_exercise.rb index fe35eab2..658b5be0 100644 --- a/app/services/proforma_service/convert_task_to_exercise.rb +++ b/app/services/proforma_service/convert_task_to_exercise.rb @@ -39,11 +39,9 @@ module ProformaService end def task_files - @task_files ||= Hash[ - @task.all_files.reject { |file| file.id == 'ms-placeholder-file' }.map do |task_file| - [task_file.id, codeocean_file_from_task_file(task_file)] - end - ] + @task_files ||= @task.all_files.reject {|file| file.id == 'ms-placeholder-file' }.map do |task_file| + [task_file.id, codeocean_file_from_task_file(task_file)] + end.to_h end def codeocean_file_from_task_file(file) diff --git a/app/services/proforma_service/import.rb b/app/services/proforma_service/import.rb index 9a2e6317..e4b5fe12 100644 --- a/app/services/proforma_service/import.rb +++ b/app/services/proforma_service/import.rb @@ -39,7 +39,7 @@ module ProformaService def import_multi Zip::File.open(@zip.path) do |zip_file| - zip_files = zip_file.filter { |entry| entry.name.match?(/\.zip$/) } + zip_files = zip_file.filter {|entry| entry.name.match?(/\.zip$/) } begin zip_files.map! do |entry| store_zip_entry_in_tempfile entry @@ -65,7 +65,7 @@ module ProformaService zip_file.map(&:name) end - filenames.select { |f| f[/\.xml$/] }.any? + filenames.select {|f| f[/\.xml$/] }.any? rescue Zip::Error raise Proforma::InvalidZip end diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb index c108ed98..78b4168d 100644 --- a/app/uploaders/file_uploader.rb +++ b/app/uploaders/file_uploader.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class FileUploader < CarrierWave::Uploader::Base storage :file diff --git a/app/views/code_ocean/files/show.json.jbuilder b/app/views/code_ocean/files/show.json.jbuilder index 09c6c701..94cef071 100644 --- a/app/views/code_ocean/files/show.json.jbuilder +++ b/app/views/code_ocean/files/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.extract! @file, :id, :name_with_extension diff --git a/app/views/comments/index.json.jbuilder b/app/views/comments/index.json.jbuilder index e42dd5bf..31850473 100644 --- a/app/views/comments/index.json.jbuilder +++ b/app/views/comments/index.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.array!(@comments) do |comment| json.extract! comment, :id, :user_id, :file_id, :row, :column, :text, :username, :date, :updated, :editable json.url comment_url(comment, format: :json) diff --git a/app/views/comments/show.json.jbuilder b/app/views/comments/show.json.jbuilder index 621bd9f6..b804cd4f 100644 --- a/app/views/comments/show.json.jbuilder +++ b/app/views/comments/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.extract! @comment, :id, :user_id, :file_id, :row, :column, :text, :created_at, :updated_at diff --git a/app/views/exercises/reload.json.jbuilder b/app/views/exercises/reload.json.jbuilder index 8e5d4e3c..3f5793b1 100644 --- a/app/views/exercises/reload.json.jbuilder +++ b/app/views/exercises/reload.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.set! :files do json.array! @exercise.files.visible, :content, :id end diff --git a/app/views/file_types/show.json.jbuilder b/app/views/file_types/show.json.jbuilder index 0842614e..8eede65f 100644 --- a/app/views/file_types/show.json.jbuilder +++ b/app/views/file_types/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.extract! @file_type, :id, :name, :editor_mode, :file_extension, :executable, :renderable, :binary diff --git a/app/views/proxy_exercises/reload.json.jbuilder b/app/views/proxy_exercises/reload.json.jbuilder index 8e5d4e3c..3f5793b1 100644 --- a/app/views/proxy_exercises/reload.json.jbuilder +++ b/app/views/proxy_exercises/reload.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.set! :files do json.array! @exercise.files.visible, :content, :id end diff --git a/app/views/request_for_comments/index.json.jbuilder b/app/views/request_for_comments/index.json.jbuilder index eaf4293a..756f4b17 100644 --- a/app/views/request_for_comments/index.json.jbuilder +++ b/app/views/request_for_comments/index.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.array!(@request_for_comments) do |request_for_comment| json.extract! request_for_comment, :id, :user_id, :exercise_id, :file_id, :user_type json.url request_for_comment_url(request_for_comment, format: :json) diff --git a/app/views/request_for_comments/show.json.jbuilder b/app/views/request_for_comments/show.json.jbuilder index 443ce0fb..61301c53 100644 --- a/app/views/request_for_comments/show.json.jbuilder +++ b/app/views/request_for_comments/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.extract! @request_for_comment, :id, :user_id, :exercise_id, :file_id, :created_at, :updated_at, :user_type, :solved diff --git a/app/views/submissions/show.json.jbuilder b/app/views/submissions/show.json.jbuilder index 8ad8960a..9c280bee 100644 --- a/app/views/submissions/show.json.jbuilder +++ b/app/views/submissions/show.json.jbuilder @@ -1,7 +1,10 @@ +# frozen_string_literal: true + json.extract! @submission, :id, :files json.download_url download_submission_path(@submission, format: :json) json.score_url score_submission_path(@submission, format: :json) -json.download_file_url download_file_submission_path(@submission, 'a.', format: :json).gsub(/a\.\.json$/, '{filename}.json') +json.download_file_url download_file_submission_path(@submission, 'a.', format: :json).gsub(/a\.\.json$/, + '{filename}.json') json.render_url render_submission_path(@submission, 'a.', format: :json).gsub(/a\.\.json$/, '{filename}.json') json.run_url run_submission_path(@submission, 'a.', format: :json).gsub(/a\.\.json$/, '{filename}.json') json.test_url test_submission_path(@submission, 'a.', format: :json).gsub(/a\.\.json$/, '{filename}.json') diff --git a/config.ru b/config.ru index 4a3c09a6..6dc83218 100644 --- a/config.ru +++ b/config.ru @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. -require_relative "config/environment" +require_relative 'config/environment' run Rails.application Rails.application.load_server diff --git a/config/application.rb b/config/application.rb index 17d35456..78b2bee6 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'boot' require 'rails/all' @@ -25,7 +27,7 @@ module CodeOcean # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de - config.i18n.available_locales = [:de, :en] + config.i18n.available_locales = %i[de en] extra_paths = %W[ #{config.root}/lib @@ -40,7 +42,7 @@ module CodeOcean config.action_cable.mount_path = '/cable' - config.telegraf.tags = { application: 'codeocean' } + config.telegraf.tags = {application: 'codeocean'} config.after_initialize do # Initialize the counters according to the db diff --git a/config/boot.rb b/config/boot.rb index b9e460ce..c04863fa 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/environment.rb b/config/environment.rb index d4654f20..b8a976dc 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Load the Rails application. require_relative 'application' diff --git a/config/environments/development.rb b/config/environments/development.rb index b0e05e12..01edd517 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -26,7 +26,7 @@ Rails.application.configure do config.cache_store = :memory_store config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{2.days.to_i}" + 'Cache-Control' => "public, max-age=#{2.days.to_i}", } else config.action_controller.perform_caching = false diff --git a/config/environments/production.rb b/config/environments/production.rb index 398510a0..39abff0a 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/config/environments/test.rb b/config/environments/test.rb index cfc5d053..0b8ee95a 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -22,7 +22,7 @@ Rails.application.configure do # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{1.hour.to_i}" + 'Cache-Control' => "public, max-age=#{1.hour.to_i}", } # Show full error reports and disable caching. diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb index 89d2efab..f4556db3 100644 --- a/config/initializers/application_controller_renderer.rb +++ b/config/initializers/application_controller_renderer.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # ActiveSupport::Reloader.to_prepare do diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 949bb44e..fa603a4e 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -13,7 +13,7 @@ Rails.application.config.assets.paths << Rails.root.join('node_modules') # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. -Rails.application.config.assets.precompile += %w( markdown-buttons.png ) +Rails.application.config.assets.precompile += %w[markdown-buttons.png] # Disable concurrent asset compilation to prevent segfault # https://github.com/sass/sassc-ruby/issues/197 # Reproduce: `rake assets:clobber`, `rake assets:precompile`. If the command succeeds, it worked diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 33699c30..d43cc1d2 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. @@ -5,4 +7,4 @@ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". -Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] +Rails.backtrace_cleaner.remove_silencers! if ENV['BACKTRACE'] diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb index 5a6a32d3..ee8dff9c 100644 --- a/config/initializers/cookies_serializer.rb +++ b/config/initializers/cookies_serializer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Specify a serializer for the signed and encrypted cookie jars. diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 4b34a036..3babc73f 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +Rails.application.config.filter_parameters += %i[ + passw secret token _key crypt salt certificate otp ssn ] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 638bf0c7..d6c6e2f7 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -15,4 +15,3 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.acronym 'IO' end - diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index dc189968..6e1d16f0 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: diff --git a/config/initializers/monkey_patches.rb b/config/initializers/monkey_patches.rb index a910b23a..5ae5de8a 100644 --- a/config/initializers/monkey_patches.rb +++ b/config/initializers/monkey_patches.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + unless Array.respond_to?(:average) class Array def average - inject(:+) / length unless blank? + inject(:+) / length if present? end end end @@ -9,7 +11,7 @@ end unless Array.respond_to?(:to_h) class Array def to_h - Hash[self] + to_h end end end diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb index 00f64d71..50bcf4ea 100644 --- a/config/initializers/permissions_policy.rb +++ b/config/initializers/permissions_policy.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Define an application-wide HTTP permissions policy. For further # information see https://developers.google.com/web/updates/2018/06/feature-policy # diff --git a/config/initializers/prometheus.rb b/config/initializers/prometheus.rb index 3f736ab6..0a3fb409 100644 --- a/config/initializers/prometheus.rb +++ b/config/initializers/prometheus.rb @@ -3,7 +3,7 @@ require 'code_ocean/config' return unless CodeOcean::Config.new(:code_ocean).read[:prometheus_exporter][:enabled] && !defined?(::Rails::Console) -return if %w[db: assets:].any? { |task| Rake.application.top_level_tasks.to_s.include?(task) } +return if %w[db: assets:].any? {|task| Rake.application.top_level_tasks.to_s.include?(task) } # Add metric callbacks to all models ActiveSupport.on_load :active_record do diff --git a/config/initializers/rails_admin.rb b/config/initializers/rails_admin.rb index e87bc853..489fdd79 100644 --- a/config/initializers/rails_admin.rb +++ b/config/initializers/rails_admin.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true RailsAdmin.config do |config| - ### Popular gems integration ## == Devise == @@ -63,23 +62,23 @@ RailsAdmin.config do |config| per_page(value) end - def total_count() + def total_count count end - def first_page?() + def first_page? self == first end - def last_page?() + def last_page? self == last end end end + module CollectionMethods - alias_method :num_pages, :total_pages + alias num_pages total_pages end end end end - diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index aed61f8c..43ed5fc8 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: '_code_ocean_session', expire_after: 1.month diff --git a/config/initializers/sorcery.rb b/config/initializers/sorcery.rb index 46d97ff6..abc23dfc 100644 --- a/config/initializers/sorcery.rb +++ b/config/initializers/sorcery.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # The first thing you need to configure is which modules you need in your app. # The default is nothing which will include only core features (password encryption, login/logout). # Available submodules are: :user_activation, :http_basic_auth, :remember_me, # :reset_password, :session_timeout, :brute_force_protection, :activity_logging, :external -Rails.application.config.sorcery.submodules = [:brute_force_protection, :remember_me, :reset_password, :user_activation] +Rails.application.config.sorcery.submodules = %i[brute_force_protection remember_me reset_password user_activation] # Here you can configure each submodule's features. Rails.application.config.sorcery.configure do |config| @@ -13,73 +15,62 @@ Rails.application.config.sorcery.configure do |config| # # config.not_authenticated_action = - # When a non logged in user tries to enter a page that requires login, save # the URL he wanted to reach, and send him there after login, using 'redirect_back_or_to'. # Default: `true` # # config.save_return_to_url = - # Set domain option for cookies; Useful for remember_me submodule. # Default: `nil` # # config.cookie_domain = - # -- session timeout -- # How long in seconds to keep the session alive. # Default: `3600` # # config.session_timeout = - # Use the last action as the beginning of session timeout. # Default: `false` # # config.session_timeout_from_last_action = - # -- http_basic_auth -- # What realm to display for which controller name. For example {"My App" => "Application"} # Default: `{"application" => "Application"}` # # config.controller_to_realm_map = - # -- activity logging -- # will register the time of last user login, every login. # Default: `true` # # config.register_login_time = - # will register the time of last user logout, every logout. # Default: `true` # # config.register_logout_time = - # will register the time of last user action, every action. # Default: `true` # # config.register_last_activity_time = - # -- external -- # What providers are supported by this app, i.e. [:twitter, :facebook, :github, :linkedin, :xing, :google, :liveid] . # Default: `[]` # # config.external_providers = - # You can change it by your local ca_file. i.e. '/etc/pki/tls/certs/ca-bundle.crt' # Path to ca_file. By default use a internal ca-bundle.crt. # Default: `'path/to/ca_file'` # # config.ca_file = - # For information about LinkedIn API: # - user info fields go to https://developer.linkedin.com/documents/profile-fields # - access permissions go to https://developer.linkedin.com/documents/authentication#granting @@ -139,7 +130,6 @@ Rails.application.config.sorcery.configure do |config| # config.liveid.callback_url = "http://mydomain.com:3000/oauth/callback?provider=liveid" # config.liveid.user_info_mapping = {:username => "name"} - # --- user config --- config.user_config do |user| # -- core -- @@ -148,74 +138,62 @@ Rails.application.config.sorcery.configure do |config| # # user.username_attribute_names = - # change *virtual* password attribute, the one which is used until an encrypted one is generated. # Default: `:password` # # user.password_attribute_name = - # downcase the username before trying to authenticate, default is false # Default: `false` # user.downcase_username_before_authenticating = true - # change default email attribute. # Default: `:email` # # user.email_attribute_name = - # change default crypted_password attribute. # Default: `:crypted_password` # # user.crypted_password_attribute_name = - # what pattern to use to join the password with the salt # Default: `""` # # user.salt_join_token = - # change default salt attribute. # Default: `:salt` # # user.salt_attribute_name = - # how many times to apply encryption to the password. # Default: `nil` # # user.stretches = - # encryption key used to encrypt reversible encryptions such as AES256. # WARNING: If used for users' passwords, changing this key will leave passwords undecryptable! # Default: `nil` # # user.encryption_key = - # use an external encryption class. # Default: `nil` # # user.custom_encryption_provider = - # encryption algorithm name. See 'encryption_algorithm=' for available options. # Default: `:bcrypt` # # user.encryption_algorithm = - # make this configuration inheritable for subclasses. Useful for ActiveRecord's STI. # Default: `false` # # user.subclasses_inherit_config = - # -- remember_me -- # allow the remember_me cookie to settable through AJAX # Default: `true` @@ -227,38 +205,32 @@ Rails.application.config.sorcery.configure do |config| # # user.remember_me_for = - # -- user_activation -- # the attribute name to hold activation state (active/pending). # Default: `:activation_state` # # user.activation_state_attribute_name = - # the attribute name to hold activation code (sent by email). # Default: `:activation_token` # # user.activation_token_attribute_name = - # the attribute name to hold activation code expiration date. # Default: `:activation_token_expires_at` # # user.activation_token_expires_at_attribute_name = - # how many seconds before the activation code expires. nil for never expires. # Default: `nil` # # user.activation_token_expiration_period = - # your mailer class. Required. # Default: `nil` # user.user_activation_mailer = UserMailer - # when true sorcery will not automatically # email activation details and allow you to # manually handle how and when email is sent. @@ -266,56 +238,47 @@ Rails.application.config.sorcery.configure do |config| # # user.activation_mailer_disabled = - # activation needed email method on your mailer class. # Default: `:activation_needed_email` # # user.activation_needed_email_method_name = - # activation success email method on your mailer class. # Default: `:activation_success_email` # # user.activation_success_email_method_name = - # do you want to prevent or allow users that did not activate by email to login? # Default: `true` # # user.prevent_non_active_users_to_login = - # -- reset_password -- # reset password code attribute name. # Default: `:reset_password_token` # # user.reset_password_token_attribute_name = - # expires at attribute name. # Default: `:reset_password_token_expires_at` # # user.reset_password_token_expires_at_attribute_name = - # when was email sent, used for hammering protection. # Default: `:reset_password_email_sent_at` # # user.reset_password_email_sent_at_attribute_name = - # mailer class. Needed. # Default: `nil` # user.reset_password_mailer = UserMailer - # reset password email method on your mailer class. # Default: `:reset_password_email` # # user.reset_password_email_method_name = - # when true sorcery will not automatically # email password reset details and allow you to # manually handle how and when email is sent @@ -323,38 +286,32 @@ Rails.application.config.sorcery.configure do |config| # # user.reset_password_mailer_disabled = - # how many seconds before the reset request expires. nil for never expires. # Default: `nil` # # user.reset_password_expiration_period = - # hammering protection, how long to wait before allowing another email to be sent. # Default: `5 * 60` # user.reset_password_time_between_emails = 1.minute - # -- brute_force_protection -- # Failed logins attribute name. # Default: `:failed_logins_count` # # user.failed_logins_count_attribute_name = - # This field indicates whether user is banned and when it will be active again. # Default: `:lock_expires_at` # # user.lock_expires_at_attribute_name = - # How many failed logins allowed. # Default: `50` # # user.consecutive_login_retries_amount_limit = - # How long the user should be banned. in seconds. 0 for permanent. # Default: `60 * 60` # @@ -387,44 +344,37 @@ Rails.application.config.sorcery.configure do |config| # # user.last_login_at_attribute_name = - # Last logout attribute name. # Default: `:last_logout_at` # # user.last_logout_at_attribute_name = - # Last activity attribute name. # Default: `:last_activity_at` # # user.last_activity_at_attribute_name = - # How long since last activity is he user defined logged out? # Default: `10 * 60` # # user.activity_timeout = - # -- external -- # Class which holds the various external provider data for this user. # Default: `nil` # # user.authentications_class = - # User's identifier in authentications class. # Default: `:user_id` # # user.authentications_user_id_attribute_name = - # Provider's identifier in authentications class. # Default: `:provider` # # user.provider_attribute_name = - # User's external unique identifier in authentications class. # Default: `:uid` # diff --git a/config/initializers/will_paginate.rb b/config/initializers/will_paginate.rb index bfff0a68..d626a823 100644 --- a/config/initializers/will_paginate.rb +++ b/config/initializers/will_paginate.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + WillPaginate.per_page = 20 diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index bbfc3961..2f3c0db4 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which diff --git a/config/puma.rb b/config/puma.rb index 58d38795..f771f275 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,28 +1,30 @@ +# frozen_string_literal: true + # Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5) +min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count } threads min_threads_count, max_threads_count # Specifies the `worker_timeout` threshold that Puma will use to wait before # terminating a worker in development environments. # -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" +worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development' # Specifies the `port` that Puma will listen on to receive requests; default is 7000. # -port ENV.fetch("PORT") { 7000 } +port ENV.fetch('PORT', 7000) # Specifies the `environment` that Puma will run in. # -environment ENV.fetch("RAILS_ENV") { "development" } +environment ENV.fetch('RAILS_ENV', 'development') # Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } +pidfile ENV.fetch('PIDFILE', 'tmp/pids/server.pid') # Specifies the number of `workers` to boot in clustered mode. # Workers are forked web server processes. If using threads and workers together diff --git a/config/schedule.rb b/config/schedule.rb index f1236a52..597ca71c 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Use this file to easily define all of your cron jobs. # # It's helpful, but not entirely necessary to understand cron before proceeding. @@ -19,7 +21,7 @@ # Learn more: http://github.com/javan/whenever -set :output, Whenever.path + '/log/whenever/whenever_$(date +%Y%m%d%H%M%S).log' +set :output, "#{Whenever.path}/log/whenever/whenever_$(date +%Y%m%d%H%M%S).log" set :environment, ENV['RAILS_ENV'] if ENV['RAILS_ENV'] every 1.day, at: '3:00 am' do diff --git a/config/spring.rb b/config/spring.rb index db5bf130..93cd0ff8 100644 --- a/config/spring.rb +++ b/config/spring.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + Spring.watch( - ".ruby-version", - ".rbenv-vars", - "tmp/restart.txt", - "tmp/caching-dev.txt" + '.ruby-version', + '.rbenv-vars', + 'tmp/restart.txt', + 'tmp/caching-dev.txt' ) diff --git a/db/migrate/20140625134118_create_exercises.rb b/db/migrate/20140625134118_create_exercises.rb index 1395ecc3..069c70a1 100644 --- a/db/migrate/20140625134118_create_exercises.rb +++ b/db/migrate/20140625134118_create_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateExercises < ActiveRecord::Migration[4.2] def change create_table :exercises do |t| diff --git a/db/migrate/20140626143132_create_execution_environments.rb b/db/migrate/20140626143132_create_execution_environments.rb index 40c50d0b..e4392b57 100644 --- a/db/migrate/20140626143132_create_execution_environments.rb +++ b/db/migrate/20140626143132_create_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateExecutionEnvironments < ActiveRecord::Migration[4.2] def change create_table :execution_environments do |t| diff --git a/db/migrate/20140626144036_create_submissions.rb b/db/migrate/20140626144036_create_submissions.rb index 07242ed1..bccf690b 100644 --- a/db/migrate/20140626144036_create_submissions.rb +++ b/db/migrate/20140626144036_create_submissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateSubmissions < ActiveRecord::Migration[4.2] def change create_table :submissions do |t| diff --git a/db/migrate/20140630093736_add_reference_implementation_to_exercises.rb b/db/migrate/20140630093736_add_reference_implementation_to_exercises.rb index d9a854e2..191f345a 100644 --- a/db/migrate/20140630093736_add_reference_implementation_to_exercises.rb +++ b/db/migrate/20140630093736_add_reference_implementation_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddReferenceImplementationToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :reference_implementation, :text diff --git a/db/migrate/20140630111215_add_indent_size_to_execution_environments.rb b/db/migrate/20140630111215_add_indent_size_to_execution_environments.rb index 6f2830a8..0d77ba74 100644 --- a/db/migrate/20140630111215_add_indent_size_to_execution_environments.rb +++ b/db/migrate/20140630111215_add_indent_size_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndentSizeToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :indent_size, :integer diff --git a/db/migrate/20140701120126_create_consumers.rb b/db/migrate/20140701120126_create_consumers.rb index 8efbc84e..705c3f63 100644 --- a/db/migrate/20140701120126_create_consumers.rb +++ b/db/migrate/20140701120126_create_consumers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateConsumers < ActiveRecord::Migration[4.2] def change create_table :consumers do |t| diff --git a/db/migrate/20140701122345_create_users.rb b/db/migrate/20140701122345_create_users.rb index 215e0ffb..4501ca21 100644 --- a/db/migrate/20140701122345_create_users.rb +++ b/db/migrate/20140701122345_create_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateUsers < ActiveRecord::Migration[4.2] def change create_table :users do |t| diff --git a/db/migrate/20140702100130_add_oauth_key_to_consumers.rb b/db/migrate/20140702100130_add_oauth_key_to_consumers.rb index e52d914c..5aa24620 100644 --- a/db/migrate/20140702100130_add_oauth_key_to_consumers.rb +++ b/db/migrate/20140702100130_add_oauth_key_to_consumers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddOauthKeyToConsumers < ActiveRecord::Migration[4.2] def change add_column :consumers, :oauth_key, :string diff --git a/db/migrate/20140703070749_add_oauth_secret_to_consumers.rb b/db/migrate/20140703070749_add_oauth_secret_to_consumers.rb index 61825748..6a0aeb3d 100644 --- a/db/migrate/20140703070749_add_oauth_secret_to_consumers.rb +++ b/db/migrate/20140703070749_add_oauth_secret_to_consumers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddOauthSecretToConsumers < ActiveRecord::Migration[4.2] def change add_column :consumers, :oauth_secret, :string diff --git a/db/migrate/20140716153147_add_role_to_users.rb b/db/migrate/20140716153147_add_role_to_users.rb index 35228ab0..7644985c 100644 --- a/db/migrate/20140716153147_add_role_to_users.rb +++ b/db/migrate/20140716153147_add_role_to_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddRoleToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :role, :string diff --git a/db/migrate/20140717074902_add_user_id_to_exercises.rb b/db/migrate/20140717074902_add_user_id_to_exercises.rb index 55c75391..502fbace 100644 --- a/db/migrate/20140717074902_add_user_id_to_exercises.rb +++ b/db/migrate/20140717074902_add_user_id_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserIdToExercises < ActiveRecord::Migration[4.2] def change add_reference :exercises, :user diff --git a/db/migrate/20140722125431_add_run_command_to_execution_environments.rb b/db/migrate/20140722125431_add_run_command_to_execution_environments.rb index de7e0f21..0d29329f 100644 --- a/db/migrate/20140722125431_add_run_command_to_execution_environments.rb +++ b/db/migrate/20140722125431_add_run_command_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddRunCommandToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :run_command, :string diff --git a/db/migrate/20140723135530_add_test_command_to_execution_environments.rb b/db/migrate/20140723135530_add_test_command_to_execution_environments.rb index fefc57eb..0383367d 100644 --- a/db/migrate/20140723135530_add_test_command_to_execution_environments.rb +++ b/db/migrate/20140723135530_add_test_command_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTestCommandToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :test_command, :string diff --git a/db/migrate/20140723135747_add_test_code_to_exercises.rb b/db/migrate/20140723135747_add_test_code_to_exercises.rb index 8f184f37..105a479e 100644 --- a/db/migrate/20140723135747_add_test_code_to_exercises.rb +++ b/db/migrate/20140723135747_add_test_code_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTestCodeToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :test_code, :text diff --git a/db/migrate/20140724155359_add_cause_to_submissions.rb b/db/migrate/20140724155359_add_cause_to_submissions.rb index 37b273ca..73e43a74 100644 --- a/db/migrate/20140724155359_add_cause_to_submissions.rb +++ b/db/migrate/20140724155359_add_cause_to_submissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddCauseToSubmissions < ActiveRecord::Migration[4.2] def change add_column :submissions, :cause, :string diff --git a/db/migrate/20140730114343_add_template_test_code_to_exercises.rb b/db/migrate/20140730114343_add_template_test_code_to_exercises.rb index a0575cbf..7bf5be31 100644 --- a/db/migrate/20140730114343_add_template_test_code_to_exercises.rb +++ b/db/migrate/20140730114343_add_template_test_code_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTemplateTestCodeToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :template_test_code, :text diff --git a/db/migrate/20140730115010_add_supports_user_defined_tests_to_exercises.rb b/db/migrate/20140730115010_add_supports_user_defined_tests_to_exercises.rb index 401899b6..40cc72d6 100644 --- a/db/migrate/20140730115010_add_supports_user_defined_tests_to_exercises.rb +++ b/db/migrate/20140730115010_add_supports_user_defined_tests_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddSupportsUserDefinedTestsToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :supports_user_defined_tests, :boolean diff --git a/db/migrate/20140805161431_add_testing_framework_to_execution_environments.rb b/db/migrate/20140805161431_add_testing_framework_to_execution_environments.rb index 8b5ea99e..ebce5eca 100644 --- a/db/migrate/20140805161431_add_testing_framework_to_execution_environments.rb +++ b/db/migrate/20140805161431_add_testing_framework_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTestingFrameworkToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :testing_framework, :string diff --git a/db/migrate/20140812102114_create_file_types.rb b/db/migrate/20140812102114_create_file_types.rb index 22fd2e4c..a2e5d9db 100644 --- a/db/migrate/20140812102114_create_file_types.rb +++ b/db/migrate/20140812102114_create_file_types.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateFileTypes < ActiveRecord::Migration[4.2] def change create_table :file_types do |t| diff --git a/db/migrate/20140812144733_create_files.rb b/db/migrate/20140812144733_create_files.rb index 789981b9..354179bc 100644 --- a/db/migrate/20140812144733_create_files.rb +++ b/db/migrate/20140812144733_create_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateFiles < ActiveRecord::Migration[4.2] def change create_table :files do |t| diff --git a/db/migrate/20140812150607_remove_file_type_related_columns_from_execution_environments.rb b/db/migrate/20140812150607_remove_file_type_related_columns_from_execution_environments.rb index 53d14dfd..b27a9408 100644 --- a/db/migrate/20140812150607_remove_file_type_related_columns_from_execution_environments.rb +++ b/db/migrate/20140812150607_remove_file_type_related_columns_from_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveFileTypeRelatedColumnsFromExecutionEnvironments < ActiveRecord::Migration[4.2] def change remove_column :execution_environments, :editor_mode, :string diff --git a/db/migrate/20140812150925_remove_file_related_columns_from_exercises.rb b/db/migrate/20140812150925_remove_file_related_columns_from_exercises.rb index 92954d72..38ff45b0 100644 --- a/db/migrate/20140812150925_remove_file_related_columns_from_exercises.rb +++ b/db/migrate/20140812150925_remove_file_related_columns_from_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveFileRelatedColumnsFromExercises < ActiveRecord::Migration[4.2] def change remove_column :exercises, :reference_implementation, :text diff --git a/db/migrate/20140813091722_remove_code_from_submissions.rb b/db/migrate/20140813091722_remove_code_from_submissions.rb index 2f8ded5e..795a3bb5 100644 --- a/db/migrate/20140813091722_remove_code_from_submissions.rb +++ b/db/migrate/20140813091722_remove_code_from_submissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveCodeFromSubmissions < ActiveRecord::Migration[4.2] def change remove_column :submissions, :code, :text diff --git a/db/migrate/20140820170039_add_instructions_to_exercises.rb b/db/migrate/20140820170039_add_instructions_to_exercises.rb index aeab4a95..2b9c80cb 100644 --- a/db/migrate/20140820170039_add_instructions_to_exercises.rb +++ b/db/migrate/20140820170039_add_instructions_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddInstructionsToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :instructions, :text diff --git a/db/migrate/20140821064318_add_published_to_exercises.rb b/db/migrate/20140821064318_add_published_to_exercises.rb index 999ba1f5..b999159b 100644 --- a/db/migrate/20140821064318_add_published_to_exercises.rb +++ b/db/migrate/20140821064318_add_published_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddPublishedToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :published, :boolean diff --git a/db/migrate/20140823172643_add_executable_to_file_types.rb b/db/migrate/20140823172643_add_executable_to_file_types.rb index af2f975f..d32dd552 100644 --- a/db/migrate/20140823172643_add_executable_to_file_types.rb +++ b/db/migrate/20140823172643_add_executable_to_file_types.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddExecutableToFileTypes < ActiveRecord::Migration[4.2] def change add_column :file_types, :executable, :boolean diff --git a/db/migrate/20140823173923_add_renderable_to_file_types.rb b/db/migrate/20140823173923_add_renderable_to_file_types.rb index 034a480a..423aa28d 100644 --- a/db/migrate/20140823173923_add_renderable_to_file_types.rb +++ b/db/migrate/20140823173923_add_renderable_to_file_types.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddRenderableToFileTypes < ActiveRecord::Migration[4.2] def change add_column :file_types, :renderable, :boolean diff --git a/db/migrate/20140825121336_create_external_users.rb b/db/migrate/20140825121336_create_external_users.rb index e7b9d816..43bc37c5 100644 --- a/db/migrate/20140825121336_create_external_users.rb +++ b/db/migrate/20140825121336_create_external_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateExternalUsers < ActiveRecord::Migration[4.2] def change create_table :external_users do |t| diff --git a/db/migrate/20140825125801_create_internal_users.rb b/db/migrate/20140825125801_create_internal_users.rb index 2ff2c342..c0247675 100644 --- a/db/migrate/20140825125801_create_internal_users.rb +++ b/db/migrate/20140825125801_create_internal_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateInternalUsers < ActiveRecord::Migration[4.2] def change create_table :internal_users do |t| diff --git a/db/migrate/20140825154202_drop_users.rb b/db/migrate/20140825154202_drop_users.rb index 201b6433..5e250fbe 100644 --- a/db/migrate/20140825154202_drop_users.rb +++ b/db/migrate/20140825154202_drop_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DropUsers < ActiveRecord::Migration[4.2] def change drop_table :users diff --git a/db/migrate/20140825161350_add_user_type_to_exercises.rb b/db/migrate/20140825161350_add_user_type_to_exercises.rb index c9c44d47..f8688499 100644 --- a/db/migrate/20140825161350_add_user_type_to_exercises.rb +++ b/db/migrate/20140825161350_add_user_type_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserTypeToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :user_type, :string diff --git a/db/migrate/20140825161358_add_user_type_to_file_types.rb b/db/migrate/20140825161358_add_user_type_to_file_types.rb index 09eb709e..de3c95b2 100644 --- a/db/migrate/20140825161358_add_user_type_to_file_types.rb +++ b/db/migrate/20140825161358_add_user_type_to_file_types.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserTypeToFileTypes < ActiveRecord::Migration[4.2] def change add_column :file_types, :user_type, :string diff --git a/db/migrate/20140825161406_add_user_type_to_submissions.rb b/db/migrate/20140825161406_add_user_type_to_submissions.rb index fd72ba6c..c8c90aa7 100644 --- a/db/migrate/20140825161406_add_user_type_to_submissions.rb +++ b/db/migrate/20140825161406_add_user_type_to_submissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserTypeToSubmissions < ActiveRecord::Migration[4.2] def change add_column :submissions, :user_type, :string diff --git a/db/migrate/20140826073318_sorcery_core.rb b/db/migrate/20140826073318_sorcery_core.rb index 077e88b8..ce978f4f 100644 --- a/db/migrate/20140826073318_sorcery_core.rb +++ b/db/migrate/20140826073318_sorcery_core.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SorceryCore < ActiveRecord::Migration[4.2] def change InternalUser.delete_all diff --git a/db/migrate/20140826073319_sorcery_brute_force_protection.rb b/db/migrate/20140826073319_sorcery_brute_force_protection.rb index abd9d835..3723acbc 100644 --- a/db/migrate/20140826073319_sorcery_brute_force_protection.rb +++ b/db/migrate/20140826073319_sorcery_brute_force_protection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SorceryBruteForceProtection < ActiveRecord::Migration[4.2] def change add_column :internal_users, :failed_logins_count, :integer, default: 0 diff --git a/db/migrate/20140826073320_sorcery_remember_me.rb b/db/migrate/20140826073320_sorcery_remember_me.rb index f232eb09..84429385 100644 --- a/db/migrate/20140826073320_sorcery_remember_me.rb +++ b/db/migrate/20140826073320_sorcery_remember_me.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SorceryRememberMe < ActiveRecord::Migration[4.2] def change add_column :internal_users, :remember_me_token, :string, default: nil diff --git a/db/migrate/20140826073321_sorcery_reset_password.rb b/db/migrate/20140826073321_sorcery_reset_password.rb index 74ab7c8d..26a4801c 100644 --- a/db/migrate/20140826073321_sorcery_reset_password.rb +++ b/db/migrate/20140826073321_sorcery_reset_password.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SorceryResetPassword < ActiveRecord::Migration[4.2] def change add_column :internal_users, :reset_password_token, :string, default: nil diff --git a/db/migrate/20140826073322_sorcery_user_activation.rb b/db/migrate/20140826073322_sorcery_user_activation.rb index 47fc60f1..cb8758b1 100644 --- a/db/migrate/20140826073322_sorcery_user_activation.rb +++ b/db/migrate/20140826073322_sorcery_user_activation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SorceryUserActivation < ActiveRecord::Migration[4.2] def change add_column :internal_users, :activation_state, :string, default: nil diff --git a/db/migrate/20140827065359_add_binary_to_file_types.rb b/db/migrate/20140827065359_add_binary_to_file_types.rb index 0fa3c65d..fe2d4ea8 100644 --- a/db/migrate/20140827065359_add_binary_to_file_types.rb +++ b/db/migrate/20140827065359_add_binary_to_file_types.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddBinaryToFileTypes < ActiveRecord::Migration[4.2] def change add_column :file_types, :binary, :boolean diff --git a/db/migrate/20140827083957_add_native_file_to_files.rb b/db/migrate/20140827083957_add_native_file_to_files.rb index cafe27f5..3a92195d 100644 --- a/db/migrate/20140827083957_add_native_file_to_files.rb +++ b/db/migrate/20140827083957_add_native_file_to_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddNativeFileToFiles < ActiveRecord::Migration[4.2] def change add_column :files, :native_file, :string diff --git a/db/migrate/20140829141913_create_hints.rb b/db/migrate/20140829141913_create_hints.rb index ca49c91b..3c8a1464 100644 --- a/db/migrate/20140829141913_create_hints.rb +++ b/db/migrate/20140829141913_create_hints.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateHints < ActiveRecord::Migration[4.2] def change create_table :hints do |t| diff --git a/db/migrate/20140903093436_remove_not_null_constraints_from_internal_users.rb b/db/migrate/20140903093436_remove_not_null_constraints_from_internal_users.rb index d1f11303..b7f51a13 100644 --- a/db/migrate/20140903093436_remove_not_null_constraints_from_internal_users.rb +++ b/db/migrate/20140903093436_remove_not_null_constraints_from_internal_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveNotNullConstraintsFromInternalUsers < ActiveRecord::Migration[4.2] def change change_column_null(:internal_users, :crypted_password, true) diff --git a/db/migrate/20140903165113_create_errors.rb b/db/migrate/20140903165113_create_errors.rb index 27534d38..8d9b849d 100644 --- a/db/migrate/20140903165113_create_errors.rb +++ b/db/migrate/20140903165113_create_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateErrors < ActiveRecord::Migration[4.2] def change create_table :errors do |t| diff --git a/db/migrate/20140904082810_add_token_to_exercises.rb b/db/migrate/20140904082810_add_token_to_exercises.rb index 14e7a459..713210a5 100644 --- a/db/migrate/20140904082810_add_token_to_exercises.rb +++ b/db/migrate/20140904082810_add_token_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTokenToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :token, :string diff --git a/db/migrate/20140909115430_add_file_id_to_exercises.rb b/db/migrate/20140909115430_add_file_id_to_exercises.rb index 09990eac..4ab10268 100644 --- a/db/migrate/20140909115430_add_file_id_to_exercises.rb +++ b/db/migrate/20140909115430_add_file_id_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddFileIdToExercises < ActiveRecord::Migration[4.2] def change add_reference :exercises, :file diff --git a/db/migrate/20140915095420_add_role_to_files.rb b/db/migrate/20140915095420_add_role_to_files.rb index 47774e4c..2d57c908 100644 --- a/db/migrate/20140915095420_add_role_to_files.rb +++ b/db/migrate/20140915095420_add_role_to_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddRoleToFiles < ActiveRecord::Migration[4.2] def change add_column :files, :role, :string diff --git a/db/migrate/20140915122846_remove_file_id_from_exercises.rb b/db/migrate/20140915122846_remove_file_id_from_exercises.rb index 955f4d13..9b495a3a 100644 --- a/db/migrate/20140915122846_remove_file_id_from_exercises.rb +++ b/db/migrate/20140915122846_remove_file_id_from_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveFileIdFromExercises < ActiveRecord::Migration[4.2] def change remove_reference :exercises, :file diff --git a/db/migrate/20140918063522_add_hashed_content_to_files.rb b/db/migrate/20140918063522_add_hashed_content_to_files.rb index 44c103f0..f7685207 100644 --- a/db/migrate/20140918063522_add_hashed_content_to_files.rb +++ b/db/migrate/20140918063522_add_hashed_content_to_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddHashedContentToFiles < ActiveRecord::Migration[4.2] def change add_column :files, :hashed_content, :string diff --git a/db/migrate/20140922161120_add_feedback_message_to_files.rb b/db/migrate/20140922161120_add_feedback_message_to_files.rb index a5908e00..4d04a887 100644 --- a/db/migrate/20140922161120_add_feedback_message_to_files.rb +++ b/db/migrate/20140922161120_add_feedback_message_to_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddFeedbackMessageToFiles < ActiveRecord::Migration[4.2] def change add_column :files, :feedback_message, :string diff --git a/db/migrate/20140922161226_add_weight_to_files.rb b/db/migrate/20140922161226_add_weight_to_files.rb index c2664529..d1515f4d 100644 --- a/db/migrate/20140922161226_add_weight_to_files.rb +++ b/db/migrate/20140922161226_add_weight_to_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddWeightToFiles < ActiveRecord::Migration[4.2] def change add_column :files, :weight, :float diff --git a/db/migrate/20141003072729_add_help_to_execution_environments.rb b/db/migrate/20141003072729_add_help_to_execution_environments.rb index 057aac53..54a36f05 100644 --- a/db/migrate/20141003072729_add_help_to_execution_environments.rb +++ b/db/migrate/20141003072729_add_help_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddHelpToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :help, :text diff --git a/db/migrate/20141004114747_add_exposed_ports_to_execution_environments.rb b/db/migrate/20141004114747_add_exposed_ports_to_execution_environments.rb index b930022b..5fcd6c1f 100644 --- a/db/migrate/20141004114747_add_exposed_ports_to_execution_environments.rb +++ b/db/migrate/20141004114747_add_exposed_ports_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddExposedPortsToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :exposed_ports, :string diff --git a/db/migrate/20141009110434_add_permitted_execution_time_to_execution_environments.rb b/db/migrate/20141009110434_add_permitted_execution_time_to_execution_environments.rb index c7c73ca3..210d61d6 100644 --- a/db/migrate/20141009110434_add_permitted_execution_time_to_execution_environments.rb +++ b/db/migrate/20141009110434_add_permitted_execution_time_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddPermittedExecutionTimeToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :permitted_execution_time, :integer diff --git a/db/migrate/20141011145303_add_user_id_and_user_type_to_execution_environments.rb b/db/migrate/20141011145303_add_user_id_and_user_type_to_execution_environments.rb index b0ef78fc..b6e77068 100644 --- a/db/migrate/20141011145303_add_user_id_and_user_type_to_execution_environments.rb +++ b/db/migrate/20141011145303_add_user_id_and_user_type_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserIdAndUserTypeToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_reference :execution_environments, :user diff --git a/db/migrate/20141017110211_rename_published_to_public.rb b/db/migrate/20141017110211_rename_published_to_public.rb index f651460c..88547f9f 100644 --- a/db/migrate/20141017110211_rename_published_to_public.rb +++ b/db/migrate/20141017110211_rename_published_to_public.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RenamePublishedToPublic < ActiveRecord::Migration[4.2] def change rename_column :exercises, :published, :public diff --git a/db/migrate/20141031161603_add_path_to_files.rb b/db/migrate/20141031161603_add_path_to_files.rb index 46b012d4..234e8d0f 100644 --- a/db/migrate/20141031161603_add_path_to_files.rb +++ b/db/migrate/20141031161603_add_path_to_files.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddPathToFiles < ActiveRecord::Migration[4.2] def change add_column :files, :path, :string diff --git a/db/migrate/20141119131607_create_comments.rb b/db/migrate/20141119131607_create_comments.rb index eb697231..c572e854 100644 --- a/db/migrate/20141119131607_create_comments.rb +++ b/db/migrate/20141119131607_create_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateComments < ActiveRecord::Migration[4.2] def change create_table :comments do |t| diff --git a/db/migrate/20150128083123_create_teams.rb b/db/migrate/20150128083123_create_teams.rb index f2f7c543..f26722ab 100644 --- a/db/migrate/20150128083123_create_teams.rb +++ b/db/migrate/20150128083123_create_teams.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateTeams < ActiveRecord::Migration[4.2] def change create_table :teams do |t| diff --git a/db/migrate/20150128084834_create_internal_users_teams.rb b/db/migrate/20150128084834_create_internal_users_teams.rb index ece283c2..c45df2d2 100644 --- a/db/migrate/20150128084834_create_internal_users_teams.rb +++ b/db/migrate/20150128084834_create_internal_users_teams.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateInternalUsersTeams < ActiveRecord::Migration[4.2] def change create_table :internal_users_teams do |t| diff --git a/db/migrate/20150128093003_add_team_id_to_exercises.rb b/db/migrate/20150128093003_add_team_id_to_exercises.rb index 04c58cd0..c88f3f8f 100644 --- a/db/migrate/20150128093003_add_team_id_to_exercises.rb +++ b/db/migrate/20150128093003_add_team_id_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTeamIdToExercises < ActiveRecord::Migration[4.2] def change add_reference :exercises, :team diff --git a/db/migrate/20150204080832_add_pool_size_to_execution_environments.rb b/db/migrate/20150204080832_add_pool_size_to_execution_environments.rb index aab35315..afe35010 100644 --- a/db/migrate/20150204080832_add_pool_size_to_execution_environments.rb +++ b/db/migrate/20150204080832_add_pool_size_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddPoolSizeToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :pool_size, :integer diff --git a/db/migrate/20150310150712_add_file_type_id_to_execution_environments.rb b/db/migrate/20150310150712_add_file_type_id_to_execution_environments.rb index 214bcec0..4bb249f1 100644 --- a/db/migrate/20150310150712_add_file_type_id_to_execution_environments.rb +++ b/db/migrate/20150310150712_add_file_type_id_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddFileTypeIdToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_reference :execution_environments, :file_type diff --git a/db/migrate/20150317083739_add_memory_limit_to_execution_environments.rb b/db/migrate/20150317083739_add_memory_limit_to_execution_environments.rb index 899b7d50..c9a019cc 100644 --- a/db/migrate/20150317083739_add_memory_limit_to_execution_environments.rb +++ b/db/migrate/20150317083739_add_memory_limit_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddMemoryLimitToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :memory_limit, :integer diff --git a/db/migrate/20150317115338_add_network_enabled_to_execution_environments.rb b/db/migrate/20150317115338_add_network_enabled_to_execution_environments.rb index c328a298..e5b62d0a 100644 --- a/db/migrate/20150317115338_add_network_enabled_to_execution_environments.rb +++ b/db/migrate/20150317115338_add_network_enabled_to_execution_environments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddNetworkEnabledToExecutionEnvironments < ActiveRecord::Migration[4.2] def change add_column :execution_environments, :network_enabled, :boolean diff --git a/db/migrate/20150327141740_create_request_for_comments.rb b/db/migrate/20150327141740_create_request_for_comments.rb index a89b947b..38d3c001 100644 --- a/db/migrate/20150327141740_create_request_for_comments.rb +++ b/db/migrate/20150327141740_create_request_for_comments.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class CreateRequestForComments < ActiveRecord::Migration[4.2] def change create_table :request_for_comments do |t| - t.integer :requestorid, :null => false - t.integer :exerciseid, :null => false - t.integer :fileid, :null => false + t.integer :requestorid, null: false + t.integer :exerciseid, null: false + t.integer :fileid, null: false t.timestamp :requested_at t.timestamps diff --git a/db/migrate/20150408155923_add_submission_to_error.rb b/db/migrate/20150408155923_add_submission_to_error.rb index e7363e0d..7b51c10f 100644 --- a/db/migrate/20150408155923_add_submission_to_error.rb +++ b/db/migrate/20150408155923_add_submission_to_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddSubmissionToError < ActiveRecord::Migration[4.2] def change add_reference :errors, :submission, index: true diff --git a/db/migrate/20150421074734_add_file_index_to_files.rb b/db/migrate/20150421074734_add_file_index_to_files.rb index c18d09f1..b6286934 100644 --- a/db/migrate/20150421074734_add_file_index_to_files.rb +++ b/db/migrate/20150421074734_add_file_index_to_files.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class AddFileIndexToFiles < ActiveRecord::Migration[4.2] def change - add_index(:files, [:context_id, :context_type]) + add_index(:files, %i[context_id context_type]) end end diff --git a/db/migrate/20150818141554_add_user_type_to_request_for_comments.rb b/db/migrate/20150818141554_add_user_type_to_request_for_comments.rb index 86eff763..ebc2c8b4 100644 --- a/db/migrate/20150818141554_add_user_type_to_request_for_comments.rb +++ b/db/migrate/20150818141554_add_user_type_to_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserTypeToRequestForComments < ActiveRecord::Migration[4.2] def change add_column :request_for_comments, :user_type, :string diff --git a/db/migrate/20150818142251_correct_column_names.rb b/db/migrate/20150818142251_correct_column_names.rb index 0fcb2d70..58a49af8 100644 --- a/db/migrate/20150818142251_correct_column_names.rb +++ b/db/migrate/20150818142251_correct_column_names.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class CorrectColumnNames < ActiveRecord::Migration[4.2] def change - rename_column :request_for_comments, :requestorid, :requestor_user_id - rename_column :request_for_comments, :exerciseid, :exercise_id - rename_column :request_for_comments, :fileid, :file_id + rename_column :request_for_comments, :requestorid, :requestor_user_id + rename_column :request_for_comments, :exerciseid, :exercise_id + rename_column :request_for_comments, :fileid, :file_id end end diff --git a/db/migrate/20150903152727_remove_requestor_from_request_for_comments.rb b/db/migrate/20150903152727_remove_requestor_from_request_for_comments.rb index 134649bf..d371135d 100644 --- a/db/migrate/20150903152727_remove_requestor_from_request_for_comments.rb +++ b/db/migrate/20150903152727_remove_requestor_from_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveRequestorFromRequestForComments < ActiveRecord::Migration[4.2] def change rename_column :request_for_comments, :requestor_user_id, :user_id diff --git a/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb b/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb index fce56b0a..a32f7a83 100644 --- a/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb +++ b/db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddHideFileTreeToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :hide_file_tree, :boolean diff --git a/db/migrate/20160204094409_create_code_harbor_links.rb b/db/migrate/20160204094409_create_code_harbor_links.rb index f159362b..4e9bcf3e 100644 --- a/db/migrate/20160204094409_create_code_harbor_links.rb +++ b/db/migrate/20160204094409_create_code_harbor_links.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateCodeHarborLinks < ActiveRecord::Migration[4.2] def change create_table :code_harbor_links do |t| diff --git a/db/migrate/20160204111716_add_user_to_code_harbor_link.rb b/db/migrate/20160204111716_add_user_to_code_harbor_link.rb index 0bf4b575..3966bda8 100644 --- a/db/migrate/20160204111716_add_user_to_code_harbor_link.rb +++ b/db/migrate/20160204111716_add_user_to_code_harbor_link.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class AddUserToCodeHarborLink < ActiveRecord::Migration[4.2] def change - add_reference :code_harbor_links, :user, polymorphic: true, index: true + add_reference :code_harbor_links, :user, polymorphic: true, index: true end end diff --git a/db/migrate/20160302133540_create_testruns.rb b/db/migrate/20160302133540_create_testruns.rb index fa622cfe..c791de6a 100644 --- a/db/migrate/20160302133540_create_testruns.rb +++ b/db/migrate/20160302133540_create_testruns.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateTestruns < ActiveRecord::Migration[4.2] def change create_table :testruns do |t| diff --git a/db/migrate/20160426114951_add_question_to_request_for_comments.rb b/db/migrate/20160426114951_add_question_to_request_for_comments.rb index 31c3f60e..2ac75085 100644 --- a/db/migrate/20160426114951_add_question_to_request_for_comments.rb +++ b/db/migrate/20160426114951_add_question_to_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddQuestionToRequestForComments < ActiveRecord::Migration[4.2] def change add_column :request_for_comments, :question, :text diff --git a/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb b/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb index 37df9904..6206c404 100644 --- a/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb +++ b/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddAllowFileCreationToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :allow_file_creation, :boolean diff --git a/db/migrate/20160512131539_change_comment_text_attribute_to_text_datatype.rb b/db/migrate/20160512131539_change_comment_text_attribute_to_text_datatype.rb index 148ec9ea..b00ea047 100644 --- a/db/migrate/20160512131539_change_comment_text_attribute_to_text_datatype.rb +++ b/db/migrate/20160512131539_change_comment_text_attribute_to_text_datatype.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + class ChangeCommentTextAttributeToTextDatatype < ActiveRecord::Migration[4.2] def up change_column :comments, :text, :text end + def down # This might cause trouble if you have strings longer # than 255 characters. diff --git a/db/migrate/20160609185708_create_file_templates.rb b/db/migrate/20160609185708_create_file_templates.rb index aa111443..83f161e0 100644 --- a/db/migrate/20160609185708_create_file_templates.rb +++ b/db/migrate/20160609185708_create_file_templates.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateFileTemplates < ActiveRecord::Migration[4.2] def change create_table :file_templates do |t| diff --git a/db/migrate/20160610111602_add_file_template_to_file.rb b/db/migrate/20160610111602_add_file_template_to_file.rb index dbcc83e5..7035f4a9 100644 --- a/db/migrate/20160610111602_add_file_template_to_file.rb +++ b/db/migrate/20160610111602_add_file_template_to_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddFileTemplateToFile < ActiveRecord::Migration[4.2] def change add_reference :files, :file_template diff --git a/db/migrate/20160624130951_add_solved_to_request_for_comments.rb b/db/migrate/20160624130951_add_solved_to_request_for_comments.rb index bfa1e2a1..dbd8dea4 100644 --- a/db/migrate/20160624130951_add_solved_to_request_for_comments.rb +++ b/db/migrate/20160624130951_add_solved_to_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddSolvedToRequestForComments < ActiveRecord::Migration[4.2] def change add_column :request_for_comments, :solved, :boolean diff --git a/db/migrate/20160630154310_add_submission_to_request_for_comments.rb b/db/migrate/20160630154310_add_submission_to_request_for_comments.rb index 4e2e1494..65dac9f1 100644 --- a/db/migrate/20160630154310_add_submission_to_request_for_comments.rb +++ b/db/migrate/20160630154310_add_submission_to_request_for_comments.rb @@ -1,33 +1,33 @@ +# frozen_string_literal: true + class AddSubmissionToRequestForComments < ActiveRecord::Migration[4.2] def change add_reference :request_for_comments, :submission end end -=begin -We issued the following on the database to add the submission_ids for existing entries - -UPDATE request_for_comments -SET submission_id = sub.submission_id_external -FROM -(SELECT s.id AS submission_id_external, - rfc.id AS rfc_id, - s.created_at AS submission_created_at, - rfc.created_at AS rfc_created_at -FROM submissions s, - request_for_comments rfc -WHERE s.user_id = rfc.user_id -AND s.exercise_id = rfc.exercise_id -AND rfc.created_at + interval '2 hours' > s.created_at -AND s.created_at = - (SELECT MAX(created_at) - FROM submissions - WHERE exercise_id = s.exercise_id - AND user_id = s.user_id - AND rfc.created_at + interval '2 hours' > created_at - GROUP BY s.exercise_id, - s.user_id)) as sub -WHERE id = sub.rfc_id -AND submission_id IS NULL; - -=end +# We issued the following on the database to add the submission_ids for existing entries +# +# UPDATE request_for_comments +# SET submission_id = sub.submission_id_external +# FROM +# (SELECT s.id AS submission_id_external, +# rfc.id AS rfc_id, +# s.created_at AS submission_created_at, +# rfc.created_at AS rfc_created_at +# FROM submissions s, +# request_for_comments rfc +# WHERE s.user_id = rfc.user_id +# AND s.exercise_id = rfc.exercise_id +# AND rfc.created_at + interval '2 hours' > s.created_at +# AND s.created_at = +# (SELECT MAX(created_at) +# FROM submissions +# WHERE exercise_id = s.exercise_id +# AND user_id = s.user_id +# AND rfc.created_at + interval '2 hours' > created_at +# GROUP BY s.exercise_id, +# s.user_id)) as sub +# WHERE id = sub.rfc_id +# AND submission_id IS NULL; +# diff --git a/db/migrate/20160701092140_remove_requested_at_from_request_for_comments.rb b/db/migrate/20160701092140_remove_requested_at_from_request_for_comments.rb index 75f2236a..23a33e1e 100644 --- a/db/migrate/20160701092140_remove_requested_at_from_request_for_comments.rb +++ b/db/migrate/20160701092140_remove_requested_at_from_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveRequestedAtFromRequestForComments < ActiveRecord::Migration[4.2] def change remove_column :request_for_comments, :requested_at diff --git a/db/migrate/20160704143402_remove_teams.rb b/db/migrate/20160704143402_remove_teams.rb index f093a4f6..f638a41f 100644 --- a/db/migrate/20160704143402_remove_teams.rb +++ b/db/migrate/20160704143402_remove_teams.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveTeams < ActiveRecord::Migration[4.2] def change remove_reference :exercises, :team diff --git a/db/migrate/20160907123009_add_allow_auto_completion_to_exercises.rb b/db/migrate/20160907123009_add_allow_auto_completion_to_exercises.rb index 03ce4757..c99632da 100644 --- a/db/migrate/20160907123009_add_allow_auto_completion_to_exercises.rb +++ b/db/migrate/20160907123009_add_allow_auto_completion_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddAllowAutoCompletionToExercises < ActiveRecord::Migration[4.2] def change add_column :exercises, :allow_auto_completion, :boolean, default: false diff --git a/db/migrate/20170112151637_create_lti_parameters.rb b/db/migrate/20170112151637_create_lti_parameters.rb index b6370387..d3324786 100644 --- a/db/migrate/20170112151637_create_lti_parameters.rb +++ b/db/migrate/20170112151637_create_lti_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateLtiParameters < ActiveRecord::Migration[4.2] def change create_table :lti_parameters do |t| @@ -8,4 +10,4 @@ class CreateLtiParameters < ActiveRecord::Migration[4.2] t.timestamps end end -end \ No newline at end of file +end diff --git a/db/migrate/20170202170437_create_remote_evaluation_mappings.rb b/db/migrate/20170202170437_create_remote_evaluation_mappings.rb index f04cc2ed..12ba6980 100644 --- a/db/migrate/20170202170437_create_remote_evaluation_mappings.rb +++ b/db/migrate/20170202170437_create_remote_evaluation_mappings.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + class CreateRemoteEvaluationMappings < ActiveRecord::Migration[4.2] def change create_table :remote_evaluation_mappings do |t| - t.integer "user_id", null: false - t.integer "exercise_id", null: false - t.string "validation_token", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.integer 'user_id', null: false + t.integer 'exercise_id', null: false + t.string 'validation_token', null: false + t.datetime 'created_at' + t.datetime 'updated_at' end end -end \ No newline at end of file +end diff --git a/db/migrate/20170205163247_create_exercise_collections.rb b/db/migrate/20170205163247_create_exercise_collections.rb index 157a96f8..88abf8c3 100644 --- a/db/migrate/20170205163247_create_exercise_collections.rb +++ b/db/migrate/20170205163247_create_exercise_collections.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateExerciseCollections < ActiveRecord::Migration[4.2] def change create_table :exercise_collections do |t| @@ -9,6 +11,5 @@ class CreateExerciseCollections < ActiveRecord::Migration[4.2] t.belongs_to :exercise_collection, index: true t.belongs_to :exercise, index: true end - end end diff --git a/db/migrate/20170205165450_create_proxy_exercises.rb b/db/migrate/20170205165450_create_proxy_exercises.rb index 7bb9d8cc..52ef1a55 100644 --- a/db/migrate/20170205165450_create_proxy_exercises.rb +++ b/db/migrate/20170205165450_create_proxy_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateProxyExercises < ActiveRecord::Migration[4.2] def change create_table :proxy_exercises do |t| diff --git a/db/migrate/20170205210357_create_interventions.rb b/db/migrate/20170205210357_create_interventions.rb index b8eb3132..97f739b4 100644 --- a/db/migrate/20170205210357_create_interventions.rb +++ b/db/migrate/20170205210357_create_interventions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateInterventions < ActiveRecord::Migration[4.2] def change create_table :user_exercise_interventions do |t| @@ -16,8 +18,5 @@ class CreateInterventions < ActiveRecord::Migration[4.2] end Intervention.createDefaultInterventions - end - - end diff --git a/db/migrate/20170206141210_add_tags.rb b/db/migrate/20170206141210_add_tags.rb index 77d048af..bdb72e48 100644 --- a/db/migrate/20170206141210_add_tags.rb +++ b/db/migrate/20170206141210_add_tags.rb @@ -1,5 +1,6 @@ -class AddTags < ActiveRecord::Migration[4.2] +# frozen_string_literal: true +class AddTags < ActiveRecord::Migration[4.2] def change add_column :exercises, :expected_worktime_seconds, :integer, default: 60 add_column :exercises, :expected_difficulty, :integer, default: 1 @@ -15,5 +16,4 @@ class AddTags < ActiveRecord::Migration[4.2] t.integer :factor, default: 1 end end - end diff --git a/db/migrate/20170206152503_add_user_feedback.rb b/db/migrate/20170206152503_add_user_feedback.rb index c860e630..e17ad2e9 100644 --- a/db/migrate/20170206152503_add_user_feedback.rb +++ b/db/migrate/20170206152503_add_user_feedback.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserFeedback < ActiveRecord::Migration[4.2] def change create_table :user_exercise_feedbacks do |t| diff --git a/db/migrate/20170228165741_add_search.rb b/db/migrate/20170228165741_add_search.rb index c7168cc6..833a4cb4 100644 --- a/db/migrate/20170228165741_add_search.rb +++ b/db/migrate/20170228165741_add_search.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddSearch < ActiveRecord::Migration[4.2] def change create_table :searches do |t| diff --git a/db/migrate/20170321150454_add_reason_to_user_proxy_exercise_exercise.rb b/db/migrate/20170321150454_add_reason_to_user_proxy_exercise_exercise.rb index f257dcf3..a6a4e858 100644 --- a/db/migrate/20170321150454_add_reason_to_user_proxy_exercise_exercise.rb +++ b/db/migrate/20170321150454_add_reason_to_user_proxy_exercise_exercise.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddReasonToUserProxyExerciseExercise < ActiveRecord::Migration[4.2] def change change_table :user_proxy_exercise_exercises do |t| diff --git a/db/migrate/20170323130756_add_index_to_submissions.rb b/db/migrate/20170323130756_add_index_to_submissions.rb index 128f43bb..36200f60 100644 --- a/db/migrate/20170323130756_add_index_to_submissions.rb +++ b/db/migrate/20170323130756_add_index_to_submissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndexToSubmissions < ActiveRecord::Migration[4.2] def change add_index :submissions, :exercise_id diff --git a/db/migrate/20170403162848_set_default_for_request_for_comment_solved.rb b/db/migrate/20170403162848_set_default_for_request_for_comment_solved.rb index d952e51a..75e88a53 100644 --- a/db/migrate/20170403162848_set_default_for_request_for_comment_solved.rb +++ b/db/migrate/20170403162848_set_default_for_request_for_comment_solved.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class SetDefaultForRequestForCommentSolved < ActiveRecord::Migration[4.2] def change change_column_default :request_for_comments, :solved, false RequestForComment.where(solved: nil).update_all(solved: false) end -end \ No newline at end of file +end diff --git a/db/migrate/20170411090543_improve_user_feedback.rb b/db/migrate/20170411090543_improve_user_feedback.rb index bf89aafc..c9ab707a 100644 --- a/db/migrate/20170411090543_improve_user_feedback.rb +++ b/db/migrate/20170411090543_improve_user_feedback.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ImproveUserFeedback < ActiveRecord::Migration[4.2] def change add_column :user_exercise_feedbacks, :user_estimated_worktime, :integer diff --git a/db/migrate/20170608141612_add_thank_you_note_to_request_for_comments.rb b/db/migrate/20170608141612_add_thank_you_note_to_request_for_comments.rb index b75f3589..9f239d4e 100644 --- a/db/migrate/20170608141612_add_thank_you_note_to_request_for_comments.rb +++ b/db/migrate/20170608141612_add_thank_you_note_to_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddThankYouNoteToRequestForComments < ActiveRecord::Migration[4.2] def change add_column :request_for_comments, :thank_you_note, :text diff --git a/db/migrate/20170703075832_create_error_templates.rb b/db/migrate/20170703075832_create_error_templates.rb index 5556f4ea..59134f42 100644 --- a/db/migrate/20170703075832_create_error_templates.rb +++ b/db/migrate/20170703075832_create_error_templates.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateErrorTemplates < ActiveRecord::Migration[4.2] def change create_table :error_templates do |t| diff --git a/db/migrate/20170703075959_create_error_template_attributes.rb b/db/migrate/20170703075959_create_error_template_attributes.rb index aa733b09..06ca5849 100644 --- a/db/migrate/20170703075959_create_error_template_attributes.rb +++ b/db/migrate/20170703075959_create_error_template_attributes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateErrorTemplateAttributes < ActiveRecord::Migration[4.2] def change create_table :error_template_attributes do |t| diff --git a/db/migrate/20170703080205_create_structured_errors.rb b/db/migrate/20170703080205_create_structured_errors.rb index 111923ca..e6430396 100644 --- a/db/migrate/20170703080205_create_structured_errors.rb +++ b/db/migrate/20170703080205_create_structured_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateStructuredErrors < ActiveRecord::Migration[4.2] def change create_table :structured_errors do |t| diff --git a/db/migrate/20170703080355_create_structured_error_attributes.rb b/db/migrate/20170703080355_create_structured_error_attributes.rb index 81bc1d19..7ad3f469 100644 --- a/db/migrate/20170703080355_create_structured_error_attributes.rb +++ b/db/migrate/20170703080355_create_structured_error_attributes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateStructuredErrorAttributes < ActiveRecord::Migration[4.2] def change create_table :structured_error_attributes do |t| diff --git a/db/migrate/20170711170456_add_description_and_hint_to_error_template.rb b/db/migrate/20170711170456_add_description_and_hint_to_error_template.rb index 11d1985f..223948a3 100644 --- a/db/migrate/20170711170456_add_description_and_hint_to_error_template.rb +++ b/db/migrate/20170711170456_add_description_and_hint_to_error_template.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddDescriptionAndHintToErrorTemplate < ActiveRecord::Migration[4.2] def change add_column :error_templates, :description, :text diff --git a/db/migrate/20170711170928_change_error_template_attribute_relationship_to_n_to_m.rb b/db/migrate/20170711170928_change_error_template_attribute_relationship_to_n_to_m.rb index 32f3a304..0cc7feaf 100644 --- a/db/migrate/20170711170928_change_error_template_attribute_relationship_to_n_to_m.rb +++ b/db/migrate/20170711170928_change_error_template_attribute_relationship_to_n_to_m.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ChangeErrorTemplateAttributeRelationshipToNToM < ActiveRecord::Migration[4.2] def change remove_belongs_to :error_template_attributes, :error_template diff --git a/db/migrate/20170719133351_add_match_to_structured_error_attribute.rb b/db/migrate/20170719133351_add_match_to_structured_error_attribute.rb index 51d868ab..bfcfb167 100644 --- a/db/migrate/20170719133351_add_match_to_structured_error_attribute.rb +++ b/db/migrate/20170719133351_add_match_to_structured_error_attribute.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddMatchToStructuredErrorAttribute < ActiveRecord::Migration[4.2] def change add_column :structured_error_attributes, :match, :boolean diff --git a/db/migrate/20170830083601_add_cause_to_testruns.rb b/db/migrate/20170830083601_add_cause_to_testruns.rb index d737c029..2fea8d54 100644 --- a/db/migrate/20170830083601_add_cause_to_testruns.rb +++ b/db/migrate/20170830083601_add_cause_to_testruns.rb @@ -1,15 +1,17 @@ +# frozen_string_literal: true + class AddCauseToTestruns < ActiveRecord::Migration[4.2] def up add_column :testruns, :cause, :string Testrun.reset_column_information - Testrun.all.each{ |testrun| - if(testrun.submission.nil?) + Testrun.all.each do |testrun| + if testrun.submission.nil? say_with_time "#{testrun.id} has no submission" do end else testrun.cause = testrun.submission.cause testrun.save end - } + end end def down diff --git a/db/migrate/20170906124500_create_subscriptions.rb b/db/migrate/20170906124500_create_subscriptions.rb index 83adc2d7..6e4464e5 100644 --- a/db/migrate/20170906124500_create_subscriptions.rb +++ b/db/migrate/20170906124500_create_subscriptions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateSubscriptions < ActiveRecord::Migration[4.2] def change create_table :subscriptions do |t| diff --git a/db/migrate/20170913054203_rename_subscription_type.rb b/db/migrate/20170913054203_rename_subscription_type.rb index e380bb07..c061da61 100644 --- a/db/migrate/20170913054203_rename_subscription_type.rb +++ b/db/migrate/20170913054203_rename_subscription_type.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RenameSubscriptionType < ActiveRecord::Migration[4.2] def change rename_column :subscriptions, :type, :subscription_type diff --git a/db/migrate/20170920145852_add_deleted_to_subscription.rb b/db/migrate/20170920145852_add_deleted_to_subscription.rb index 6c071b3a..0e1fdc36 100644 --- a/db/migrate/20170920145852_add_deleted_to_subscription.rb +++ b/db/migrate/20170920145852_add_deleted_to_subscription.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddDeletedToSubscription < ActiveRecord::Migration[4.2] def change add_column :subscriptions, :deleted, :boolean diff --git a/db/migrate/20171002131135_remove_expected_working_time.rb b/db/migrate/20171002131135_remove_expected_working_time.rb index b9d6edd3..29f77102 100644 --- a/db/migrate/20171002131135_remove_expected_working_time.rb +++ b/db/migrate/20171002131135_remove_expected_working_time.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveExpectedWorkingTime < ActiveRecord::Migration[4.2] def change remove_column :exercises, :expected_worktime_seconds diff --git a/db/migrate/20171115121125_add_anomaly_detection_flag_to_exercise_collection.rb b/db/migrate/20171115121125_add_anomaly_detection_flag_to_exercise_collection.rb index d9816951..93cf328c 100644 --- a/db/migrate/20171115121125_add_anomaly_detection_flag_to_exercise_collection.rb +++ b/db/migrate/20171115121125_add_anomaly_detection_flag_to_exercise_collection.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class AddAnomalyDetectionFlagToExerciseCollection < ActiveRecord::Migration[4.2] def change - add_column :exercise_collections, :use_anomaly_detection, :boolean, :default => false + add_column :exercise_collections, :use_anomaly_detection, :boolean, default: false end end diff --git a/db/migrate/20171120153705_add_timestamps_to_user_exercise_feedbacks.rb b/db/migrate/20171120153705_add_timestamps_to_user_exercise_feedbacks.rb index 7f3bb0c7..1541497d 100644 --- a/db/migrate/20171120153705_add_timestamps_to_user_exercise_feedbacks.rb +++ b/db/migrate/20171120153705_add_timestamps_to_user_exercise_feedbacks.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class AddTimestampsToUserExerciseFeedbacks < ActiveRecord::Migration[4.2] def up - add_column :user_exercise_feedbacks, :created_at, :datetime, null: false, default: Time.now - add_column :user_exercise_feedbacks, :updated_at, :datetime, null: false, default: Time.now + add_column :user_exercise_feedbacks, :created_at, :datetime, null: false, default: Time.zone.now + add_column :user_exercise_feedbacks, :updated_at, :datetime, null: false, default: Time.zone.now end end diff --git a/db/migrate/20171122124222_add_index_to_exercises.rb b/db/migrate/20171122124222_add_index_to_exercises.rb index d02e13bd..e1105a3b 100644 --- a/db/migrate/20171122124222_add_index_to_exercises.rb +++ b/db/migrate/20171122124222_add_index_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndexToExercises < ActiveRecord::Migration[4.2] def change add_index :exercises, :id diff --git a/db/migrate/20171210172208_add_user_to_exercise_collection.rb b/db/migrate/20171210172208_add_user_to_exercise_collection.rb index 6b63120a..af360737 100644 --- a/db/migrate/20171210172208_add_user_to_exercise_collection.rb +++ b/db/migrate/20171210172208_add_user_to_exercise_collection.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class AddUserToExerciseCollection < ActiveRecord::Migration[4.2] def change - add_reference :exercise_collections, :user, polymorphic: true, index: true + add_reference :exercise_collections, :user, polymorphic: true, index: true end end diff --git a/db/migrate/20180130101645_add_submission_to_structured_errors.rb b/db/migrate/20180130101645_add_submission_to_structured_errors.rb index 0f6ccec6..7980cc36 100644 --- a/db/migrate/20180130101645_add_submission_to_structured_errors.rb +++ b/db/migrate/20180130101645_add_submission_to_structured_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddSubmissionToStructuredErrors < ActiveRecord::Migration[4.2] def change add_reference :structured_errors, :submission, index: true diff --git a/db/migrate/20180130172021_add_reached_full_score_to_request_for_comment.rb b/db/migrate/20180130172021_add_reached_full_score_to_request_for_comment.rb index 651ff184..ffb60187 100644 --- a/db/migrate/20180130172021_add_reached_full_score_to_request_for_comment.rb +++ b/db/migrate/20180130172021_add_reached_full_score_to_request_for_comment.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + class AddReachedFullScoreToRequestForComment < ActiveRecord::Migration[4.2] def up add_column :request_for_comments, :full_score_reached, :boolean, default: false - RequestForComment.find_each { |rfc| - if rfc.submission.present? and rfc.submission.exercise.has_user_solved(rfc.user) + RequestForComment.find_each do |rfc| + if rfc.submission.present? && rfc.submission.exercise.has_user_solved(rfc.user) rfc.full_score_reached = true rfc.save end - } + end end def down diff --git a/db/migrate/20180202132034_add_times_featured_to_request_for_comments.rb b/db/migrate/20180202132034_add_times_featured_to_request_for_comments.rb index 53194328..58484970 100644 --- a/db/migrate/20180202132034_add_times_featured_to_request_for_comments.rb +++ b/db/migrate/20180202132034_add_times_featured_to_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddTimesFeaturedToRequestForComments < ActiveRecord::Migration[4.2] def change add_column :request_for_comments, :times_featured, :integer, default: 0 diff --git a/db/migrate/20180222145909_fix_timestamps_on_feedback.rb b/db/migrate/20180222145909_fix_timestamps_on_feedback.rb index 32909752..af6f0368 100644 --- a/db/migrate/20180222145909_fix_timestamps_on_feedback.rb +++ b/db/migrate/20180222145909_fix_timestamps_on_feedback.rb @@ -1,10 +1,10 @@ +# frozen_string_literal: true + class FixTimestampsOnFeedback < ActiveRecord::Migration[4.2] def up change_column_default(:user_exercise_feedbacks, :created_at, nil) change_column_default(:user_exercise_feedbacks, :updated_at, nil) end - def down - - end + def down; end end diff --git a/db/migrate/20180226131340_create_anomaly_notifications.rb b/db/migrate/20180226131340_create_anomaly_notifications.rb index c7f4e104..1cfe9db4 100644 --- a/db/migrate/20180226131340_create_anomaly_notifications.rb +++ b/db/migrate/20180226131340_create_anomaly_notifications.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateAnomalyNotifications < ActiveRecord::Migration[4.2] def change create_table :anomaly_notifications do |t| diff --git a/db/migrate/20180515110030_remove_file_id_from_structured_errors.rb b/db/migrate/20180515110030_remove_file_id_from_structured_errors.rb index c0cd23d1..e8b45138 100644 --- a/db/migrate/20180515110030_remove_file_id_from_structured_errors.rb +++ b/db/migrate/20180515110030_remove_file_id_from_structured_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RemoveFileIdFromStructuredErrors < ActiveRecord::Migration[4.2] def change remove_column :structured_errors, :file_id diff --git a/db/migrate/20180703125302_create_exercise_collection_items.rb b/db/migrate/20180703125302_create_exercise_collection_items.rb index aa172c62..ea63a8b6 100644 --- a/db/migrate/20180703125302_create_exercise_collection_items.rb +++ b/db/migrate/20180703125302_create_exercise_collection_items.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateExerciseCollectionItems < ActiveRecord::Migration[4.2] def up rename_table :exercise_collections_exercises, :exercise_collection_items diff --git a/db/migrate/20180814145059_create_events.rb b/db/migrate/20180814145059_create_events.rb index 5d1eb5e1..02c19ec5 100644 --- a/db/migrate/20180814145059_create_events.rb +++ b/db/migrate/20180814145059_create_events.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateEvents < ActiveRecord::Migration[4.2] def change create_table :events do |t| diff --git a/db/migrate/20180814154055_rename_events_type_to_category.rb b/db/migrate/20180814154055_rename_events_type_to_category.rb index 9bfe9d0b..f2b83d0a 100644 --- a/db/migrate/20180814154055_rename_events_type_to_category.rb +++ b/db/migrate/20180814154055_rename_events_type_to_category.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RenameEventsTypeToCategory < ActiveRecord::Migration[4.2] def change rename_column :events, :type, :category diff --git a/db/migrate/20180815115351_remove_event_indices.rb b/db/migrate/20180815115351_remove_event_indices.rb index fdf7959d..c8cff77b 100644 --- a/db/migrate/20180815115351_remove_event_indices.rb +++ b/db/migrate/20180815115351_remove_event_indices.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class RemoveEventIndices < ActiveRecord::Migration[4.2] def change - remove_index :events, [:user_type, :user_id] + remove_index :events, %i[user_type user_id] remove_index :events, :exercise_id remove_index :events, :file_id end diff --git a/db/migrate/20180823135317_add_index_for_testrun_submission_id.rb b/db/migrate/20180823135317_add_index_for_testrun_submission_id.rb index 8394660c..f40eedda 100644 --- a/db/migrate/20180823135317_add_index_for_testrun_submission_id.rb +++ b/db/migrate/20180823135317_add_index_for_testrun_submission_id.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndexForTestrunSubmissionId < ActiveRecord::Migration[4.2] def change add_index :testruns, :submission_id diff --git a/db/migrate/20180904115948_add_index_for_lti_parameters_external_user_id.rb b/db/migrate/20180904115948_add_index_for_lti_parameters_external_user_id.rb index e18f9c73..522c2e58 100644 --- a/db/migrate/20180904115948_add_index_for_lti_parameters_external_user_id.rb +++ b/db/migrate/20180904115948_add_index_for_lti_parameters_external_user_id.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndexForLtiParametersExternalUserId < ActiveRecord::Migration[4.2] def change add_index :lti_parameters, :external_users_id diff --git a/db/migrate/20181116143743_add_role_to_external_users.rb b/db/migrate/20181116143743_add_role_to_external_users.rb index 5b4d7066..a6589817 100644 --- a/db/migrate/20181116143743_add_role_to_external_users.rb +++ b/db/migrate/20181116143743_add_role_to_external_users.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddRoleToExternalUsers < ActiveRecord::Migration[5.2] def change add_column :external_users, :role, :string, default: 'learner', null: false diff --git a/db/migrate/20181119161514_add_user_to_proxy_exercise.rb b/db/migrate/20181119161514_add_user_to_proxy_exercise.rb index 1d9f3192..c19ff639 100644 --- a/db/migrate/20181119161514_add_user_to_proxy_exercise.rb +++ b/db/migrate/20181119161514_add_user_to_proxy_exercise.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class AddUserToProxyExercise < ActiveRecord::Migration[5.2] def change - add_reference :proxy_exercises, :user, polymorphic: true, index: true + add_reference :proxy_exercises, :user, polymorphic: true, index: true add_column :proxy_exercises, :public, :boolean, null: false, default: false internal_user = InternalUser.find_by(id: 46) || InternalUser.first diff --git a/db/migrate/20181122084546_create_study_groups.rb b/db/migrate/20181122084546_create_study_groups.rb index 63919d75..82895073 100644 --- a/db/migrate/20181122084546_create_study_groups.rb +++ b/db/migrate/20181122084546_create_study_groups.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateStudyGroups < ActiveRecord::Migration[5.2] def change create_table :study_groups do |t| @@ -7,7 +9,6 @@ class CreateStudyGroups < ActiveRecord::Migration[5.2] t.timestamps end - add_index :study_groups, [:external_id, :consumer_id], unique: true + add_index :study_groups, %i[external_id consumer_id], unique: true end end - diff --git a/db/migrate/20181122090243_create_study_group_memberships.rb b/db/migrate/20181122090243_create_study_group_memberships.rb index 8cb34dd3..4de5acf2 100644 --- a/db/migrate/20181122090243_create_study_group_memberships.rb +++ b/db/migrate/20181122090243_create_study_group_memberships.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateStudyGroupMemberships < ActiveRecord::Migration[5.2] def change create_table :study_group_memberships do |t| diff --git a/db/migrate/20181122090244_add_study_group_to_submission.rb b/db/migrate/20181122090244_add_study_group_to_submission.rb index 94cd30d6..ac8b86f4 100644 --- a/db/migrate/20181122090244_add_study_group_to_submission.rb +++ b/db/migrate/20181122090244_add_study_group_to_submission.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddStudyGroupToSubmission < ActiveRecord::Migration[5.2] def change add_reference :submissions, :study_group, index: true, null: true, foreign_key: true diff --git a/db/migrate/20181126163428_add_user_type_to_remote_evaluation_mappings.rb b/db/migrate/20181126163428_add_user_type_to_remote_evaluation_mappings.rb index 0ad50d0f..6a1ee2ba 100644 --- a/db/migrate/20181126163428_add_user_type_to_remote_evaluation_mappings.rb +++ b/db/migrate/20181126163428_add_user_type_to_remote_evaluation_mappings.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUserTypeToRemoteEvaluationMappings < ActiveRecord::Migration[5.2] def change add_column :remote_evaluation_mappings, :user_type, :string diff --git a/db/migrate/20181127160857_drop_hints.rb b/db/migrate/20181127160857_drop_hints.rb index 83f0905e..ebb58797 100644 --- a/db/migrate/20181127160857_drop_hints.rb +++ b/db/migrate/20181127160857_drop_hints.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DropHints < ActiveRecord::Migration[5.2] def change drop_table :hints diff --git a/db/migrate/20181129093207_drop_errors.rb b/db/migrate/20181129093207_drop_errors.rb index 2ec4e82c..e959351c 100644 --- a/db/migrate/20181129093207_drop_errors.rb +++ b/db/migrate/20181129093207_drop_errors.rb @@ -1,5 +1,6 @@ -class DropErrors < ActiveRecord::Migration[5.2] +# frozen_string_literal: true +class DropErrors < ActiveRecord::Migration[5.2] # define old CodeOcean::Error module so that the migration works module CodeOcean class Error < ApplicationRecord @@ -15,21 +16,16 @@ class DropErrors < ActiveRecord::Migration[5.2] true end - def to_s - id.to_s - end + delegate :to_s, to: :id end end - - def change - puts 'Migrating CodeOcean::Errors to StructuredErrors using RegEx. This might take a (long) while but will return.' submissions_controller = SubmissionsController.new # Iterate only over those Errors containing a message and submission_id - CodeOcean::Error.where.not(message: [nil, ""]).where.not(submission_id: [nil, ""]).each do |error| + CodeOcean::Error.where.not(message: [nil, '']).where.not(submission_id: [nil, '']).each do |error| raw_output = error.message submission = Submission.find_by(id: error.submission_id) diff --git a/db/migrate/20190213131802_add_indices_for_request_for_comments.rb b/db/migrate/20190213131802_add_indices_for_request_for_comments.rb index f0c0dbd4..ab9deeca 100644 --- a/db/migrate/20190213131802_add_indices_for_request_for_comments.rb +++ b/db/migrate/20190213131802_add_indices_for_request_for_comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndicesForRequestForComments < ActiveRecord::Migration[5.2] def change add_index :request_for_comments, :submission_id diff --git a/db/migrate/20190818104802_rename_code_harbor_links_to_codeharbor_links.rb b/db/migrate/20190818104802_rename_code_harbor_links_to_codeharbor_links.rb index 5c7ba063..f8b879be 100644 --- a/db/migrate/20190818104802_rename_code_harbor_links_to_codeharbor_links.rb +++ b/db/migrate/20190818104802_rename_code_harbor_links_to_codeharbor_links.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RenameCodeHarborLinksToCodeharborLinks < ActiveRecord::Migration[5.2] def change rename_table :code_harbor_links, :codeharbor_links diff --git a/db/migrate/20190818104954_add_push_url_rename_oauth2token_in_codeharbor_links.rb b/db/migrate/20190818104954_add_push_url_rename_oauth2token_in_codeharbor_links.rb index 24dd9137..41106225 100644 --- a/db/migrate/20190818104954_add_push_url_rename_oauth2token_in_codeharbor_links.rb +++ b/db/migrate/20190818104954_add_push_url_rename_oauth2token_in_codeharbor_links.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddPushUrlRenameOauth2tokenInCodeharborLinks < ActiveRecord::Migration[5.2] def change add_column :codeharbor_links, :push_url, :string diff --git a/db/migrate/20190830142809_add_uuid_to_exercise.rb b/db/migrate/20190830142809_add_uuid_to_exercise.rb index 4dfa6e5c..bd65f8b1 100644 --- a/db/migrate/20190830142809_add_uuid_to_exercise.rb +++ b/db/migrate/20190830142809_add_uuid_to_exercise.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUuidToExercise < ActiveRecord::Migration[5.2] def change add_column :exercises, :uuid, :uuid diff --git a/db/migrate/20191008163045_add_unpublished_to_exercise.rb b/db/migrate/20191008163045_add_unpublished_to_exercise.rb index 56bc215d..74a09ed0 100644 --- a/db/migrate/20191008163045_add_unpublished_to_exercise.rb +++ b/db/migrate/20191008163045_add_unpublished_to_exercise.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddUnpublishedToExercise < ActiveRecord::Migration[5.2] def change add_column :exercises, :unpublished, :boolean, default: false diff --git a/db/migrate/20200326115249_add_container_execution_time_to_testruns.rb b/db/migrate/20200326115249_add_container_execution_time_to_testruns.rb index d04b041d..e4ead4f1 100644 --- a/db/migrate/20200326115249_add_container_execution_time_to_testruns.rb +++ b/db/migrate/20200326115249_add_container_execution_time_to_testruns.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddContainerExecutionTimeToTestruns < ActiveRecord::Migration[5.2] def change add_column :testruns, :container_execution_time, :interval diff --git a/db/migrate/20200506093054_add_deadline_to_exercises.rb b/db/migrate/20200506093054_add_deadline_to_exercises.rb index 39526198..b4627966 100644 --- a/db/migrate/20200506093054_add_deadline_to_exercises.rb +++ b/db/migrate/20200506093054_add_deadline_to_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddDeadlineToExercises < ActiveRecord::Migration[5.2] def change add_column :exercises, :submission_deadline, :datetime, null: true, default: nil diff --git a/db/migrate/20201019090123_add_normalized_score_and_submission_to_user_exercise_feedback.rb b/db/migrate/20201019090123_add_normalized_score_and_submission_to_user_exercise_feedback.rb index cfa13bb0..ef06fce1 100644 --- a/db/migrate/20201019090123_add_normalized_score_and_submission_to_user_exercise_feedback.rb +++ b/db/migrate/20201019090123_add_normalized_score_and_submission_to_user_exercise_feedback.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddNormalizedScoreAndSubmissionToUserExerciseFeedback < ActiveRecord::Migration[5.2] def change add_column :user_exercise_feedbacks, :normalized_score, :float @@ -7,9 +9,9 @@ class AddNormalizedScoreAndSubmissionToUserExerciseFeedback < ActiveRecord::Migr ActiveRecord::Base.record_timestamps = false UserExerciseFeedback.all.find_each do |uef| latest_submission = Submission - .where(user_id: uef.user_id, user_type: uef.user_type, exercise_id: uef.exercise_id) - .where('created_at < ?', uef.updated_at) - .order(created_at: :desc).first + .where(user_id: uef.user_id, user_type: uef.user_type, exercise_id: uef.exercise_id) + .where('created_at < ?', uef.updated_at) + .order(created_at: :desc).first # In the beginning, CodeOcean allowed feedback for exercises while viewing an RfC. As a RfC # might be opened by any registered learner, feedback for exercises was created by learners diff --git a/db/migrate/20201026184633_create_linter_checks.rb b/db/migrate/20201026184633_create_linter_checks.rb index 2e98473b..131ca360 100644 --- a/db/migrate/20201026184633_create_linter_checks.rb +++ b/db/migrate/20201026184633_create_linter_checks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateLinterChecks < ActiveRecord::Migration[5.2] def change create_table :linter_checks do |t| diff --git a/db/migrate/20201208095929_add_index_to_rfc.rb b/db/migrate/20201208095929_add_index_to_rfc.rb index 50bd4d40..92fb7feb 100644 --- a/db/migrate/20201208095929_add_index_to_rfc.rb +++ b/db/migrate/20201208095929_add_index_to_rfc.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class AddIndexToRfc < ActiveRecord::Migration[5.2] def change add_index(:request_for_comments, %i[user_id user_type created_at], - order: { user_id: :asc, user_type: :asc, created_at: :desc }, name: :index_rfc_on_user_and_created_at) + order: {user_id: :asc, user_type: :asc, created_at: :desc}, name: :index_rfc_on_user_and_created_at) end end diff --git a/db/migrate/20201208132844_add_index_to_unpublished_exercises.rb b/db/migrate/20201208132844_add_index_to_unpublished_exercises.rb index 02d9d06e..26bc578c 100644 --- a/db/migrate/20201208132844_add_index_to_unpublished_exercises.rb +++ b/db/migrate/20201208132844_add_index_to_unpublished_exercises.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndexToUnpublishedExercises < ActiveRecord::Migration[5.2] def change add_index(:exercises, :id, where: 'NOT unpublished', name: :index_unpublished_exercises) diff --git a/db/migrate/20201210113500_add_index_to_exercise_title.rb b/db/migrate/20201210113500_add_index_to_exercise_title.rb index 899ce712..f38be1ea 100644 --- a/db/migrate/20201210113500_add_index_to_exercise_title.rb +++ b/db/migrate/20201210113500_add_index_to_exercise_title.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class AddIndexToExerciseTitle < ActiveRecord::Migration[5.2] def change enable_extension 'pg_trgm' diff --git a/db/migrate/20210512133611_add_service_name_to_active_storage_blobs.active_storage.rb b/db/migrate/20210512133611_add_service_name_to_active_storage_blobs.active_storage.rb index 18ed13a5..cdfc14f9 100644 --- a/db/migrate/20210512133611_add_service_name_to_active_storage_blobs.active_storage.rb +++ b/db/migrate/20210512133611_add_service_name_to_active_storage_blobs.active_storage.rb @@ -1,16 +1,16 @@ +# frozen_string_literal: true + # This migration comes from active_storage (originally 20190112182829) class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] def up - if table_exists?(:active_storage_blobs) - unless column_exists?(:active_storage_blobs, :service_name) - add_column :active_storage_blobs, :service_name, :string + if table_exists?(:active_storage_blobs) && !column_exists?(:active_storage_blobs, :service_name) + add_column :active_storage_blobs, :service_name, :string - if configured_service = ActiveStorage::Blob.service.name - ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) - end - - change_column :active_storage_blobs, :service_name, :string, null: false + if configured_service = ActiveStorage::Blob.service.name + ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) end + + change_column :active_storage_blobs, :service_name, :string, null: false end end diff --git a/db/migrate/20210512133612_create_active_storage_variant_records.active_storage.rb b/db/migrate/20210512133612_create_active_storage_variant_records.active_storage.rb index f131b807..591dbca9 100644 --- a/db/migrate/20210512133612_create_active_storage_variant_records.active_storage.rb +++ b/db/migrate/20210512133612_create_active_storage_variant_records.active_storage.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This migration comes from active_storage (originally 20191206030411) class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] def change @@ -6,7 +8,7 @@ class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] t.belongs_to :blob, null: false, index: false t.string :variation_digest, null: false - t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true + t.index %i[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true t.foreign_key :active_storage_blobs, column: :blob_id end end diff --git a/db/seeds.rb b/db/seeds.rb index 5abc3927..37cfcd55 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + def find_factories_by_class(klass) FactoryBot.factories.select do |factory| factory.instance_variable_get(:@class_name).to_s == klass.to_s || factory.instance_variable_get(:@name) == klass.model_name.singular.to_sym @@ -6,7 +8,7 @@ end module ActiveRecord class Base - [:build, :create].each do |strategy| + %i[build create].each do |strategy| define_singleton_method("#{strategy}_factories") do |attributes = {}| find_factories_by_class(self).map(&:name).map do |factory_name| FactoryBot.send(strategy, factory_name, attributes) diff --git a/db/seeds/audio_video/index.html_spec.rb b/db/seeds/audio_video/index.html_spec.rb index b9459550..de9f4a15 100644 --- a/db/seeds/audio_video/index.html_spec.rb +++ b/db/seeds/audio_video/index.html_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rack/file' require 'capybara/rspec' diff --git a/db/seeds/development.rb b/db/seeds/development.rb index a6d4c17a..87ca3629 100644 --- a/db/seeds/development.rb +++ b/db/seeds/development.rb @@ -18,7 +18,7 @@ external_user = FactoryBot.create(:external_user) ExecutionEnvironment.create_factories user: admin # exercises -@exercises = find_factories_by_class(Exercise).map(&:name).map { |factory_name| [factory_name, FactoryBot.create(factory_name, user: teacher)] }.to_h +@exercises = find_factories_by_class(Exercise).map(&:name).index_with {|factory_name| FactoryBot.create(factory_name, user: teacher) } # file types FileType.create_factories diff --git a/db/seeds/fibonacci/exercise.rb b/db/seeds/fibonacci/exercise.rb index 81652f9d..e0a57e43 100644 --- a/db/seeds/fibonacci/exercise.rb +++ b/db/seeds/fibonacci/exercise.rb @@ -1,2 +1,3 @@ -def fibonacci(n) -end +# frozen_string_literal: true + +def fibonacci(n); end diff --git a/db/seeds/fibonacci/exercise_spec_1.rb b/db/seeds/fibonacci/exercise_spec_1.rb index d9937179..428c4537 100644 --- a/db/seeds/fibonacci/exercise_spec_1.rb +++ b/db/seeds/fibonacci/exercise_spec_1.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require './exercise' describe '#fibonacci' do diff --git a/db/seeds/fibonacci/exercise_spec_2.rb b/db/seeds/fibonacci/exercise_spec_2.rb index 97ba7936..974a18d4 100644 --- a/db/seeds/fibonacci/exercise_spec_2.rb +++ b/db/seeds/fibonacci/exercise_spec_2.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require './exercise' describe '#fibonacci' do it 'works recursively' do @n = 16 - expect(self).to receive(:fibonacci).and_call_original.at_least(@n ** 2).times + expect(self).to receive(:fibonacci).and_call_original.at_least(@n**2).times fibonacci(@n) end end diff --git a/db/seeds/fibonacci/exercise_spec_3.rb b/db/seeds/fibonacci/exercise_spec_3.rb index 68651314..82f6a72b 100644 --- a/db/seeds/fibonacci/exercise_spec_3.rb +++ b/db/seeds/fibonacci/exercise_spec_3.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require './exercise' require './reference' diff --git a/db/seeds/fibonacci/reference.rb b/db/seeds/fibonacci/reference.rb index 4b202328..6ee48352 100644 --- a/db/seeds/fibonacci/reference.rb +++ b/db/seeds/fibonacci/reference.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Reference def fibonacci(n) n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2) diff --git a/db/seeds/files/exercise.rb b/db/seeds/files/exercise.rb index 54198781..92a4ae34 100644 --- a/db/seeds/files/exercise.rb +++ b/db/seeds/files/exercise.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + SOURCE_FILENAME = 'data.txt' TARGET_FILENAME = 'copy.txt' diff --git a/db/seeds/files/exercise_spec.rb b/db/seeds/files/exercise_spec.rb index 878217ce..11f02fa7 100644 --- a/db/seeds/files/exercise_spec.rb +++ b/db/seeds/files/exercise_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require './exercise' describe '#write_to_file' do diff --git a/db/seeds/hello_world/exercise_spec.rb b/db/seeds/hello_world/exercise_spec.rb index e7e53ab4..38d08a16 100644 --- a/db/seeds/hello_world/exercise_spec.rb +++ b/db/seeds/hello_world/exercise_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + describe 'Exercise' do it "outputs 'Hello World" do expect($stdout).to receive(:puts).with('Hello World') diff --git a/db/seeds/production.rb b/db/seeds/production.rb index ad12ee2c..2820de64 100644 --- a/db/seeds/production.rb +++ b/db/seeds/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'highline/import' # consumers @@ -7,7 +9,7 @@ FactoryBot.create(:consumer) email = ask('Enter admin email: ') passwords = ['password', 'password confirmation'].map do |attribute| - ask("Enter admin #{attribute}: ") { |question| question.echo = false } + ask("Enter admin #{attribute}: ") {|question| question.echo = false } end if passwords.uniq.length == 1 diff --git a/db/seeds/sql_select/comparator.rb b/db/seeds/sql_select/comparator.rb index 715598e5..5b3971c8 100644 --- a/db/seeds/sql_select/comparator.rb +++ b/db/seeds/sql_select/comparator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'sqlite3' REFERENCE_QUERY = File.new('reference.sql', 'r').read diff --git a/db/seeds/tdd/exercise_spec.rb b/db/seeds/tdd/exercise_spec.rb index 566cfc94..9ecd2f7a 100644 --- a/db/seeds/tdd/exercise_spec.rb +++ b/db/seeds/tdd/exercise_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + describe 'Exercise' do it 'includes a successful example' do expect(true).to be true diff --git a/db/seeds/web_app/app.rb b/db/seeds/web_app/app.rb index 76915b6f..5b499849 100644 --- a/db/seeds/web_app/app.rb +++ b/db/seeds/web_app/app.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'sinatra' set :bind, '0.0.0.0' diff --git a/lib/active_model/validations/boolean_presence_validator.rb b/lib/active_model/validations/boolean_presence_validator.rb index f1fac7dd..80acaafe 100644 --- a/lib/active_model/validations/boolean_presence_validator.rb +++ b/lib/active_model/validations/boolean_presence_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveModel module Validations class BooleanPresenceValidator < EachValidator diff --git a/lib/assessor.rb b/lib/assessor.rb index 5e018dfa..47612f94 100644 --- a/lib/assessor.rb +++ b/lib/assessor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Assessor MAXIMUM_SCORE = 1 @@ -9,9 +11,9 @@ class Assessor end def calculate_score(test_outcome) - score = 0.0; - if(test_outcome[:passed].to_f != 0.0 && test_outcome[:count].to_f != 0.0) - score = (test_outcome[:passed].to_f / test_outcome[:count].to_f) + score = 0.0 + if test_outcome[:passed].to_f != 0.0 && test_outcome[:count].to_f != 0.0 + score = (test_outcome[:passed].to_f / test_outcome[:count]) # prevent negative scores score = [0.0, score].max end @@ -23,7 +25,7 @@ class Assessor if options[:execution_environment].testing_framework? @testing_framework_adapter = Kernel.const_get(options[:execution_environment].testing_framework).new else - fail(Error, 'No testing framework adapter set!') + raise Error.new('No testing framework adapter set!') end end diff --git a/lib/code_ocean/config.rb b/lib/code_ocean/config.rb index f73e54b9..f8f186a1 100644 --- a/lib/code_ocean/config.rb +++ b/lib/code_ocean/config.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CodeOcean class Config def initialize(filename) @@ -7,10 +9,10 @@ module CodeOcean def read(options = {}) path = Rails.root.join('config', "#{@filename}.yml#{options[:erb] ? '.erb' : ''}") if ::File.exist?(path) - content = options[:erb] ? YAML.load(ERB.new(::File.new(path, 'r').read).result) : YAML.load_file(path) + content = options[:erb] ? YAML.safe_load(ERB.new(::File.new(path, 'r').read).result) : YAML.load_file(path) content[Rails.env].with_indifferent_access else - fail(Error, "Configuration file not found: #{path}") + raise Error.new("Configuration file not found: #{path}") end end diff --git a/lib/cpp_catch2_adapter.rb b/lib/cpp_catch2_adapter.rb index 00a838b4..ea0c21b0 100644 --- a/lib/cpp_catch2_adapter.rb +++ b/lib/cpp_catch2_adapter.rb @@ -1,21 +1,23 @@ -class CppCatch2Adapter < TestingFrameworkAdapter - ALL_PASSED_REGEXP = /in\s+(\d+)\s+test case/ - COUNT_REGEXP = /test cases:\s+(\d+)/ - FAILURES_REGEXP = / \|\s+(\d+)\s+failed/ - ASSERTION_ERROR_REGEXP = /\n(.+)error:(.+);/ - - def self.framework_name - 'CppCatch2' - end - - def parse_output(output) - if ALL_PASSED_REGEXP.match(output[:stdout]) - {count: Regexp.last_match(1).to_i, passed: Regexp.last_match(1).to_i} - else - count = COUNT_REGEXP.match(output[:stdout]).try(:captures).try(:first).try(:to_i) || 0 - failed = FAILURES_REGEXP.match(output[:stdout]).try(:captures).try(:first).try(:to_i) || 0 - error_matches = ASSERTION_ERROR_REGEXP.match(output[:stdout]).try(:captures) || [] - {count: count, failed: failed, error_messages: error_matches} - end - end -end +# frozen_string_literal: true + +class CppCatch2Adapter < TestingFrameworkAdapter + ALL_PASSED_REGEXP = /in\s+(\d+)\s+test case/.freeze + COUNT_REGEXP = /test cases:\s+(\d+)/.freeze + FAILURES_REGEXP = / \|\s+(\d+)\s+failed/.freeze + ASSERTION_ERROR_REGEXP = /\n(.+)error:(.+);/.freeze + + def self.framework_name + 'CppCatch2' + end + + def parse_output(output) + if ALL_PASSED_REGEXP.match(output[:stdout]) + {count: Regexp.last_match(1).to_i, passed: Regexp.last_match(1).to_i} + else + count = COUNT_REGEXP.match(output[:stdout]).try(:captures).try(:first).try(:to_i) || 0 + failed = FAILURES_REGEXP.match(output[:stdout]).try(:captures).try(:first).try(:to_i) || 0 + error_matches = ASSERTION_ERROR_REGEXP.match(output[:stdout]).try(:captures) || [] + {count: count, failed: failed, error_messages: error_matches} + end + end +end diff --git a/lib/docker_client.rb b/lib/docker_client.rb index c2a0df32..7eb4bc39 100644 --- a/lib/docker_client.rb +++ b/lib/docker_client.rb @@ -11,7 +11,7 @@ class DockerClient CONTAINER_WORKSPACE_PATH = '/workspace' # '/home/python/workspace' #'/tmp/workspace' DEFAULT_MEMORY_LIMIT = 256 # Ralf: I suggest to replace this with the environment variable. Ask Hauke why this is not the case! - LOCAL_WORKSPACE_ROOT = File.expand_path(self.config[:workspace_root]) + LOCAL_WORKSPACE_ROOT = File.expand_path(config[:workspace_root]) MINIMUM_MEMORY_LIMIT = 4 RECYCLE_CONTAINERS = false RETRY_COUNT = 2 @@ -19,14 +19,13 @@ class DockerClient MAXIMUM_CONTAINER_LIFETIME = 20.minutes SELF_DESTROY_GRACE_PERIOD = 2.minutes - attr_reader :container - attr_reader :socket + attr_reader :container, :socket attr_accessor :tubesock def self.check_availability! Timeout.timeout(config[:connection_timeout]) { Docker.version } rescue Excon::Errors::SocketError, Timeout::Error - raise(Error, "The Docker host at #{Docker.url} is not reachable!") + raise Error.new("The Docker host at #{Docker.url} is not reachable!") end def self.clean_container_workspace(container) @@ -37,9 +36,9 @@ class DockerClient if local_workspace_path && Pathname.new(local_workspace_path).exist? Pathname.new(local_workspace_path).children.each do |p| p.rmtree - rescue Errno::ENOENT, Errno::EACCES => error - Sentry.capture_exception(error) - Rails.logger.error("clean_container_workspace: Got #{error.class.to_s}: #{error.to_s}") + rescue Errno::ENOENT, Errno::EACCES => e + Sentry.capture_exception(e) + Rails.logger.error("clean_container_workspace: Got #{e.class}: #{e}") end # FileUtils.rmdir(Pathname.new(local_workspace_path)) end @@ -49,7 +48,7 @@ class DockerClient { class_name: File.basename(filename, File.extname(filename)).camelize, filename: filename, - module_name: File.basename(filename, File.extname(filename)).underscore + module_name: File.basename(filename, File.extname(filename)).underscore, } end @@ -70,32 +69,32 @@ class DockerClient 'Binds' => mapped_directories(local_workspace_path), 'PortBindings' => mapped_ports(execution_environment), # Resource limitations. - 'NanoCPUs' => 4 * 1000000000, # CPU quota in units of 10^-9 CPUs. + 'NanoCPUs' => 4 * 1_000_000_000, # CPU quota in units of 10^-9 CPUs. 'PidsLimit' => 100, 'KernelMemory' => execution_environment.memory_limit.megabytes, # if below Memory, the Docker host (!) might experience an OOM 'Memory' => execution_environment.memory_limit.megabytes, 'MemorySwap' => execution_environment.memory_limit.megabytes, # same value as Memory to disable Swap - 'OomScoreAdj' => 500 + 'OomScoreAdj' => 500, } end def create_socket(container, stderr = false) # TODO: factor out query params # todo separate stderr - query_params = 'logs=0&stream=1&' + (stderr ? 'stderr=1' : 'stdout=1&stdin=1') + query_params = "logs=0&stream=1&#{stderr ? 'stderr=1' : 'stdout=1&stdin=1'}" # Headers are required by Docker headers = {'Origin' => 'http://localhost'} - socket_url = DockerClient.config['ws_host'] + '/v1.27/containers/' + @container.id + '/attach/ws?' + query_params + socket_url = "#{DockerClient.config['ws_host']}/v1.27/containers/#{@container.id}/attach/ws?#{query_params}" # The ping value is measured in seconds and specifies how often a Ping frame should be sent. # Internally, Faye::WebSocket uses EventMachine and the ping value is used to wake the EventMachine thread socket = Faye::WebSocket::Client.new(socket_url, [], headers: headers, ping: 0.1) - Rails.logger.debug 'Opening Websocket on URL ' + socket_url + Rails.logger.debug "Opening Websocket on URL #{socket_url}" socket.on :error do |event| - Rails.logger.info 'Websocket error: ' + event.message.to_s + Rails.logger.info "Websocket error: #{event.message}" end socket.on :close do |_event| Rails.logger.info 'Websocket closed.' @@ -117,10 +116,10 @@ class DockerClient # this is however not guaranteed and caused issues on the server already. Therefore create the necessary folders manually! local_workspace_path = generate_local_workspace_path FileUtils.mkdir(local_workspace_path) - FileUtils.chmod_R(0777, local_workspace_path) + FileUtils.chmod_R(0o777, local_workspace_path) container = Docker::Container.create(container_creation_options(execution_environment, local_workspace_path)) container.start - container.start_time = Time.now + container.start_time = Time.zone.now container.status = :created container.execution_environment = execution_environment container.re_use = true @@ -130,19 +129,19 @@ class DockerClient timeout = Random.rand(MINIMUM_CONTAINER_LIFETIME..MAXIMUM_CONTAINER_LIFETIME) # seconds sleep(timeout) container.re_use = false - if container.status != :executing - container.docker_client.kill_container(container, false) - Rails.logger.info('Killing container in status ' + container.status.to_s + ' after ' + (Time.now - container.start_time).to_s + ' seconds.') - else + if container.status == :executing Thread.new do timeout = SELF_DESTROY_GRACE_PERIOD.to_i sleep(timeout) container.docker_client.kill_container(container, false) - Rails.logger.info('Force killing container in status ' + container.status.to_s + ' after ' + (Time.now - container.start_time).to_s + ' seconds.') + Rails.logger.info("Force killing container in status #{container.status} after #{Time.zone.now - container.start_time} seconds.") ensure # guarantee that the thread is releasing the DB connection after it is done ActiveRecord::Base.connection_pool.release_connection end + else + container.docker_client.kill_container(container, false) + Rails.logger.info("Killing container in status #{container.status} after #{Time.zone.now - container.start_time} seconds.") end ensure # guarantee that the thread is releasing the DB connection after it is done @@ -150,8 +149,8 @@ class DockerClient end container - rescue Docker::Error::NotFoundError => error - Rails.logger.error('create_container: Got Docker::Error::NotFoundError: ' + error.to_s) + rescue Docker::Error::NotFoundError => e + Rails.logger.error("create_container: Got Docker::Error::NotFoundError: #{e}") destroy_container(container) # (tries += 1) <= RETRY_COUNT ? retry : raise(error) end @@ -169,7 +168,7 @@ class DockerClient end FileUtils.chmod_R('+rwX', self.class.local_workspace_path(container)) rescue Docker::Error::NotFoundError => e - Rails.logger.info('create_workspace_files: Rescued from Docker::Error::NotFoundError: ' + e.to_s) + Rails.logger.info("create_workspace_files: Rescued from Docker::Error::NotFoundError: #{e}") end private :create_workspace_files @@ -187,7 +186,7 @@ class DockerClient # create a temporary dir, put all files in it, and put it into the container. the dir is automatically removed when leaving the block. Dir.mktmpdir do |dir| submission.collect_files.each do |file| - disk_file = File.new(dir + '/' + (file.path || '') + file.name_with_extension, 'w') + disk_file = File.new("#{dir}/#{file.path || ''}#{file.name_with_extension}", 'w') disk_file.write(file.content) disk_file.close end @@ -198,7 +197,7 @@ class DockerClient # container.exec(['bash', '-c', 'chown -R python ' + CONTAINER_WORKSPACE_PATH]) # container.exec(['bash', '-c', 'chgrp -G python ' + CONTAINER_WORKSPACE_PATH]) rescue StandardError => e - Rails.logger.error('create workspace folder: Rescued from StandardError: ' + e.to_s) + Rails.logger.error("create workspace folder: Rescued from StandardError: #{e}") end # sleep 1000 @@ -207,38 +206,39 @@ class DockerClient # tar the files in dir and put the tar to CONTAINER_WORKSPACE_PATH in the container container.archive_in(dir, CONTAINER_WORKSPACE_PATH, overwrite: false) rescue StandardError => e - Rails.logger.error('insert tar: Rescued from StandardError: ' + e.to_s) + Rails.logger.error("insert tar: Rescued from StandardError: #{e}") end # Rails.logger.info('command: tar -xf ' + CONTAINER_WORKSPACE_PATH + '/' + dir.split('/tmp/')[1] + ' -C ' + CONTAINER_WORKSPACE_PATH) begin # untar the tar file placed in the CONTAINER_WORKSPACE_PATH - container.exec(['bash', '-c', 'tar -xf ' + CONTAINER_WORKSPACE_PATH + '/' + dir.split('/tmp/')[1] + ' -C ' + CONTAINER_WORKSPACE_PATH]) + container.exec(['bash', '-c', + "tar -xf #{CONTAINER_WORKSPACE_PATH}/#{dir.split('/tmp/')[1]} -C #{CONTAINER_WORKSPACE_PATH}"]) rescue StandardError => e - Rails.logger.error('untar: Rescued from StandardError: ' + e.to_s) + Rails.logger.error("untar: Rescued from StandardError: #{e}") end # sleep 1000 end rescue StandardError => e - Rails.logger.error('create_workspace_files_transmit: Rescued from StandardError: ' + e.to_s) + Rails.logger.error("create_workspace_files_transmit: Rescued from StandardError: #{e}") end def self.destroy_container(container) @socket&.close - Rails.logger.info('destroying container ' + container.to_s) + Rails.logger.info("destroying container #{container}") # Checks only if container assignment is not nil and not whether the container itself is still present. if container && !DockerContainerPool.config[:active] container.kill - container.port_bindings.values.each { |port| PortPool.release(port) } + container.port_bindings.each_value {|port| PortPool.release(port) } begin clean_container_workspace(container) FileUtils.rmtree(local_workspace_path(container)) - rescue Errno::ENOENT, Errno::EACCES => error - Sentry.capture_exception(error) - Rails.logger.error("clean_container_workspace: Got #{error.class.to_s}: #{error.to_s}") + rescue Errno::ENOENT, Errno::EACCES => e + Sentry.capture_exception(e) + Rails.logger.error("clean_container_workspace: Got #{e.class}: #{e}") end # Checks only if container assignment is not nil and not whether the container itself is still present. @@ -246,11 +246,11 @@ class DockerClient elsif container DockerContainerPool.destroy_container(container) end - rescue Docker::Error::NotFoundError => error - Rails.logger.error('destroy_container: Rescued from Docker::Error::NotFoundError: ' + error.to_s) + rescue Docker::Error::NotFoundError => e + Rails.logger.error("destroy_container: Rescued from Docker::Error::NotFoundError: #{e}") Rails.logger.error('No further actions are done concerning that.') - rescue Docker::Error::ConflictError => error - Rails.logger.error('destroy_container: Rescued from Docker::Error::ConflictError: ' + error.to_s) + rescue Docker::Error::ConflictError => e + Rails.logger.error("destroy_container: Rescued from Docker::Error::ConflictError: #{e}") Rails.logger.error('No further actions are done concerning that.') end @@ -263,21 +263,22 @@ class DockerClient # only used by score and execute_arbitrary_command def execute_command(command, before_execution_block, output_consuming_block) # tries ||= 0 - container_request_time = Time.now + container_request_time = Time.zone.now @container = DockerContainerPool.get_container(@execution_environment) - waiting_for_container_time = Time.now - container_request_time + waiting_for_container_time = Time.zone.now - container_request_time if @container @container.status = :executing before_execution_block.try(:call) - execution_request_time = Time.now + execution_request_time = Time.zone.now command_result = send_command(command, @container, &output_consuming_block) - container_execution_time = Time.now - execution_request_time + container_execution_time = Time.zone.now - execution_request_time - command_result.merge!(waiting_for_container_time: waiting_for_container_time) - command_result.merge!(container_execution_time: container_execution_time) + command_result[:waiting_for_container_time] = waiting_for_container_time + command_result[:container_execution_time] = container_execution_time command_result else - {status: :container_depleted, waiting_for_container_time: waiting_for_container_time, container_execution_time: nil} + {status: :container_depleted, waiting_for_container_time: waiting_for_container_time, +container_execution_time: nil} end rescue Excon::Errors::SocketError => e # socket errors seems to be normal when using exec @@ -298,7 +299,7 @@ class DockerClient # Prevent catching this error here raise rescue StandardError => e - Rails.logger.error('execute_websocket_command: Rescued from StandardError caused by before_execution_block.call: ' + e.to_s) + Rails.logger.error("execute_websocket_command: Rescued from StandardError caused by before_execution_block.call: #{e}") end # TODO: catch exception if socket could not be created @socket ||= create_socket(@container) @@ -309,16 +310,16 @@ class DockerClient end def kill_after_timeout(container) - """ + " We need to start a second thread to kill the websocket connection, as it is impossible to determine whether further input is requested. - """ + " container.status = :executing @thread = Thread.new do - timeout = (@execution_environment.permitted_execution_time.to_i) # seconds + timeout = @execution_environment.permitted_execution_time.to_i # seconds sleep(timeout) if container && container.status != :available - Rails.logger.info('Killing container after timeout of ' + timeout.to_s + ' seconds.') + Rails.logger.info("Killing container after timeout of #{timeout} seconds.") # send timeout to the tubesock socket # FIXME: 2nd thread to notify user. @tubesock&.send_data JSON.dump({'cmd' => 'timeout'}) @@ -338,7 +339,7 @@ class DockerClient ActiveRecord::Base.connection_pool.release_connection end else - Rails.logger.info('Container' + container.to_s + ' already removed.') + Rails.logger.info("Container#{container} already removed.") end ensure # guarantee that the thread is releasing the DB connection after it is done @@ -351,25 +352,30 @@ class DockerClient end def exit_container(container) - Rails.logger.debug('exiting container ' + container.to_s) + Rails.logger.debug("exiting container #{container}") # exit the timeout thread if it is still alive exit_thread_if_alive @socket.close # if we use pooling and recylce the containers, put it back. otherwise, destroy it. - DockerContainerPool.config[:active] && RECYCLE_CONTAINERS ? self.class.return_container(container, @execution_environment) : self.class.destroy_container(container) + if DockerContainerPool.config[:active] && RECYCLE_CONTAINERS + self.class.return_container(container, + @execution_environment) + else + self.class.destroy_container(container) + end end def kill_container(container, _create_new = true) exit_thread_if_alive - Rails.logger.info('killing container ' + container.to_s) + Rails.logger.info("killing container #{container}") self.class.destroy_container(container) end def execute_run_command(submission, filename, &block) - """ + " Run commands by attaching a websocket to Docker. - """ - filepath = submission.collect_files.find { |f| f.name_with_extension == filename }.filepath + " + filepath = submission.collect_files.find {|f| f.name_with_extension == filename }.filepath command = submission.execution_environment.run_command % command_substitutions(filepath) create_workspace_files = proc { create_workspace_files(container, submission) } open_websocket_connection(command, create_workspace_files, block) @@ -377,15 +383,15 @@ class DockerClient end def execute_test_command(submission, filename, &block) - """ + " Stick to existing Docker API with exec command. - """ - file = submission.collect_files.find { |f| f.name_with_extension == filename } + " + file = submission.collect_files.find {|f| f.name_with_extension == filename } filepath = file.filepath command = submission.execution_environment.test_command % command_substitutions(filepath) create_workspace_files = proc { create_workspace_files(container, submission) } test_result = execute_command(command, create_workspace_files, block) - test_result.merge!(file_role: file.role) + test_result[:file_role] = file.role test_result end @@ -404,7 +410,7 @@ class DockerClient end def self.image_tags - Docker::Image.all.map { |image| image.info['RepoTags'] }.flatten.reject { |tag| tag.nil? || tag.include?('') } + Docker::Image.all.map {|image| image.info['RepoTags'] }.flatten.reject {|tag| tag.nil? || tag.include?('') } end def initialize(options = {}) @@ -417,7 +423,7 @@ class DockerClient def self.initialize_environment # TODO: Move to DockerContainerPool - raise(Error, 'Docker configuration missing!') unless config[:connection_timeout] && config[:workspace_root] + raise Error.new('Docker configuration missing!') unless config[:connection_timeout] && config[:workspace_root] Docker.url = config[:host] if config[:host] # TODO: availability check disabled for performance reasons. Reconsider if this is necessary. @@ -427,11 +433,13 @@ class DockerClient end def local_file_path(options = {}) - resulting_file_path = File.join(self.class.local_workspace_path(options[:container]), options[:file].path || '', options[:file].name_with_extension) + resulting_file_path = File.join(self.class.local_workspace_path(options[:container]), options[:file].path || '', + options[:file].name_with_extension) absolute_path = File.expand_path(resulting_file_path) unless absolute_path.start_with? self.class.local_workspace_path(options[:container]).to_s - raise(FilepathError, 'Filepath not allowed') + raise FilepathError.new('Filepath not allowed') end + absolute_path end @@ -457,12 +465,12 @@ class DockerClient end def self.return_container(container, execution_environment) - Rails.logger.debug('returning container ' + container.to_s) + Rails.logger.debug("returning container #{container}") begin clean_container_workspace(container) - rescue Docker::Error::NotFoundError => error + rescue Docker::Error::NotFoundError => e # FIXME: Create new container? - Rails.logger.info('return_container: Rescued from Docker::Error::NotFoundError: ' + error.to_s) + Rails.logger.info("return_container: Rescued from Docker::Error::NotFoundError: #{e}") Rails.logger.info('Nothing is done here additionally. The container will be exchanged upon its next retrieval.') end DockerContainerPool.return_container(container, execution_environment) @@ -477,21 +485,30 @@ class DockerClient Timeout.timeout(@execution_environment.permitted_execution_time.to_i) do # TODO: check phusion doku again if we need -i -t options here # https://stackoverflow.com/questions/363223/how-do-i-get-both-stdout-and-stderr-to-go-to-the-terminal-and-a-log-file - output = container.exec(['bash', '-c', "#{command} 1> >(tee -a /tmp/stdout.log) 2> >(tee -a /tmp/stderr.log >&2); rm -f /tmp/std*.log"], tty: false) + output = container.exec( + ['bash', '-c', + "#{command} 1> >(tee -a /tmp/stdout.log) 2> >(tee -a /tmp/stderr.log >&2); rm -f /tmp/std*.log"], tty: false + ) end Rails.logger.debug 'output from container.exec' Rails.logger.debug output if output.nil? kill_container(container) else - result = {status: output[2] == 0 ? :ok : :failed, stdout: output[0].join.force_encoding('utf-8'), stderr: output[1].join.force_encoding('utf-8')} + result = {status: (output[2]).zero? ? :ok : :failed, stdout: output[0].join.force_encoding('utf-8'), +stderr: output[1].join.force_encoding('utf-8')} end # if we use pooling and recylce the containers, put it back. otherwise, destroy it. - DockerContainerPool.config[:active] && RECYCLE_CONTAINERS ? self.class.return_container(container, @execution_environment) : self.class.destroy_container(container) + if DockerContainerPool.config[:active] && RECYCLE_CONTAINERS + self.class.return_container(container, + @execution_environment) + else + self.class.destroy_container(container) + end result rescue Timeout::Error - Rails.logger.info('got timeout error for container ' + container.to_s) + Rails.logger.info("got timeout error for container #{container}") stdout = container.exec(['cat', '/tmp/stdout.log'])[0].join.force_encoding('utf-8') stderr = container.exec(['cat', '/tmp/stderr.log'])[0].join.force_encoding('utf-8') kill_container(container) @@ -501,5 +518,6 @@ class DockerClient private :send_command class Error < RuntimeError; end + class FilepathError < RuntimeError; end end diff --git a/lib/docker_container_mixin.rb b/lib/docker_container_mixin.rb index 2a5d60f7..83b77865 100644 --- a/lib/docker_container_mixin.rb +++ b/lib/docker_container_mixin.rb @@ -1,10 +1,7 @@ -module DockerContainerMixin +# frozen_string_literal: true - attr_accessor :start_time - attr_accessor :status - attr_accessor :re_use - attr_accessor :execution_environment - attr_accessor :docker_client +module DockerContainerMixin + attr_accessor :start_time, :status, :re_use, :execution_environment, :docker_client def binds host_config['Binds'] @@ -12,7 +9,7 @@ module DockerContainerMixin def port_bindings # Don't use cached version as this might be changed during runtime - json['HostConfig']['PortBindings'].try(:map) { |key, value| [key.to_i, value.first['HostPort'].to_i] }.to_h + json['HostConfig']['PortBindings'].try(:map) {|key, value| [key.to_i, value.first['HostPort'].to_i] }.to_h end def host_config diff --git a/lib/docker_container_pool.rb b/lib/docker_container_pool.rb index abddb49d..fd3d85c1 100644 --- a/lib/docker_container_pool.rb +++ b/lib/docker_container_pool.rb @@ -1,30 +1,32 @@ +# frozen_string_literal: true + require 'concurrent/future' require 'concurrent/timer_task' - class DockerContainerPool - def self.config - #TODO: Why erb? + # TODO: Why erb? @config ||= CodeOcean::Config.new(:docker).read(erb: true)[:pool] end def self.create_container(execution_environment) - Rails.logger.info('trying to create container for execution environment: ' + execution_environment.to_s) + Rails.logger.info("trying to create container for execution environment: #{execution_environment}") container = DockerClient.create_container(execution_environment) container.status = 'available' # FIXME: String vs Symbol usage? - #Rails.logger.debug('created container ' + container.to_s + ' for execution environment ' + execution_environment.to_s) + # Rails.logger.debug('created container ' + container.to_s + ' for execution environment ' + execution_environment.to_s) container rescue StandardError => e - Sentry.set_extras({container: container.inspect, execution_environment: execution_environment.inspect, config: config.inspect}) + Sentry.set_extras({container: container.inspect, execution_environment: execution_environment.inspect, +config: config.inspect}) Sentry.capture_exception(e) nil end def self.return_container(container, execution_environment) - Faraday.get(config[:location] + "/docker_container_pool/return_container/" + container.id) + Faraday.get("#{config[:location]}/docker_container_pool/return_container/#{container.id}") rescue StandardError => e - Sentry.set_extras({container: container.inspect, execution_environment: execution_environment.inspect, config: config.inspect}) + Sentry.set_extras({container: container.inspect, execution_environment: execution_environment.inspect, +config: config.inspect}) Sentry.capture_exception(e) nil end @@ -33,10 +35,11 @@ class DockerContainerPool # if pooling is active, do pooling, otherwise just create an container and return it if config[:active] begin - container_id = JSON.parse(Faraday.get(config[:location] + "/docker_container_pool/get_container/" + execution_environment.id.to_s).body)['id'] - Docker::Container.get(container_id) unless container_id.blank? + container_id = JSON.parse(Faraday.get("#{config[:location]}/docker_container_pool/get_container/#{execution_environment.id}").body)['id'] + Docker::Container.get(container_id) if container_id.present? rescue StandardError => e - Sentry.set_extras({container_id: container_id.inspect, execution_environment: execution_environment.inspect, config: config.inspect}) + Sentry.set_extras({container_id: container_id.inspect, execution_environment: execution_environment.inspect, +config: config.inspect}) Sentry.capture_exception(e) nil end @@ -46,11 +49,11 @@ class DockerContainerPool end def self.destroy_container(container) - Faraday.get(config[:location] + "/docker_container_pool/destroy_container/" + container.id) + Faraday.get("#{config[:location]}/docker_container_pool/destroy_container/#{container.id}") end def self.quantities - response = JSON.parse(Faraday.get(config[:location] + "/docker_container_pool/quantities").body) + response = JSON.parse(Faraday.get("#{config[:location]}/docker_container_pool/quantities").body) response.transform_keys(&:to_i) rescue StandardError => e Sentry.set_extras({response: response.inspect}) @@ -59,7 +62,7 @@ class DockerContainerPool end def self.dump_info - JSON.parse(Faraday.get(config[:location] + "/docker_container_pool/dump_info").body) + JSON.parse(Faraday.get("#{config[:location]}/docker_container_pool/dump_info").body) rescue StandardError => e Sentry.capture_exception(e) nil diff --git a/lib/file_tree.rb b/lib/file_tree.rb index ced4ea45..672ceab8 100644 --- a/lib/file_tree.rb +++ b/lib/file_tree.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class FileTree < Tree::TreeNode def file_icon(file) if file.file_type.audio? @@ -25,10 +27,10 @@ class FileTree < Tree::TreeNode def initialize(files = []) super(root_label) - files.uniq{|f| f.name_with_extension}.each do |file| + files.uniq(&:name_with_extension).each do |file| parent = self (file.path || '').split('/').each do |segment| - node = parent.children.detect { |child| child.name == segment } || parent.add(Tree::TreeNode.new(segment)) + node = parent.children.detect {|child| child.name == segment } || parent.add(Tree::TreeNode.new(segment)) parent = node end parent.add(Tree::TreeNode.new(file.name_with_extension, file)) @@ -37,14 +39,14 @@ class FileTree < Tree::TreeNode def map_to_js_tree(node) { - children: node.children.map { |child| map_to_js_tree(child) }, + children: node.children.map {|child| map_to_js_tree(child) }, icon: node_icon(node), id: node.content.try(:ancestor_id), state: { disabled: !node.is_leaf?, - opened: !node.is_leaf? + opened: !node.is_leaf?, }, - text: node.name + text: node.name, } end private :map_to_js_tree @@ -68,8 +70,8 @@ class FileTree < Tree::TreeNode def to_js_tree { core: { - data: map_to_js_tree(self) - } + data: map_to_js_tree(self), + }, }.to_json end end diff --git a/lib/generators/testing_framework_adapter_generator.rb b/lib/generators/testing_framework_adapter_generator.rb index 34de7ff4..9b113fe8 100644 --- a/lib/generators/testing_framework_adapter_generator.rb +++ b/lib/generators/testing_framework_adapter_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails/generators' class TestingFrameworkAdapterGenerator < Rails::Generators::NamedBase @@ -5,26 +7,26 @@ class TestingFrameworkAdapterGenerator < Rails::Generators::NamedBase SPEC_PATH = ->(name) { Rails.root.join('spec', 'lib', "#{name.underscore}_adapter_spec.rb") } def create_testing_framework_adapter - create_file ADAPTER_PATH.call(file_name), <<-code -class #{file_name.camelize}Adapter < TestingFrameworkAdapter - def self.framework_name - '#{file_name.camelize}' - end - - def parse_output(output) - end -end - code + create_file ADAPTER_PATH.call(file_name), <<~CODE + class #{file_name.camelize}Adapter < TestingFrameworkAdapter + def self.framework_name + '#{file_name.camelize}' + end + #{' '} + def parse_output(output) + end + end + CODE end def create_spec - create_file SPEC_PATH.call(file_name), <<-code -require 'rails_helper' - -describe #{file_name.camelize}Adapter do - describe '#parse_output' do - end -end - code + create_file SPEC_PATH.call(file_name), <<~CODE + require 'rails_helper' + #{' '} + describe #{file_name.camelize}Adapter do + describe '#parse_output' do + end + end + CODE end end diff --git a/lib/junit_adapter.rb b/lib/junit_adapter.rb index df0eff5d..a7eb31c1 100644 --- a/lib/junit_adapter.rb +++ b/lib/junit_adapter.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + class JunitAdapter < TestingFrameworkAdapter - COUNT_REGEXP = /Tests run: (\d+)/ - FAILURES_REGEXP = /Failures: (\d+)/ - SUCCESS_REGEXP = /OK \((\d+) test[s]?\)/ - ASSERTION_ERROR_REGEXP = /java\.lang\.AssertionError:?\s(.*?)\tat org.junit|org\.junit\.ComparisonFailure:\s(.*?)\tat org.junit/m + COUNT_REGEXP = /Tests run: (\d+)/.freeze + FAILURES_REGEXP = /Failures: (\d+)/.freeze + SUCCESS_REGEXP = /OK \((\d+) tests?\)/.freeze + ASSERTION_ERROR_REGEXP = /java\.lang\.AssertionError:?\s(.*?)\tat org.junit|org\.junit\.ComparisonFailure:\s(.*?)\tat org.junit/m.freeze def self.framework_name 'JUnit' diff --git a/lib/mocha_adapter.rb b/lib/mocha_adapter.rb index a5b8469d..7d5bb7b3 100644 --- a/lib/mocha_adapter.rb +++ b/lib/mocha_adapter.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class MochaAdapter < TestingFrameworkAdapter - SUCCESS_REGEXP = /(\d+) passing/ - FAILURES_REGEXP = /(\d+) failing/ + SUCCESS_REGEXP = /(\d+) passing/.freeze + FAILURES_REGEXP = /(\d+) failing/.freeze def self.framework_name 'Mocha' @@ -11,6 +13,6 @@ class MochaAdapter < TestingFrameworkAdapter matches_failed = FAILURES_REGEXP.match(output[:stdout]) failed = matches_failed ? matches_failed.captures.first.to_i : 0 success = matches_success ? matches_success.captures.first.to_i : 0 - {count: success+failed, failed: failed} + {count: success + failed, failed: failed} end end diff --git a/lib/nonce_store.rb b/lib/nonce_store.rb index 5b1b57c0..6f49ffde 100644 --- a/lib/nonce_store.rb +++ b/lib/nonce_store.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + class NonceStore def self.build_cache_key(nonce) "lti_nonce_#{nonce}" end def self.add(nonce) - Rails.cache.write(build_cache_key(nonce), Time.now, expires_in: Lti::MAXIMUM_SESSION_AGE) + Rails.cache.write(build_cache_key(nonce), Time.zone.now, expires_in: Lti::MAXIMUM_SESSION_AGE) end def self.delete(nonce) diff --git a/lib/port_pool.rb b/lib/port_pool.rb index 4a493df9..e32b5438 100644 --- a/lib/port_pool.rb +++ b/lib/port_pool.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PortPool PORT_RANGE = DockerClient.config[:ports] @@ -11,6 +13,6 @@ class PortPool end def self.release(port) - @available_ports << port if PORT_RANGE.include?(port) && !@available_ports.include?(port) + @available_ports << port if PORT_RANGE.include?(port) && @available_ports.exclude?(port) end end diff --git a/lib/prometheus/controller.rb b/lib/prometheus/controller.rb index 19bcc931..0ef27f00 100644 --- a/lib/prometheus/controller.rb +++ b/lib/prometheus/controller.rb @@ -42,11 +42,11 @@ module Prometheus def initialize_rfc_metrics # Initialize rfc metric @rfc_count.observe(RequestForComment.unsolved.where(full_score_reached: false).count, - state: RequestForComment::ONGOING) + state: RequestForComment::ONGOING) @rfc_count.observe(RequestForComment.unsolved.where(full_score_reached: true).count, - state: RequestForComment::SOFT_SOLVED) + state: RequestForComment::SOFT_SOLVED) @rfc_count.observe(RequestForComment.where(solved: true).count, - state: RequestForComment::SOLVED) + state: RequestForComment::SOLVED) # count of rfcs with comments @rfc_commented_count.observe(RequestForComment.joins(:comments).distinct.count(:id)) @@ -56,8 +56,8 @@ module Prometheus Rails.logger.debug("Prometheus metric updated for #{object.class.name}") case object - when RequestForComment - update_rfc(object) + when RequestForComment + update_rfc(object) end end @@ -66,10 +66,10 @@ module Prometheus Rails.logger.debug("Prometheus instance count increased for #{object.class.name}") case object - when RequestForComment - create_rfc(object) - when Comment - create_comment(object) + when RequestForComment + create_rfc(object) + when Comment + create_comment(object) end end @@ -78,8 +78,8 @@ module Prometheus Rails.logger.debug("Prometheus instance count decreased for #{object.class.name}") case object - when Comment - destroy_comment(object) + when Comment + destroy_comment(object) end end diff --git a/lib/py_lint_adapter.rb b/lib/py_lint_adapter.rb index d7d8c133..575c0b44 100644 --- a/lib/py_lint_adapter.rb +++ b/lib/py_lint_adapter.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class PyLintAdapter < TestingFrameworkAdapter - REGEXP = /Your code has been rated at (-?\d+\.?\d*)\/(\d+\.?\d*)/ - ASSERTION_ERROR_REGEXP = /^(.*?\.py):(\d+):(.*?)\(([^,]*?), ([^,]*?),([^,]*?)\) (.*?)$/ + REGEXP = %r{Your code has been rated at (-?\d+\.?\d*)/(\d+\.?\d*)}.freeze + ASSERTION_ERROR_REGEXP = /^(.*?\.py):(\d+):(.*?)\(([^,]*?), ([^,]*?),([^,]*?)\) (.*?)$/.freeze def self.framework_name 'PyLint' @@ -22,14 +24,14 @@ class PyLintAdapter < TestingFrameworkAdapter assertion_error_matches = Timeout.timeout(2.seconds) do output[:stdout].scan(ASSERTION_ERROR_REGEXP).map do |match| { - file_name: match[0].strip, + file_name: match[0].strip, line: match[1].to_i, severity: match[2].strip, code: match[3].strip, name: match[4].strip, # e.g. function name, nil if outside of a function. Not always available scope: match[5].strip.presence, - result: match[6].strip + result: match[6].strip, } end || [] end @@ -37,8 +39,9 @@ class PyLintAdapter < TestingFrameworkAdapter Sentry.capture_message({stdout: output[:stdout], regex: ASSERTION_ERROR_REGEXP}.to_json) assertion_error_matches = [] end - concatenated_errors = assertion_error_matches.map { |result| "#{result[:name]}: #{result[:result]}" }.flatten - {count: count, failed: failed, error_messages: concatenated_errors, detailed_linter_results: assertion_error_matches} + concatenated_errors = assertion_error_matches.map {|result| "#{result[:name]}: #{result[:result]}" }.flatten + {count: count, failed: failed, error_messages: concatenated_errors, +detailed_linter_results: assertion_error_matches} end def self.translate_linter(assessment, locale) @@ -47,7 +50,7 @@ class PyLintAdapter < TestingFrameworkAdapter I18n.locale = locale || I18n.default_locale - return assessment unless assessment[:detailed_linter_results].present? + return assessment if assessment[:detailed_linter_results].blank? assessment[:detailed_linter_results].map! do |message| severity = message[:severity] @@ -73,7 +76,7 @@ class PyLintAdapter < TestingFrameworkAdapter replacement = {} end - replacement.merge!(default: message[:result]) + replacement[:default] = message[:result] message[:result] = I18n.t("linter.#{severity}.#{name}.replacement", replacement) message end diff --git a/lib/py_unit_adapter.rb b/lib/py_unit_adapter.rb index 30528c32..88f43758 100644 --- a/lib/py_unit_adapter.rb +++ b/lib/py_unit_adapter.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + class PyUnitAdapter < TestingFrameworkAdapter - COUNT_REGEXP = /Ran (\d+) test/ - FAILURES_REGEXP = /FAILED \(.*failures=(\d+).*\)/ - ERRORS_REGEXP = /FAILED \(.*errors=(\d+).*\)/ - ASSERTION_ERROR_REGEXP = /^(ERROR|FAIL):\ (.*?)\ .*?^[^\.\n]*?(Error|Exception):\s((\s|\S)*?)(>>>.*?)*\s\s(-|=){70}/m + COUNT_REGEXP = /Ran (\d+) test/.freeze + FAILURES_REGEXP = /FAILED \(.*failures=(\d+).*\)/.freeze + ERRORS_REGEXP = /FAILED \(.*errors=(\d+).*\)/.freeze + ASSERTION_ERROR_REGEXP = /^(ERROR|FAIL):\ (.*?)\ .*?^[^.\n]*?(Error|Exception):\s((\s|\S)*?)(>>>.*?)*\s\s(-|=){70}/m.freeze def self.framework_name 'PyUnit' @@ -16,7 +18,7 @@ class PyUnitAdapter < TestingFrameworkAdapter errors = error_matches ? error_matches.captures.try(:first).to_i : 0 begin assertion_error_matches = Timeout.timeout(2.seconds) do - output[:stderr].scan(ASSERTION_ERROR_REGEXP).map { |match| + output[:stderr].scan(ASSERTION_ERROR_REGEXP).map do |match| testname = match[1] error = match[3].strip @@ -25,7 +27,7 @@ class PyUnitAdapter < TestingFrameworkAdapter else "#{testname}: #{error}" end - }.flatten || [] + end.flatten || [] end rescue Timeout::Error Sentry.capture_message({stderr: output[:stderr], regex: ASSERTION_ERROR_REGEXP}.to_json) diff --git a/lib/py_unit_and_py_lint_adapter.rb b/lib/py_unit_and_py_lint_adapter.rb index bdac31c4..f303a7d1 100644 --- a/lib/py_unit_and_py_lint_adapter.rb +++ b/lib/py_unit_and_py_lint_adapter.rb @@ -1,5 +1,6 @@ -class PyUnitAndPyLintAdapter < TestingFrameworkAdapter +# frozen_string_literal: true +class PyUnitAndPyLintAdapter < TestingFrameworkAdapter def self.framework_name 'PyUnit and PyLint' end diff --git a/lib/python20_course_week.rb b/lib/python20_course_week.rb index 7d510ea6..0d4d9bc7 100644 --- a/lib/python20_course_week.rb +++ b/lib/python20_course_week.rb @@ -1,22 +1,21 @@ # frozen_string_literal: true class Python20CourseWeek - def self.get_for(exercise) case exercise.title - when /Python20 Aufgabe 1/ - 1 - when /Python20 Aufgabe 2/ - 2 - when /Python20 Aufgabe 3/ - 3 - when /Python20 Aufgabe 4/ - 4 - when /Python20 Snake/ - 4 - else - # Not part of the Python20 course - nil + when /Python20 Aufgabe 1/ + 1 + when /Python20 Aufgabe 2/ + 2 + when /Python20 Aufgabe 3/ + 3 + when /Python20 Aufgabe 4/ + 4 + when /Python20 Snake/ + 4 + else + # Not part of the Python20 course + nil end end diff --git a/lib/r_script_adapter.rb b/lib/r_script_adapter.rb index d387eaa2..bd65af51 100644 --- a/lib/r_script_adapter.rb +++ b/lib/r_script_adapter.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class RScriptAdapter < TestingFrameworkAdapter - REGEXP = /(\d+) examples?, (\d+) passed?/ - ASSERTION_ERROR_REGEXP = /AssertionError:\s(.*)/ + REGEXP = /(\d+) examples?, (\d+) passed?/.freeze + ASSERTION_ERROR_REGEXP = /AssertionError:\s(.*)/.freeze def self.framework_name 'R Script' diff --git a/lib/rspec_adapter.rb b/lib/rspec_adapter.rb index c68a0e2d..80d8a4d6 100644 --- a/lib/rspec_adapter.rb +++ b/lib/rspec_adapter.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class RspecAdapter < TestingFrameworkAdapter - REGEXP = /(\d+) examples?, (\d+) failures?/ + REGEXP = /(\d+) examples?, (\d+) failures?/.freeze def self.framework_name 'RSpec 3' diff --git a/lib/seeds_helper.rb b/lib/seeds_helper.rb index fa506bc8..817862eb 100644 --- a/lib/seeds_helper.rb +++ b/lib/seeds_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SeedsHelper def self.read_seed_file(filename) file = File.new(seed_file_path(filename), 'r') diff --git a/lib/sql_result_set_comparator_adapter.rb b/lib/sql_result_set_comparator_adapter.rb index 61b9ae3d..3607586a 100644 --- a/lib/sql_result_set_comparator_adapter.rb +++ b/lib/sql_result_set_comparator_adapter.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class SqlResultSetComparatorAdapter < TestingFrameworkAdapter - MISSING_TUPLES_REGEXP = /Missing tuples: \[\]/ - UNEXPECTED_TUPLES_REGEXP = /Unexpected tuples: \[\]/ + MISSING_TUPLES_REGEXP = /Missing tuples: \[\]/.freeze + UNEXPECTED_TUPLES_REGEXP = /Unexpected tuples: \[\]/.freeze def self.framework_name 'SqlResultSetComparator' diff --git a/lib/tasks/detect_exercise_anomalies.rake b/lib/tasks/detect_exercise_anomalies.rake index ba27cf4f..cb0ca5f1 100644 --- a/lib/tasks/detect_exercise_anomalies.rake +++ b/lib/tasks/detect_exercise_anomalies.rake @@ -111,7 +111,7 @@ namespace :detect_exercise_anomalies do end def notify_users(collection, anomalies) - by_id_and_type = proc { |u| {user_id: u[:user_id], user_type: u[:user_type]} } + by_id_and_type = proc {|u| {user_id: u[:user_id], user_type: u[:user_type]} } log('Sending E-Mails to best and worst performing users of each anomaly...', 2) anomalies.each do |exercise_id, average_working_time| @@ -122,7 +122,7 @@ namespace :detect_exercise_anomalies do users = {} %i[performers_by_time performers_by_score].each do |method| # merge users found by multiple methods returning a hash {best: [], worst: []} - users = users.merge(send(method, exercise, NUMBER_OF_USERS_PER_CLASS)) { |_key, this, other| this + other } + users = users.merge(send(method, exercise, NUMBER_OF_USERS_PER_CLASS)) {|_key, this, other| this + other } end # write reasons for feedback emails to db @@ -140,7 +140,8 @@ namespace :detect_exercise_anomalies do users_to_notify.each do |u| user = u[:user_type] == InternalUser.name ? InternalUser.find(u[:user_id]) : ExternalUser.find(u[:user_id]) host = CodeOcean::Application.config.action_mailer.default_url_options[:host] - feedback_link = Rails.application.routes.url_helpers.url_for(action: :new, controller: :user_exercise_feedbacks, exercise_id: exercise.id, host: host) + feedback_link = Rails.application.routes.url_helpers.url_for(action: :new, +controller: :user_exercise_feedbacks, exercise_id: exercise.id, host: host) UserMailer.exercise_anomaly_needs_feedback(user, exercise, feedback_link).deliver end log("Asked #{users_to_notify.size} users for feedback.", 2) @@ -149,7 +150,7 @@ namespace :detect_exercise_anomalies do def performers_by_score(exercise, users) submissions = exercise.last_submission_per_user.where.not(score: nil).order(score: :desc) - map_block = proc { |item| {user_id: item.user_id, user_type: item.user_type, value: item.score, reason: 'score'} } + map_block = proc {|item| {user_id: item.user_id, user_type: item.user_type, value: item.score, reason: 'score'} } best_performers = submissions.first(users).to_a.map(&map_block) worst_performers = submissions.last(users).to_a.map(&map_block) {best: best_performers, worst: worst_performers} @@ -161,8 +162,10 @@ namespace :detect_exercise_anomalies do value: time_to_f(item['working_time']), reason: 'time'} end avg_score = exercise.average_score - working_times.reject! { |item| item[:value].nil? or item[:value] <= MIN_USER_WORKING_TIME or item[:score] < avg_score } - working_times.sort_by! { |item| item[:value] } + working_times.reject! do |item| + item[:value].nil? or item[:value] <= MIN_USER_WORKING_TIME or item[:score] < avg_score + end + working_times.sort_by! {|item| item[:value] } {best: working_times.first(users), worst: working_times.last(users)} end diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake index 5152429a..a0c89a89 100644 --- a/lib/tasks/docker.rake +++ b/lib/tasks/docker.rake @@ -1,6 +1,8 @@ +# frozen_string_literal: true + namespace :docker do desc 'Remove all Docker containers and dangling Docker images (using the CLI)' - task :clean_up do + task clean_up: :environment do `test -n "$(docker ps --all --quiet)" && docker rm --force $(docker ps --all --quiet)` `test -n "docker images --filter dangling=true --quiet" && docker rmi $(docker images --filter dangling=true --quiet)` end diff --git a/lib/tasks/write_displaynames.rake b/lib/tasks/write_displaynames.rake index 955cd355..66129783 100644 --- a/lib/tasks/write_displaynames.rake +++ b/lib/tasks/write_displaynames.rake @@ -1,17 +1,17 @@ +# frozen_string_literal: true + namespace :user do -require 'csv' + require 'csv' -desc 'write displaynames retrieved from the account service as csv into the codeocean database' - -task :write_displaynames, [:file_path_read] => [ :environment ] do |t, args| + desc 'write displaynames retrieved from the account service as csv into the codeocean database' - csv_input = CSV.read(args[:file_path_read], headers:true) + task :write_displaynames, [:file_path_read] => [:environment] do |_t, args| + csv_input = CSV.read(args[:file_path_read], headers: true) csv_input.each do |row| - user = ExternalUser.find_by(:external_id => row[0]) + user = ExternalUser.find_by(external_id: row[0]) puts "Change name from #{user.name} to #{row[1]}" user.update(name: row[1]) end end end - diff --git a/lib/testing_framework_adapter.rb b/lib/testing_framework_adapter.rb index 895a5299..d2b20f33 100644 --- a/lib/testing_framework_adapter.rb +++ b/lib/testing_framework_adapter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TestingFrameworkAdapter def augment_output(options = {}) if !options[:count] @@ -15,7 +17,7 @@ class TestingFrameworkAdapter end def parse_output(*) - fail(NotImplementedError, "#{self.class} should implement #parse_output!") + raise NotImplementedError.new("#{self.class} should implement #parse_output!") end private :parse_output diff --git a/spec/concerns/file_parameters_spec.rb b/spec/concerns/file_parameters_spec.rb index 73383045..65e209a2 100644 --- a/spec/concerns/file_parameters_spec.rb +++ b/spec/concerns/file_parameters_spec.rb @@ -19,7 +19,7 @@ describe FileParameters do describe 'accepts' do it 'main file of the exercise' do - main_file = hello_world.files.find { |e| e.role = 'main_file' } + main_file = hello_world.files.find {|e| e.role = 'main_file' } expect(file_accepted?(main_file)).to be true end diff --git a/spec/concerns/lti_spec.rb b/spec/concerns/lti_spec.rb index 801b4505..beff3298 100644 --- a/spec/concerns/lti_spec.rb +++ b/spec/concerns/lti_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' class Controller < AnonymousController @@ -31,7 +33,7 @@ describe Lti do let(:last_name) { 'Doe' } let(:full_name) { 'John Doe' } let(:provider) { double } - let(:provider_full) { double(:lis_person_name_full => full_name) } + let(:provider_full) { double(lis_person_name_full: full_name) } context 'when a full name is provided' do it 'returns the full name' do @@ -61,7 +63,8 @@ describe Lti do describe '#return_to_consumer' do context 'with a return URL' do let(:consumer_return_url) { 'http://example.org' } - before(:each) { expect(controller).to receive(:params).and_return(launch_presentation_return_url: consumer_return_url) } + + before { expect(controller).to receive(:params).and_return(launch_presentation_return_url: consumer_return_url) } it 'redirects to the tool consumer' do expect(controller).to receive(:redirect_to).with(consumer_return_url) @@ -76,7 +79,7 @@ describe Lti do end context 'without a return URL' do - before(:each) do + before do expect(controller).to receive(:params).and_return({}) expect(controller).to receive(:redirect_to).with(:root) end @@ -101,7 +104,7 @@ describe Lti do let(:consumer) { FactoryBot.create(:consumer) } let(:score) { 0.5 } let(:submission) { FactoryBot.create(:submission) } - let!(:lti_parameter) { FactoryBot.create(:lti_parameter, consumers_id: consumer.id, external_users_id: submission.user_id, exercises_id: submission.exercise_id)} + let!(:lti_parameter) { FactoryBot.create(:lti_parameter, consumers_id: consumer.id, external_users_id: submission.user_id, exercises_id: submission.exercise_id) } context 'with an invalid score' do it 'raises an exception' do @@ -112,7 +115,6 @@ describe Lti do context 'with an valid score' do context 'with a tool consumer' do - context 'when grading is not supported' do it 'returns a corresponding status' do expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false) @@ -124,7 +126,7 @@ describe Lti do context 'when grading is supported' do let(:response) { double } - before(:each) do + before do expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(true) expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:post_replace_result!).with(score).and_return(response) expect(response).to receive(:response_code).at_least(:once).and_return(200) @@ -170,7 +172,7 @@ describe Lti do controller.send(:store_lti_session_data, consumer: FactoryBot.build(:consumer), parameters: parameters) end - it 'it creates an LtiParameter Object' do + it 'creates an LtiParameter Object' do before_count = LtiParameter.count controller.instance_variable_set(:@current_user, FactoryBot.create(:external_user)) controller.instance_variable_set(:@exercise, FactoryBot.create(:fibonacci)) diff --git a/spec/concerns/submission_scoring_spec.rb b/spec/concerns/submission_scoring_spec.rb index 62b29817..59b08312 100644 --- a/spec/concerns/submission_scoring_spec.rb +++ b/spec/concerns/submission_scoring_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' class Controller < AnonymousController @@ -6,11 +8,13 @@ end describe SubmissionScoring do let(:controller) { Controller.new } + before(:all) { @submission = FactoryBot.create(:submission, cause: 'submit') } - before(:each) { controller.instance_variable_set(:@current_user, FactoryBot.create(:external_user)) } + + before { controller.instance_variable_set(:@current_user, FactoryBot.create(:external_user)) } describe '#collect_test_results' do - after(:each) { controller.send(:collect_test_results, @submission) } + after { controller.send(:collect_test_results, @submission) } it 'executes every teacher-defined test file' do @submission.collect_files.select(&:teacher_defined_assessment?).each do |file| @@ -20,7 +24,7 @@ describe SubmissionScoring do end describe '#score_submission' do - after(:each) { controller.score_submission(@submission) } + after { controller.score_submission(@submission) } it 'collects the test results' do expect(controller).to receive(:collect_test_results).and_return([]) diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb index 20265e16..55d4ede5 100644 --- a/spec/controllers/admin/dashboard_controller_spec.rb +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -1,18 +1,20 @@ +# frozen_string_literal: true + require 'rails_helper' describe Admin::DashboardController do - before(:each) { allow(controller).to receive(:current_user).and_return(FactoryBot.build(:admin)) } + before { allow(controller).to receive(:current_user).and_return(FactoryBot.build(:admin)) } describe 'GET #show' do describe 'with format HTML' do - before(:each) { get :show } + before { get :show } expect_status(200) expect_template(:show) end describe 'with format JSON' do - before(:each) { get :show, format: :json } + before { get :show, format: :json } expect_json expect_status(200) diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index e8fdfcf9..541c95a5 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -1,10 +1,13 @@ +# frozen_string_literal: true + require 'rails_helper' describe ApplicationController do describe '#current_user' do context 'with an external user' do let(:external_user) { FactoryBot.create(:external_user) } - before(:each) { session[:external_user_id] = external_user.id } + + before { session[:external_user_id] = external_user.id } it 'returns the external user' do expect(controller.current_user).to eq(external_user) @@ -13,7 +16,8 @@ describe ApplicationController do context 'without an external user' do let(:internal_user) { FactoryBot.create(:teacher) } - before(:each) { login_user(internal_user) } + + before { login_user(internal_user) } it 'returns the internal user' do expect(controller.current_user).to eq(internal_user) @@ -22,7 +26,7 @@ describe ApplicationController do end describe '#render_not_authorized' do - before(:each) do + before do expect(controller).to receive(:welcome) { controller.send(:render_not_authorized) } get :welcome end @@ -35,19 +39,19 @@ describe ApplicationController do let(:locale) { :de } context 'when specifying a locale' do - before(:each) { allow(session).to receive(:[]=).at_least(:once) } + before { allow(session).to receive(:[]=).at_least(:once) } context "using the 'custom_locale' parameter" do it 'overwrites the session' do expect(session).to receive(:[]=).with(:locale, locale.to_s) - get :welcome, params: { custom_locale: locale } + get :welcome, params: {custom_locale: locale} end end context "using the 'locale' parameter" do it 'overwrites the session' do expect(session).to receive(:[]=).with(:locale, locale.to_s) - get :welcome, params: { locale: locale } + get :welcome, params: {locale: locale} end end end @@ -70,7 +74,7 @@ describe ApplicationController do end describe 'GET #welcome' do - before(:each) { get :welcome } + before { get :welcome } expect_status(200) expect_template(:welcome) diff --git a/spec/controllers/code_ocean/files_controller_spec.rb b/spec/controllers/code_ocean/files_controller_spec.rb index 7525c097..8097cd70 100644 --- a/spec/controllers/code_ocean/files_controller_spec.rb +++ b/spec/controllers/code_ocean/files_controller_spec.rb @@ -4,14 +4,16 @@ require 'rails_helper' describe CodeOcean::FilesController do let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'POST #create' do let(:submission) { FactoryBot.create(:submission, user: user) } context 'with a valid file' do - let(:perform_request) { proc { post :create, params: { code_ocean_file: FactoryBot.build(:file, context: submission).attributes, format: :json } } } - before(:each) do + let(:perform_request) { proc { post :create, params: {code_ocean_file: FactoryBot.build(:file, context: submission).attributes, format: :json} } } + + before do submission.exercise.update(allow_file_creation: true) perform_request.call end @@ -27,9 +29,9 @@ describe CodeOcean::FilesController do end context 'with an invalid file' do - before(:each) do + before do submission.exercise.update(allow_file_creation: true) - post :create, params: { code_ocean_file: {context_id: submission.id, context_type: Submission}, format: :json } + post :create, params: {code_ocean_file: {context_id: submission.id, context_type: Submission}, format: :json} end expect_assigns(file: CodeOcean::File) @@ -40,8 +42,9 @@ describe CodeOcean::FilesController do describe 'DELETE #destroy' do let(:exercise) { FactoryBot.create(:fibonacci) } - let(:perform_request) { proc { delete :destroy, params: { id: exercise.files.first.id } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { delete :destroy, params: {id: exercise.files.first.id} } } + + before { perform_request.call } expect_assigns(file: CodeOcean::File) diff --git a/spec/controllers/consumers_controller_spec.rb b/spec/controllers/consumers_controller_spec.rb index 7ce2c378..209503a5 100644 --- a/spec/controllers/consumers_controller_spec.rb +++ b/spec/controllers/consumers_controller_spec.rb @@ -1,14 +1,18 @@ +# frozen_string_literal: true + require 'rails_helper' describe ConsumersController do let(:consumer) { FactoryBot.create(:consumer) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'POST #create' do context 'with a valid consumer' do - let(:perform_request) { proc { post :create, params: { consumer: FactoryBot.attributes_for(:consumer) } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, params: {consumer: FactoryBot.attributes_for(:consumer)} } } + + before { perform_request.call } expect_assigns(consumer: Consumer) @@ -20,7 +24,7 @@ describe ConsumersController do end context 'with an invalid consumer' do - before(:each) { post :create, params: { consumer: {} } } + before { post :create, params: {consumer: {}} } expect_assigns(consumer: Consumer) expect_status(200) @@ -29,20 +33,20 @@ describe ConsumersController do end describe 'DELETE #destroy' do - before(:each) { delete :destroy, params: { id: consumer.id } } + before { delete :destroy, params: {id: consumer.id} } expect_assigns(consumer: Consumer) it 'destroys the consumer' do consumer = FactoryBot.create(:consumer) - expect { delete :destroy, params: { id: consumer.id } }.to change(Consumer, :count).by(-1) + expect { delete :destroy, params: {id: consumer.id} }.to change(Consumer, :count).by(-1) end expect_redirect(:consumers) end describe 'GET #edit' do - before(:each) { get :edit, params: { id: consumer.id } } + before { get :edit, params: {id: consumer.id} } expect_assigns(consumer: Consumer) expect_status(200) @@ -51,7 +55,8 @@ describe ConsumersController do describe 'GET #index' do let!(:consumers) { FactoryBot.create_pair(:consumer) } - before(:each) { get :index } + + before { get :index } expect_assigns(consumers: Consumer.all) expect_status(200) @@ -59,7 +64,7 @@ describe ConsumersController do end describe 'GET #new' do - before(:each) { get :new } + before { get :new } expect_assigns(consumer: Consumer) expect_status(200) @@ -67,7 +72,7 @@ describe ConsumersController do end describe 'GET #show' do - before(:each) { get :show, params: { id: consumer.id } } + before { get :show, params: {id: consumer.id} } expect_assigns(consumer: :consumer) expect_status(200) @@ -76,14 +81,14 @@ describe ConsumersController do describe 'PUT #update' do context 'with a valid consumer' do - before(:each) { put :update, params: { consumer: FactoryBot.attributes_for(:consumer), id: consumer.id } } + before { put :update, params: {consumer: FactoryBot.attributes_for(:consumer), id: consumer.id} } expect_assigns(consumer: Consumer) expect_redirect(:consumer) end context 'with an invalid consumer' do - before(:each) { put :update, params: { consumer: {name: ''}, id: consumer.id } } + before { put :update, params: {consumer: {name: ''}, id: consumer.id} } expect_assigns(consumer: Consumer) expect_status(200) diff --git a/spec/controllers/error_template_attributes_controller_spec.rb b/spec/controllers/error_template_attributes_controller_spec.rb index d1cb3d4f..a80ee6a2 100644 --- a/spec/controllers/error_template_attributes_controller_spec.rb +++ b/spec/controllers/error_template_attributes_controller_spec.rb @@ -1,43 +1,46 @@ +# frozen_string_literal: true + require 'rails_helper' describe ErrorTemplateAttributesController do let!(:error_template_attribute) { FactoryBot.create(:error_template_attribute) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } - it "should get index" do + before { allow(controller).to receive(:current_user).and_return(user) } + + it 'gets index' do get :index expect(response.status).to eq(200) expect(assigns(:error_template_attributes)).not_to be_nil end - it "should get new" do + it 'gets new' do get :new expect(response.status).to eq(200) end - it "should create error_template_attribute" do - expect { post :create, params: { error_template_attribute: { } } }.to change(ErrorTemplateAttribute, :count).by(1) + it 'creates error_template_attribute' do + expect { post :create, params: {error_template_attribute: {}} }.to change(ErrorTemplateAttribute, :count).by(1) expect(response).to redirect_to(error_template_attribute_path(assigns(:error_template_attribute))) end - it "should show error_template_attribute" do - get :show, params: { id: error_template_attribute } + it 'shows error_template_attribute' do + get :show, params: {id: error_template_attribute} expect(response.status).to eq(200) end - it "should get edit" do - get :edit, params: { id: error_template_attribute } + it 'gets edit' do + get :edit, params: {id: error_template_attribute} expect(response.status).to eq(200) end - it "should update error_template_attribute" do - patch :update, params: { id: error_template_attribute, error_template_attribute: FactoryBot.attributes_for(:error_template_attribute) } + it 'updates error_template_attribute' do + patch :update, params: {id: error_template_attribute, error_template_attribute: FactoryBot.attributes_for(:error_template_attribute)} expect(response).to redirect_to(error_template_attribute_path(assigns(:error_template_attribute))) end - it "should destroy error_template_attribute" do - expect { delete :destroy, params: { id: error_template_attribute } }.to change(ErrorTemplateAttribute, :count).by(-1) + it 'destroys error_template_attribute' do + expect { delete :destroy, params: {id: error_template_attribute} }.to change(ErrorTemplateAttribute, :count).by(-1) expect(response).to redirect_to(error_template_attributes_path) end end diff --git a/spec/controllers/error_templates_controller_spec.rb b/spec/controllers/error_templates_controller_spec.rb index 9f5da525..4f7dfbaa 100644 --- a/spec/controllers/error_templates_controller_spec.rb +++ b/spec/controllers/error_templates_controller_spec.rb @@ -1,43 +1,46 @@ +# frozen_string_literal: true + require 'rails_helper' describe ErrorTemplatesController do let!(:error_template) { FactoryBot.create(:error_template) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } - it "should get index" do + before { allow(controller).to receive(:current_user).and_return(user) } + + it 'gets index' do get :index expect(response.status).to eq(200) expect(assigns(:error_templates)).not_to be_nil end - it "should get new" do + it 'gets new' do get :new expect(response.status).to eq(200) end - it "should create error_template" do - expect { post :create, params: {error_template: { execution_environment_id: error_template.execution_environment.id } } }.to change(ErrorTemplate, :count).by(1) + it 'creates error_template' do + expect { post :create, params: {error_template: {execution_environment_id: error_template.execution_environment.id}} }.to change(ErrorTemplate, :count).by(1) expect(response).to redirect_to(error_template_path(assigns(:error_template))) end - it "should show error_template" do - get :show, params: { id: error_template } + it 'shows error_template' do + get :show, params: {id: error_template} expect(response.status).to eq(200) end - it "should get edit" do - get :edit, params: { id: error_template } + it 'gets edit' do + get :edit, params: {id: error_template} expect(response.status).to eq(200) end - it "should update error_template" do - patch :update, params: { id: error_template, error_template: FactoryBot.attributes_for(:error_template) } + it 'updates error_template' do + patch :update, params: {id: error_template, error_template: FactoryBot.attributes_for(:error_template)} expect(response).to redirect_to(error_template_path(assigns(:error_template))) end - it "should destroy error_template" do - expect { delete :destroy, params: { id: error_template } }.to change(ErrorTemplate, :count).by(-1) + it 'destroys error_template' do + expect { delete :destroy, params: {id: error_template} }.to change(ErrorTemplate, :count).by(-1) expect(response).to redirect_to(error_templates_path) end end diff --git a/spec/controllers/events_controller_spec.rb b/spec/controllers/events_controller_spec.rb index b414a860..e59922cd 100644 --- a/spec/controllers/events_controller_spec.rb +++ b/spec/controllers/events_controller_spec.rb @@ -1,14 +1,18 @@ +# frozen_string_literal: true + require 'rails_helper' describe EventsController do let(:user) { FactoryBot.create(:admin) } - let(:exercise) {FactoryBot.create(:fibonacci)} - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + let(:exercise) { FactoryBot.create(:fibonacci) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'POST #create' do context 'with a valid event' do - let(:perform_request) { proc { post :create, params: { event: {category: 'foo', data: 'bar', exercise_id: exercise.id, file_id: exercise.files[0].id} } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, params: {event: {category: 'foo', data: 'bar', exercise_id: exercise.id, file_id: exercise.files[0].id}} } } + + before { perform_request.call } expect_assigns(event: Event) @@ -20,13 +24,15 @@ describe EventsController do end context 'with an invalid event' do - before(:each) { post :create, params: { event: {exercise_id: 847482} } } + before { post :create, params: {event: {exercise_id: 847_482}} } + expect_assigns(event: Event) expect_status(422) end context 'with no event' do - before(:each) { post :create } + before { post :create } + expect_status(422) end end diff --git a/spec/controllers/execution_environments_controller_spec.rb b/spec/controllers/execution_environments_controller_spec.rb index 60f738d8..6dc8a95f 100644 --- a/spec/controllers/execution_environments_controller_spec.rb +++ b/spec/controllers/execution_environments_controller_spec.rb @@ -1,16 +1,20 @@ +# frozen_string_literal: true + require 'rails_helper' describe ExecutionEnvironmentsController do let(:execution_environment) { FactoryBot.create(:ruby) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'POST #create' do - before(:each) { expect(DockerClient).to receive(:image_tags).at_least(:once).and_return([]) } + before { expect(DockerClient).to receive(:image_tags).at_least(:once).and_return([]) } context 'with a valid execution environment' do - let(:perform_request) { proc { post :create, params: { execution_environment: FactoryBot.build(:ruby).attributes } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, params: {execution_environment: FactoryBot.build(:ruby).attributes} } } + + before { perform_request.call } expect_assigns(docker_images: Array) expect_assigns(execution_environment: ExecutionEnvironment) @@ -23,7 +27,7 @@ describe ExecutionEnvironmentsController do end context 'with an invalid execution environment' do - before(:each) { post :create, params: { execution_environment: {} } } + before { post :create, params: {execution_environment: {}} } expect_assigns(execution_environment: ExecutionEnvironment) expect_status(200) @@ -32,22 +36,22 @@ describe ExecutionEnvironmentsController do end describe 'DELETE #destroy' do - before(:each) { delete :destroy, params: { id: execution_environment.id } } + before { delete :destroy, params: {id: execution_environment.id} } expect_assigns(execution_environment: :execution_environment) it 'destroys the execution environment' do execution_environment = FactoryBot.create(:ruby) - expect { delete :destroy, params: { id: execution_environment.id } }.to change(ExecutionEnvironment, :count).by(-1) + expect { delete :destroy, params: {id: execution_environment.id} }.to change(ExecutionEnvironment, :count).by(-1) end expect_redirect(:execution_environments) end describe 'GET #edit' do - before(:each) do + before do expect(DockerClient).to receive(:image_tags).at_least(:once).and_return([]) - get :edit, params: { id: execution_environment.id } + get :edit, params: {id: execution_environment.id} end expect_assigns(docker_images: Array) @@ -59,10 +63,10 @@ describe ExecutionEnvironmentsController do describe 'POST #execute_command' do let(:command) { 'which ruby' } - before(:each) do + before do expect(DockerClient).to receive(:new).with(execution_environment: execution_environment).and_call_original expect_any_instance_of(DockerClient).to receive(:execute_arbitrary_command).with(command) - post :execute_command, params: { command: command, id: execution_environment.id } + post :execute_command, params: {command: command, id: execution_environment.id} end expect_assigns(docker_client: DockerClient) @@ -73,7 +77,8 @@ describe ExecutionEnvironmentsController do describe 'GET #index' do before(:all) { FactoryBot.create_pair(:ruby) } - before(:each) { get :index } + + before { get :index } expect_assigns(execution_environments: ExecutionEnvironment.all) expect_status(200) @@ -81,7 +86,7 @@ describe ExecutionEnvironmentsController do end describe 'GET #new' do - before(:each) do + before do expect(DockerClient).to receive(:image_tags).at_least(:once).and_return([]) get :new end @@ -96,7 +101,7 @@ describe ExecutionEnvironmentsController do context 'when Docker is available' do let(:docker_images) { [1, 2, 3] } - before(:each) do + before do expect(DockerClient).to receive(:check_availability!).at_least(:once) expect(DockerClient).to receive(:image_tags).and_return(docker_images) controller.send(:set_docker_images) @@ -108,7 +113,7 @@ describe ExecutionEnvironmentsController do context 'when Docker is unavailable' do let(:error_message) { 'Docker is unavailable' } - before(:each) do + before do expect(DockerClient).to receive(:check_availability!).at_least(:once).and_raise(DockerClient::Error.new(error_message)) controller.send(:set_docker_images) end @@ -123,7 +128,7 @@ describe ExecutionEnvironmentsController do end describe 'GET #shell' do - before(:each) { get :shell, params: { id: execution_environment.id } } + before { get :shell, params: {id: execution_environment.id} } expect_assigns(execution_environment: :execution_environment) expect_status(200) @@ -131,7 +136,7 @@ describe ExecutionEnvironmentsController do end describe 'GET #statistics' do - before(:each) { get :statistics, params: { id: execution_environment.id } } + before { get :statistics, params: {id: execution_environment.id} } expect_assigns(execution_environment: :execution_environment) expect_status(200) @@ -139,7 +144,7 @@ describe ExecutionEnvironmentsController do end describe 'GET #show' do - before(:each) { get :show, params: { id: execution_environment.id } } + before { get :show, params: {id: execution_environment.id} } expect_assigns(execution_environment: :execution_environment) expect_status(200) @@ -148,9 +153,9 @@ describe ExecutionEnvironmentsController do describe 'PUT #update' do context 'with a valid execution environment' do - before(:each) do + before do expect(DockerClient).to receive(:image_tags).at_least(:once).and_return([]) - put :update, params: { execution_environment: FactoryBot.attributes_for(:ruby), id: execution_environment.id } + put :update, params: {execution_environment: FactoryBot.attributes_for(:ruby), id: execution_environment.id} end expect_assigns(docker_images: Array) @@ -159,7 +164,7 @@ describe ExecutionEnvironmentsController do end context 'with an invalid execution environment' do - before(:each) { put :update, params: { execution_environment: {name: ''}, id: execution_environment.id } } + before { put :update, params: {execution_environment: {name: ''}, id: execution_environment.id} } expect_assigns(execution_environment: ExecutionEnvironment) expect_status(200) diff --git a/spec/controllers/exercises_controller_spec.rb b/spec/controllers/exercises_controller_spec.rb index afb620aa..fc30eb21 100644 --- a/spec/controllers/exercises_controller_spec.rb +++ b/spec/controllers/exercises_controller_spec.rb @@ -5,12 +5,14 @@ require 'rails_helper' describe ExercisesController do let(:exercise) { FactoryBot.create(:dummy) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'PUT #batch_update' do - let(:attributes) { { 'public': 'true'} } - let(:perform_request) { proc { put :batch_update, params: { exercises: {0 => attributes.merge(id: exercise.id)} } } } - before(:each) { perform_request.call } + let(:attributes) { {public: 'true'} } + let(:perform_request) { proc { put :batch_update, params: {exercises: {0 => attributes.merge(id: exercise.id)}} } } + + before { perform_request.call } it 'updates the exercises' do expect_any_instance_of(Exercise).to receive(:update).with(attributes) @@ -22,10 +24,10 @@ describe ExercisesController do end describe 'POST #clone' do - let(:perform_request) { proc { post :clone, params: { id: exercise.id } } } + let(:perform_request) { proc { post :clone, params: {id: exercise.id} } } context 'when saving succeeds' do - before(:each) { perform_request.call } + before { perform_request.call } expect_assigns(exercise: Exercise) @@ -42,7 +44,7 @@ describe ExercisesController do end context 'when saving fails' do - before(:each) do + before do expect_any_instance_of(Exercise).to receive(:save).and_return(false) perform_request.call end @@ -57,8 +59,9 @@ describe ExercisesController do let(:exercise_attributes) { FactoryBot.build(:dummy).attributes } context 'with a valid exercise' do - let(:perform_request) { proc { post :create, params: { exercise: exercise_attributes } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, params: {exercise: exercise_attributes} } } + + before { perform_request.call } expect_assigns(exercise: Exercise) @@ -70,7 +73,7 @@ describe ExercisesController do end context 'when including a file' do - let(:perform_request) { proc { post :create, params: { exercise: exercise_attributes.merge(files_attributes: files_attributes) } } } + let(:perform_request) { proc { post :create, params: {exercise: exercise_attributes.merge(files_attributes: files_attributes)} } } context 'when specifying the file content within the form' do let(:files_attributes) { {'0' => FactoryBot.build(:file).attributes} } @@ -116,7 +119,7 @@ describe ExercisesController do end context 'with an invalid exercise' do - before(:each) { post :create, params: { exercise: { } } } + before { post :create, params: {exercise: {}} } expect_assigns(exercise: Exercise) expect_status(200) @@ -125,20 +128,20 @@ describe ExercisesController do end describe 'DELETE #destroy' do - before(:each) { delete :destroy, params: { id: exercise.id } } + before { delete :destroy, params: {id: exercise.id} } expect_assigns(exercise: :exercise) it 'destroys the exercise' do exercise = FactoryBot.create(:dummy) - expect { delete :destroy, params: { id: exercise.id } }.to change(Exercise, :count).by(-1) + expect { delete :destroy, params: {id: exercise.id} }.to change(Exercise, :count).by(-1) end expect_redirect(:exercises) end describe 'GET #edit' do - before(:each) { get :edit, params: { id: exercise.id } } + before { get :edit, params: {id: exercise.id} } expect_assigns(exercise: :exercise) expect_status(200) @@ -146,11 +149,12 @@ describe ExercisesController do end describe 'GET #implement' do - let(:perform_request) { proc { get :implement, params: { id: exercise.id } } } + let(:perform_request) { proc { get :implement, params: {id: exercise.id} } } context 'with an exercise with visible files' do let(:exercise) { FactoryBot.create(:fibonacci) } - before(:each) { perform_request.call } + + before { perform_request.call } expect_assigns(exercise: :exercise) @@ -174,7 +178,7 @@ describe ExercisesController do end context 'with an exercise without visible files' do - before(:each) { perform_request.call } + before { perform_request.call } expect_assigns(exercise: :exercise) expect_flash_message(:alert, :'exercises.implement.no_files') @@ -184,8 +188,10 @@ describe ExercisesController do describe 'GET #index' do let(:scope) { Pundit.policy_scope!(user, Exercise) } + before(:all) { FactoryBot.create_pair(:dummy) } - before(:each) { get :index } + + before { get :index } expect_assigns(exercises: :scope) expect_status(200) @@ -193,7 +199,7 @@ describe ExercisesController do end describe 'GET #new' do - before(:each) { get :new } + before { get :new } expect_assigns(execution_environments: ExecutionEnvironment.all, exercise: Exercise) expect_assigns(exercise: Exercise) @@ -203,7 +209,7 @@ describe ExercisesController do describe 'GET #show' do context 'as admin' do - before(:each) { get :show, params: { id: exercise.id } } + before { get :show, params: {id: exercise.id} } expect_assigns(exercise: :exercise) expect_status(200) @@ -213,7 +219,7 @@ describe ExercisesController do describe 'GET #reload' do context 'as anyone' do - before(:each) { get :reload, format: :json, params: { id: exercise.id } } + before { get :reload, format: :json, params: {id: exercise.id} } expect_assigns(exercise: :exercise) expect_status(200) @@ -222,7 +228,7 @@ describe ExercisesController do end describe 'GET #statistics' do - before(:each) { get :statistics, params: { id: exercise.id } } + before { get :statistics, params: {id: exercise.id} } expect_assigns(exercise: :exercise) expect_status(200) @@ -231,23 +237,23 @@ describe ExercisesController do describe 'POST #submit' do let(:output) { {} } - let(:perform_request) { post :submit, format: :json, params: { id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id} } } + let(:perform_request) { post :submit, format: :json, params: {id: exercise.id, submission: {cause: 'submit', exercise_id: exercise.id}} } let(:user) { FactoryBot.create(:external_user) } let!(:lti_parameter) { FactoryBot.create(:lti_parameter, external_user: user, exercise: exercise) } - before(:each) do + before do allow_any_instance_of(Submission).to receive(:normalized_score).and_return(1) expect(controller).to receive(:collect_test_results).and_return([{score: 1, weight: 1}]) expect(controller).to receive(:score_submission).and_call_original end context 'when LTI outcomes are supported' do - before(:each) do + before do expect(controller).to receive(:lti_outcome_service?).and_return(true) end context 'when the score transmission succeeds' do - before(:each) do + before do expect(controller).to receive(:send_score).and_return(status: 'success') perform_request end @@ -263,7 +269,7 @@ describe ExercisesController do end context 'when the score transmission fails' do - before(:each) do + before do expect(controller).to receive(:send_score).and_return(status: 'unsupported') perform_request end @@ -280,7 +286,7 @@ describe ExercisesController do end context 'when LTI outcomes are not supported' do - before(:each) do + before do expect(controller).to receive(:lti_outcome_service?).and_return(false) expect(controller).not_to receive(:send_score) perform_request @@ -300,14 +306,15 @@ describe ExercisesController do describe 'PUT #update' do context 'with a valid exercise' do let(:exercise_attributes) { FactoryBot.build(:dummy).attributes } - before(:each) { put :update, params: { exercise: exercise_attributes, id: exercise.id } } + + before { put :update, params: {exercise: exercise_attributes, id: exercise.id} } expect_assigns(exercise: Exercise) expect_redirect(:exercise) end context 'with an invalid exercise' do - before(:each) { put :update, params: { exercise: {title: ''}, id: exercise.id } } + before { put :update, params: {exercise: {title: ''}, id: exercise.id} } expect_assigns(exercise: Exercise) expect_status(200) @@ -321,7 +328,7 @@ describe ExercisesController do describe 'POST #export_external_check' do render_views - let(:post_request) { post :export_external_check, params: { id: exercise.id } } + let(:post_request) { post :export_external_check, params: {id: exercise.id} } let!(:codeharbor_link) { FactoryBot.create(:codeharbor_link, user: user) } let(:external_check_hash) { {message: message, exercise_found: true, update_right: update_right, error: error} } let(:message) { 'message' } @@ -509,7 +516,7 @@ describe ExercisesController do end context 'when the imported exercise is invalid' do - before { allow(ProformaService::Import).to receive(:call) { imported_exercise.tap { |e| e.files = [] }.tap { |e| e.title = nil } } } + before { allow(ProformaService::Import).to receive(:call) { imported_exercise.tap {|e| e.files = [] }.tap {|e| e.title = nil } } } it 'responds with correct status code' do expect { post_request }.not_to(change { imported_exercise.reload.files.count }) diff --git a/spec/controllers/external_users_controller_spec.rb b/spec/controllers/external_users_controller_spec.rb index 20699899..40286549 100644 --- a/spec/controllers/external_users_controller_spec.rb +++ b/spec/controllers/external_users_controller_spec.rb @@ -1,12 +1,15 @@ +# frozen_string_literal: true + require 'rails_helper' describe ExternalUsersController do let(:user) { FactoryBot.build(:admin) } let!(:users) { FactoryBot.create_pair(:external_user) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'GET #index' do - before(:each) { get :index } + before { get :index } expect_assigns(users: ExternalUser.all) expect_status(200) @@ -14,7 +17,7 @@ describe ExternalUsersController do end describe 'GET #show' do - before(:each) { get :show, params: { id: users.first.id } } + before { get :show, params: {id: users.first.id} } expect_assigns(user: ExternalUser) expect_status(200) diff --git a/spec/controllers/file_types_controller_spec.rb b/spec/controllers/file_types_controller_spec.rb index 1041d703..783b3599 100644 --- a/spec/controllers/file_types_controller_spec.rb +++ b/spec/controllers/file_types_controller_spec.rb @@ -1,14 +1,18 @@ +# frozen_string_literal: true + require 'rails_helper' describe FileTypesController do let(:file_type) { FactoryBot.create(:dot_rb) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'POST #create' do context 'with a valid file type' do - let(:perform_request) { proc { post :create, params: { file_type: FactoryBot.attributes_for(:dot_rb) } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, params: {file_type: FactoryBot.attributes_for(:dot_rb)} } } + + before { perform_request.call } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) @@ -21,7 +25,7 @@ describe FileTypesController do end context 'with an invalid file type' do - before(:each) { post :create, params: { file_type: { } } } + before { post :create, params: {file_type: {}} } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) @@ -31,20 +35,20 @@ describe FileTypesController do end describe 'DELETE #destroy' do - before(:each) { delete :destroy, params: { id: file_type.id } } + before { delete :destroy, params: {id: file_type.id} } expect_assigns(file_type: FileType) it 'destroys the file type' do file_type = FactoryBot.create(:dot_rb) - expect { delete :destroy, params: { id: file_type.id } }.to change(FileType, :count).by(-1) + expect { delete :destroy, params: {id: file_type.id} }.to change(FileType, :count).by(-1) end expect_redirect(:file_types) end describe 'GET #edit' do - before(:each) { get :edit, params: { id: file_type.id } } + before { get :edit, params: {id: file_type.id} } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) @@ -54,7 +58,8 @@ describe FileTypesController do describe 'GET #index' do before(:all) { FactoryBot.create_pair(:dot_rb) } - before(:each) { get :index } + + before { get :index } expect_assigns(file_types: FileType.all) expect_status(200) @@ -62,7 +67,7 @@ describe FileTypesController do end describe 'GET #new' do - before(:each) { get :new } + before { get :new } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) @@ -71,7 +76,7 @@ describe FileTypesController do end describe 'GET #show' do - before(:each) { get :show, params: { id: file_type.id } } + before { get :show, params: {id: file_type.id} } expect_assigns(file_type: :file_type) expect_status(200) @@ -80,7 +85,7 @@ describe FileTypesController do describe 'PUT #update' do context 'with a valid file type' do - before(:each) { put :update, params: { file_type: FactoryBot.attributes_for(:dot_rb), id: file_type.id } } + before { put :update, params: {file_type: FactoryBot.attributes_for(:dot_rb), id: file_type.id} } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) @@ -88,7 +93,7 @@ describe FileTypesController do end context 'with an invalid file type' do - before(:each) { put :update, params: { file_type: {name: ''}, id: file_type.id } } + before { put :update, params: {file_type: {name: ''}, id: file_type.id} } expect_assigns(editor_modes: Array) expect_assigns(file_type: FileType) diff --git a/spec/controllers/internal_users_controller_spec.rb b/spec/controllers/internal_users_controller_spec.rb index d354edde..5b12e492 100644 --- a/spec/controllers/internal_users_controller_spec.rb +++ b/spec/controllers/internal_users_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe InternalUsersController do @@ -7,28 +9,28 @@ describe InternalUsersController do describe 'GET #activate' do let(:user) { InternalUser.create(FactoryBot.attributes_for(:teacher)) } - before(:each) do + before do user.send(:setup_activation) user.save(validate: false) end context 'without a valid activation token' do - before(:each) { get :activate, params: { id: user.id } } + before { get :activate, params: {id: user.id} } expect_redirect(:root) end context 'with an already activated user' do - before(:each) do + before do user.activate! - get :activate, params: { id: user.id, token: user.activation_token } + get :activate, params: {id: user.id, token: user.activation_token} end expect_redirect(:root) end context 'with valid preconditions' do - before(:each) { get :activate, params: { id: user.id, token: user.activation_token } } + before { get :activate, params: {id: user.id, token: user.activation_token} } expect_assigns(user: InternalUser) expect_status(200) @@ -40,29 +42,29 @@ describe InternalUsersController do let(:user) { InternalUser.create(FactoryBot.build(:teacher).attributes) } let(:password) { SecureRandom.hex } - before(:each) do + before do user.send(:setup_activation) user.save(validate: false) expect(user.activation_token).to be_present end context 'without a valid activation token' do - before(:each) { put :activate, params: { id: user.id } } + before { put :activate, params: {id: user.id} } expect_redirect(:root) end context 'with an already activated user' do - before(:each) do + before do user.activate! - put :activate, params: { id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: password} } + put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: password}} end expect_redirect(:root) end context 'without a password' do - before(:each) { put :activate, params: { id: user.id, internal_user: {activation_token: user.activation_token} } } + before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token}} } expect_assigns(user: InternalUser) @@ -74,7 +76,7 @@ describe InternalUsersController do end context 'without a valid password confirmation' do - before(:each) { put :activate, params: { id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: ''} } } + before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: ''}} } expect_assigns(user: InternalUser) @@ -86,7 +88,7 @@ describe InternalUsersController do end context 'with valid preconditions' do - before(:each) { put :activate, params: { id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: password} } } + before { put :activate, params: {id: user.id, internal_user: {activation_token: user.activation_token, password: password, password_confirmation: password}} } expect_assigns(user: InternalUser) @@ -100,11 +102,12 @@ describe InternalUsersController do end describe 'POST #create' do - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + before { allow(controller).to receive(:current_user).and_return(user) } context 'with a valid internal user' do - let(:perform_request) { proc { post :create, params: { internal_user: FactoryBot.build(:teacher).attributes } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, params: {internal_user: FactoryBot.build(:teacher).attributes} } } + + before { perform_request.call } expect_assigns(user: InternalUser) @@ -129,7 +132,7 @@ describe InternalUsersController do end context 'with an invalid internal user' do - before(:each) { post :create, params: { internal_user: {} } } + before { post :create, params: {internal_user: {}} } expect_assigns(user: InternalUser) expect_status(200) @@ -138,24 +141,24 @@ describe InternalUsersController do end describe 'DELETE #destroy' do - before(:each) do + before do allow(controller).to receive(:current_user).and_return(user) - delete :destroy, params: { id: users.first.id } + delete :destroy, params: {id: users.first.id} end expect_assigns(user: InternalUser) it 'destroys the internal user' do - expect { delete :destroy, params: { id: InternalUser.last.id } }.to change(InternalUser, :count).by(-1) + expect { delete :destroy, params: {id: InternalUser.last.id} }.to change(InternalUser, :count).by(-1) end expect_redirect(:internal_users) end describe 'GET #edit' do - before(:each) do + before do allow(controller).to receive(:current_user).and_return(user) - get :edit, params: { id: users.first.id } + get :edit, params: {id: users.first.id} end expect_assigns(user: InternalUser) @@ -165,7 +168,7 @@ describe InternalUsersController do describe 'GET #forgot_password' do context 'when no user is logged in' do - before(:each) do + before do allow(controller).to receive(:set_sentry_context).and_return(nil) expect(controller).to receive(:current_user).and_return(nil) @@ -177,7 +180,7 @@ describe InternalUsersController do end context 'when a user is already logged in' do - before(:each) do + before do allow(controller).to receive(:set_sentry_context).and_return(nil) expect(controller).to receive(:current_user).and_return(user) @@ -191,8 +194,9 @@ describe InternalUsersController do describe 'POST #forgot_password' do context 'with an email address' do - let(:perform_request) { proc { post :forgot_password, params: { email: user.email } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :forgot_password, params: {email: user.email} } } + + before { perform_request.call } it 'delivers instructions to reset the password' do expect(InternalUser).to receive(:where).and_return([user]) @@ -204,7 +208,7 @@ describe InternalUsersController do end context 'without an email address' do - before(:each) { post :forgot_password } + before { post :forgot_password } expect_status(200) expect_template(:forgot_password) @@ -212,7 +216,7 @@ describe InternalUsersController do end describe 'GET #index' do - before(:each) do + before do allow(controller).to receive(:current_user).and_return(user) get :index end @@ -223,7 +227,7 @@ describe InternalUsersController do end describe 'GET #new' do - before(:each) do + before do allow(controller).to receive(:current_user).and_return(user) get :new end @@ -237,15 +241,15 @@ describe InternalUsersController do let(:user) { users.first } context 'without a valid password reset token' do - before(:each) { get :reset_password, params: { id: user.id } } + before { get :reset_password, params: {id: user.id} } expect_redirect(:root) end context 'with a valid password reset token' do - before(:each) do + before do user.deliver_reset_password_instructions! - get :reset_password, params: { id: user.id, token: user.reset_password_token } + get :reset_password, params: {id: user.id, token: user.reset_password_token} end expect_assigns(user: :user) @@ -256,10 +260,11 @@ describe InternalUsersController do describe 'PUT #reset_password' do let(:user) { users.first } - before(:each) { user.deliver_reset_password_instructions! } + + before { user.deliver_reset_password_instructions! } context 'without a valid password reset token' do - before(:each) { put :reset_password, params: { id: user.id } } + before { put :reset_password, params: {id: user.id} } expect_redirect(:root) end @@ -268,8 +273,9 @@ describe InternalUsersController do let(:password) { 'foo' } context 'with a matching password confirmation' do - let(:perform_request) { proc { put :reset_password, params: { internal_user: {password: password, password_confirmation: password}, id: user.id, token: user.reset_password_token } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { put :reset_password, params: {internal_user: {password: password, password_confirmation: password}, id: user.id, token: user.reset_password_token} } } + + before { perform_request.call } expect_assigns(user: :user) @@ -281,8 +287,8 @@ describe InternalUsersController do end context 'without a matching password confirmation' do - before(:each) do - put :reset_password, params: { internal_user: {password: password, password_confirmation: ''}, id: users.first.id, token: user.reset_password_token } + before do + put :reset_password, params: {internal_user: {password: password, password_confirmation: ''}, id: users.first.id, token: user.reset_password_token} end expect_assigns(user: :user) @@ -293,9 +299,9 @@ describe InternalUsersController do end describe 'GET #show' do - before(:each) do + before do allow(controller).to receive(:current_user).and_return(user) - get :show, params: { id: users.first.id } + get :show, params: {id: users.first.id} end expect_assigns(user: InternalUser) @@ -304,17 +310,17 @@ describe InternalUsersController do end describe 'PUT #update' do - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + before { allow(controller).to receive(:current_user).and_return(user) } context 'with a valid internal user' do - before(:each) { put :update, params: { internal_user: FactoryBot.attributes_for(:teacher), id: users.first.id } } + before { put :update, params: {internal_user: FactoryBot.attributes_for(:teacher), id: users.first.id} } expect_assigns(user: InternalUser) expect_redirect { user } end context 'with an invalid internal user' do - before(:each) { put :update, params: { internal_user: {email: ''}, id: users.first.id } } + before { put :update, params: {internal_user: {email: ''}, id: users.first.id} } expect_assigns(user: InternalUser) expect_status(200) diff --git a/spec/controllers/request_for_comments_controller_spec.rb b/spec/controllers/request_for_comments_controller_spec.rb index 95bf6aec..074aa644 100644 --- a/spec/controllers/request_for_comments_controller_spec.rb +++ b/spec/controllers/request_for_comments_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe RequestForCommentsController do @@ -24,7 +26,7 @@ describe RequestForCommentsController do rfc_other_study_group.user.update(study_groups: [another_study_group]) rfc_other_study_group.submission.update(study_group: another_study_group) - get :index, params: { "q[submission_study_group_id_in][]": my_study_group.id } + get :index, params: {"q[submission_study_group_id_in][]": my_study_group.id} expect(assigns(:request_for_comments)).to eq([rfc_within_my_study_group]) end @@ -47,7 +49,7 @@ describe RequestForCommentsController do describe 'GET #get_rfcs_for_exercise' do before do exercise = FactoryBot.create(:even_odd) - get :get_rfcs_for_exercise, params: { exercise_id: exercise.id } + get :get_rfcs_for_exercise, params: {exercise_id: exercise.id} end expect_status(200) diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index 043a7912..9d882c4a 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -11,9 +11,9 @@ describe SessionsController do let(:user_attributes) { FactoryBot.build(:teacher).attributes } context 'with valid credentials' do - before(:each) do + before do user.activate! - post :create, params: { email: user.email, password: password, remember_me: 1 } + post :create, params: {email: user.email, password: password, remember_me: 1} end expect_flash_message(:notice, :'sessions.create.success') @@ -21,7 +21,7 @@ describe SessionsController do end context 'with invalid credentials' do - before(:each) { post :create, params: { email: user.email, password: '', remember_me: 1 } } + before { post :create, params: {email: user.email, password: '', remember_me: 1} } expect_flash_message(:danger, :'sessions.create.failure') expect_template(:new) @@ -32,7 +32,8 @@ describe SessionsController do let(:exercise) { FactoryBot.create(:dummy) } let(:exercise2) { FactoryBot.create(:dummy) } let(:nonce) { SecureRandom.hex } - before(:each) { I18n.locale = I18n.default_locale } + + before { I18n.locale = I18n.default_locale } context 'without OAuth parameters' do it 'refuses the LTI launch' do @@ -44,14 +45,14 @@ describe SessionsController do context 'without a valid consumer key' do it 'refuses the LTI launch' do expect(controller).to receive(:refuse_lti_launch).with(message: I18n.t('sessions.oauth.invalid_consumer')).and_call_original - post :create_through_lti, params: { oauth_consumer_key: SecureRandom.hex, oauth_signature: SecureRandom.hex } + post :create_through_lti, params: {oauth_consumer_key: SecureRandom.hex, oauth_signature: SecureRandom.hex} end end context 'with an invalid OAuth signature' do it 'refuses the LTI launch' do expect(controller).to receive(:refuse_lti_launch).with(message: I18n.t('sessions.oauth.invalid_signature')).and_call_original - post :create_through_lti, params: { oauth_consumer_key: consumer.oauth_key, oauth_signature: SecureRandom.hex } + post :create_through_lti, params: {oauth_consumer_key: consumer.oauth_key, oauth_signature: SecureRandom.hex} end end @@ -60,7 +61,7 @@ describe SessionsController do expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true) expect(NonceStore).to receive(:has?).with(nonce).and_return(true) expect(controller).to receive(:refuse_lti_launch).with(message: I18n.t('sessions.oauth.used_nonce')).and_call_original - post :create_through_lti, params: { oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex } + post :create_through_lti, params: {oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex} end end @@ -68,15 +69,16 @@ describe SessionsController do it 'refuses the LTI launch' do expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true) expect(controller).to receive(:refuse_lti_launch).with(message: I18n.t('sessions.oauth.invalid_exercise_token')).and_call_original - post :create_through_lti, params: { custom_token: '', oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: '123' } + post :create_through_lti, params: {custom_token: '', oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: '123'} end end context 'with valid launch parameters' do let(:locale) { :de } - let(:perform_request) { post :create_through_lti, params: { custom_locale: locale, custom_token: exercise.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id } } + let(:perform_request) { post :create_through_lti, params: {custom_locale: locale, custom_token: exercise.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id} } let(:user) { FactoryBot.create(:external_user, consumer_id: consumer.id) } - before(:each) { expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true) } + + before { expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true) } it 'assigns the current user' do perform_request @@ -96,7 +98,7 @@ describe SessionsController do end it 'stores LTI parameters in the session' do - #Todo replace session with lti_parameter /should be done already + # Todo replace session with lti_parameter /should be done already expect(controller).to receive(:store_lti_session_data) perform_request end @@ -109,7 +111,7 @@ describe SessionsController do context 'when LTI outcomes are supported' do let(:message) { I18n.t('sessions.create_through_lti.session_with_outcome', consumer: consumer) } - before(:each) do + before do expect(controller).to receive(:lti_outcome_service?).and_return(true) perform_request end @@ -120,7 +122,7 @@ describe SessionsController do context 'when LTI outcomes are not supported' do let(:message) { I18n.t('sessions.create_through_lti.session_without_outcome', consumer: consumer) } - before(:each) do + before do expect(controller).to receive(:lti_outcome_service?).and_return(false) perform_request end @@ -135,7 +137,7 @@ describe SessionsController do it 'redirects to recommended exercise if requested token of proxy exercise' do FactoryBot.create(:proxy_exercise, exercises: [exercise]) - post :create_through_lti, params: { custom_locale: locale, custom_token: ProxyExercise.first.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id } + post :create_through_lti, params: {custom_locale: locale, custom_token: ProxyExercise.first.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id} expect(controller).to redirect_to(implement_exercise_path(exercise.id)) end @@ -146,7 +148,7 @@ describe SessionsController do exercise.save exercise2.expected_difficulty = 1 exercise2.save - post :create_through_lti, params: { custom_locale: locale, custom_token: ProxyExercise.first.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id } + post :create_through_lti, params: {custom_locale: locale, custom_token: ProxyExercise.first.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id} expect(controller).to redirect_to(implement_exercise_path(exercise2.id)) end end @@ -154,13 +156,14 @@ describe SessionsController do describe 'DELETE #destroy' do let(:user) { double } - before(:each) { + + before do allow(controller).to receive(:set_sentry_context).and_return(nil) expect(controller).to receive(:current_user).at_least(:once).and_return(user) - } + end context 'with an internal user' do - before(:each) do + before do allow(user).to receive(:external_user?).and_return(false) allow(user).to receive(:forget_me!) delete :destroy @@ -177,13 +180,13 @@ describe SessionsController do end context 'with an external user' do - before(:each) do + before do allow(user).to receive(:external_user?).and_return(true) delete :destroy end it 'clears the session' do - #Todo replace session with lti_parameter /should be done already + # Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) delete :destroy end @@ -195,19 +198,11 @@ describe SessionsController do end describe 'GET #destroy_through_lti' do - let(:perform_request) { proc { get :destroy_through_lti, params: { consumer_id: consumer.id, submission_id: submission.id } } } - let(:submission) { FactoryBot.create(:submission, exercise: FactoryBot.create(:dummy)) } - - before(:each) do - #Todo replace session with lti_parameter - #Todo create LtiParameter Object - # session[:lti_parameters] = {} - end - - before(:each) { perform_request.call } + let(:perform_request) { proc { get :destroy_through_lti, params: {consumer_id: consumer.id, submission_id: submission.id} } } + let(:submission) { FactoryBot.create(:submission, exercise: FactoryBot.create(:dummy)) } before { perform_request.call } it 'clears the session' do - #Todo replace session with lti_parameter /should be done already + # Todo replace session with lti_parameter /should be done already expect(controller).to receive(:clear_lti_session_data) perform_request.call end @@ -218,7 +213,7 @@ describe SessionsController do describe 'GET #new' do context 'when no user is logged in' do - before(:each) do + before do allow(controller).to receive(:set_sentry_context).and_return(nil) expect(controller).to receive(:current_user).and_return(nil) @@ -230,7 +225,7 @@ describe SessionsController do end context 'when a user is already logged in' do - before(:each) do + before do allow(controller).to receive(:set_sentry_context).and_return(nil) expect(controller).to receive(:current_user).and_return(FactoryBot.build(:teacher)) diff --git a/spec/controllers/statistics_controller_spec.rb b/spec/controllers/statistics_controller_spec.rb index c193315d..8ddd30c2 100644 --- a/spec/controllers/statistics_controller_spec.rb +++ b/spec/controllers/statistics_controller_spec.rb @@ -1,34 +1,36 @@ +# frozen_string_literal: true + require 'rails_helper' describe StatisticsController do let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } - [:show, :graphs].each do |route| + before { allow(controller).to receive(:current_user).and_return(user) } + + %i[show graphs].each do |route| describe "GET ##{route}" do - before(:each) { get route } + before { get route } expect_status(200) expect_template(route) end end - [:user_activity_history, :rfc_activity_history].each do |route| + %i[user_activity_history rfc_activity_history].each do |route| describe "GET ##{route}" do - before(:each) { get route } + before { get route } expect_status(200) expect_template(:activity_history) end end - [:show, :user_activity, :user_activity_history, :rfc_activity, :rfc_activity_history].each do |route| + %i[show user_activity user_activity_history rfc_activity rfc_activity_history].each do |route| describe "GET ##{route}.json" do - before(:each) { get route, format: :json } + before { get route, format: :json } expect_status(200) expect_json end end - end diff --git a/spec/controllers/submissions_controller_spec.rb b/spec/controllers/submissions_controller_spec.rb index 62dfdcd4..448c8bf6 100644 --- a/spec/controllers/submissions_controller_spec.rb +++ b/spec/controllers/submissions_controller_spec.rb @@ -1,19 +1,23 @@ +# frozen_string_literal: true + require 'rails_helper' describe SubmissionsController do let(:submission) { FactoryBot.create(:submission) } let(:user) { FactoryBot.create(:admin) } - before(:each) { allow(controller).to receive(:current_user).and_return(user) } + + before { allow(controller).to receive(:current_user).and_return(user) } describe 'POST #create' do - before(:each) do + before do controller.request.accept = 'application/json' end context 'with a valid submission' do let(:exercise) { FactoryBot.create(:hello_world) } - let(:perform_request) { proc { post :create, format: :json, params: { submission: FactoryBot.attributes_for(:submission, exercise_id: exercise.id) } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { post :create, format: :json, params: {submission: FactoryBot.attributes_for(:submission, exercise_id: exercise.id)} } } + + before { perform_request.call } expect_assigns(submission: Submission) @@ -26,7 +30,7 @@ describe SubmissionsController do end context 'with an invalid submission' do - before(:each) { post :create, params: { submission: { } } } + before { post :create, params: {submission: {}} } expect_assigns(submission: Submission) expect_json @@ -36,17 +40,18 @@ describe SubmissionsController do describe 'GET #download_file' do context 'with an invalid filename' do - before(:each) { get :download_file, params: { filename: SecureRandom.hex, id: submission.id } } + before { get :download_file, params: {filename: SecureRandom.hex, id: submission.id} } expect_status(404) end context 'with a valid binary filename' do let(:submission) { FactoryBot.create(:submission, exercise: FactoryBot.create(:sql_select)) } - before(:each) { get :download_file, params: { filename: file.name_with_extension, id: submission.id } } + + before { get :download_file, params: {filename: file.name_with_extension, id: submission.id} } context 'for a binary file' do - let(:file) { submission.collect_files.detect { |file| file.name == 'exercise' && file.file_type.file_extension == '.sql' } } + let(:file) { submission.collect_files.detect {|file| file.name == 'exercise' && file.file_type.file_extension == '.sql' } } expect_assigns(file: :file) expect_assigns(submission: :submission) @@ -61,10 +66,11 @@ describe SubmissionsController do context 'with a valid filename' do let(:submission) { FactoryBot.create(:submission, exercise: FactoryBot.create(:audio_video)) } - before(:each) { get :download_file, params: { filename: file.name_with_extension, id: submission.id } } + + before { get :download_file, params: {filename: file.name_with_extension, id: submission.id} } context 'for a binary file' do - let(:file) { submission.collect_files.detect { |file| file.file_type.file_extension == '.mp4' } } + let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.mp4' } } expect_assigns(file: :file) expect_assigns(submission: :submission) @@ -77,7 +83,7 @@ describe SubmissionsController do end context 'for a non-binary file' do - let(:file) { submission.collect_files.detect { |file| file.file_type.file_extension == '.js' } } + let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.js' } } expect_assigns(file: :file) expect_assigns(submission: :submission) @@ -93,7 +99,8 @@ describe SubmissionsController do describe 'GET #index' do before(:all) { FactoryBot.create_pair(:submission) } - before(:each) { get :index } + + before { get :index } expect_assigns(submissions: Submission.all) expect_status(200) @@ -104,17 +111,18 @@ describe SubmissionsController do let(:file) { submission.files.first } context 'with an invalid filename' do - before(:each) { get :render_file, params: { filename: SecureRandom.hex, id: submission.id } } + before { get :render_file, params: {filename: SecureRandom.hex, id: submission.id} } expect_status(404) end context 'with a valid filename' do let(:submission) { FactoryBot.create(:submission, exercise: FactoryBot.create(:audio_video)) } - before(:each) { get :render_file, params: { filename: file.name_with_extension, id: submission.id } } + + before { get :render_file, params: {filename: file.name_with_extension, id: submission.id} } context 'for a binary file' do - let(:file) { submission.collect_files.detect { |file| file.file_type.file_extension == '.mp4' } } + let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.mp4' } } expect_assigns(file: :file) expect_assigns(submission: :submission) @@ -127,7 +135,7 @@ describe SubmissionsController do end context 'for a non-binary file' do - let(:file) { submission.collect_files.detect { |file| file.file_type.file_extension == '.js' } } + let(:file) { submission.collect_files.detect {|file| file.file_type.file_extension == '.js' } } expect_assigns(file: :file) expect_assigns(submission: :submission) @@ -143,24 +151,24 @@ describe SubmissionsController do describe 'GET #run' do let(:filename) { submission.collect_files.detect(&:main_file?).name_with_extension } - let(:perform_request) { get :run, params: { filename: filename , id: submission.id } } + let(:perform_request) { get :run, params: {filename: filename, id: submission.id} } - before(:each) do + before do expect_any_instance_of(ActionController::Live::SSE).to receive(:write).at_least(3).times end context 'when no errors occur during execution' do - before(:each) do + before do expect_any_instance_of(DockerClient).to receive(:execute_run_command).with(submission, filename).and_return({}) perform_request end - pending("todo") + pending('todo') end end describe 'GET #show' do - before(:each) { get :show, params: { id: submission.id } } + before { get :show, params: {id: submission.id} } expect_assigns(submission: :submission) expect_status(200) @@ -172,11 +180,12 @@ describe SubmissionsController do # https://github.com/rails/jbuilder/issues/32 render_views - before(:each) { get :show, params: { id: submission.id }, format: :json } + before { get :show, params: {id: submission.id}, format: :json } + expect_assigns(submission: :submission) expect_status(200) - [:render, :run, :test].each do |action| + %i[render run test].each do |action| describe "##{action}_url" do let(:url) { JSON.parse(response.body).with_indifferent_access.fetch("#{action}_url") } @@ -186,45 +195,47 @@ describe SubmissionsController do end it 'ends with a placeholder' do - expect(url).to end_with(Submission::FILENAME_URL_PLACEHOLDER + '.json') + expect(url).to end_with("#{Submission::FILENAME_URL_PLACEHOLDER}.json") end end end - describe "#score_url" do - let(:url) { JSON.parse(response.body).with_indifferent_access.fetch("score_url") } + describe '#score_url' do + let(:url) { JSON.parse(response.body).with_indifferent_access.fetch('score_url') } - it "corresponds to the score path" do + it 'corresponds to the score path' do expect(url).to eq(Rails.application.routes.url_helpers.score_submission_path(submission, format: :json)) end end end describe 'GET #score' do - let(:perform_request) { proc { get :score, params: { id: submission.id } } } - before(:each) { perform_request.call } + let(:perform_request) { proc { get :score, params: {id: submission.id} } } - pending("todo: mock puma webserver or encapsulate tubesock call (Tubesock::HijackNotAvailable)") + before { perform_request.call } + + pending('todo: mock puma webserver or encapsulate tubesock call (Tubesock::HijackNotAvailable)') end describe 'GET #test' do let(:filename) { submission.collect_files.detect(&:teacher_defined_assessment?).name_with_extension } let(:output) { {} } - before(:each) do + before do expect_any_instance_of(DockerClient).to receive(:execute_test_command).with(submission, filename) - get :test, filename: filename, id: submission.id + get :test, params: {filename: filename, id: submission.id} end - pending("todo") + pending('todo') end describe '#with_server_sent_events' do let(:response) { ActionDispatch::TestResponse.new } - before(:each) { allow(controller).to receive(:response).and_return(response) } + + before { allow(controller).to receive(:response).and_return(response) } context 'when no error occurs' do - after(:each) { controller.send(:with_server_sent_events) } + after { controller.send(:with_server_sent_events) } it 'uses server-sent events' do expect(ActionController::Live::SSE).to receive(:new).and_call_original @@ -246,7 +257,7 @@ describe SubmissionsController do end context 'when an error occurs' do - after(:each) { controller.send(:with_server_sent_events) { fail } } + after { controller.send(:with_server_sent_events) { raise } } it 'uses server-sent events' do expect(ActionController::Live::SSE).to receive(:new).and_call_original diff --git a/spec/factories/code_ocean/file.rb b/spec/factories/code_ocean/file.rb index 61241593..3e3132ee 100644 --- a/spec/factories/code_ocean/file.rb +++ b/spec/factories/code_ocean/file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'seeds_helper' module CodeOcean diff --git a/spec/factories/codeharbor_link.rb b/spec/factories/codeharbor_link.rb index c960eb9a..1456c718 100644 --- a/spec/factories/codeharbor_link.rb +++ b/spec/factories/codeharbor_link.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + FactoryBot.define do factory :codeharbor_link do user { build(:teacher) } push_url { 'http://push.url' } check_uuid_url { 'http://check-uuid.url' } - sequence(:api_key) { |n| "api_key#{n}" } + sequence(:api_key) {|n| "api_key#{n}" } end end diff --git a/spec/factories/consumer.rb b/spec/factories/consumer.rb index 59b05b8d..06d19857 100644 --- a/spec/factories/consumer.rb +++ b/spec/factories/consumer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :consumer do name { 'openHPI' } diff --git a/spec/factories/error_template_attributes.rb b/spec/factories/error_template_attributes.rb index 74d6e559..c94462a5 100644 --- a/spec/factories/error_template_attributes.rb +++ b/spec/factories/error_template_attributes.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + FactoryBot.define do factory :error_template_attribute do - key { "MyString" } - regex { "MyString" } + key { 'MyString' } + regex { 'MyString' } end end diff --git a/spec/factories/error_templates.rb b/spec/factories/error_templates.rb index 41286229..a0556912 100644 --- a/spec/factories/error_templates.rb +++ b/spec/factories/error_templates.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + FactoryBot.define do factory :error_template do association :execution_environment, factory: :ruby - name { "MyString" } - signature { "MyString" } + name { 'MyString' } + signature { 'MyString' } end end diff --git a/spec/factories/execution_environment.rb b/spec/factories/execution_environment.rb index 3961441a..5c3b50ef 100644 --- a/spec/factories/execution_environment.rb +++ b/spec/factories/execution_environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :coffee_script, class: 'ExecutionEnvironment' do created_by_teacher diff --git a/spec/factories/exercise.rb b/spec/factories/exercise.rb index 20c460cc..07ed6243 100644 --- a/spec/factories/exercise.rb +++ b/spec/factories/exercise.rb @@ -4,13 +4,13 @@ require 'seeds_helper' def create_seed_file(exercise, path, file_attributes = {}) file_extension = File.extname(path) - file_type = FactoryBot.create(file_attributes[:file_type] || :"dot_#{file_extension.gsub('.', '')}") + file_type = FactoryBot.create(file_attributes[:file_type] || :"dot_#{file_extension.delete('.')}") name = File.basename(path).gsub(file_extension, '') file_attributes.merge!(file_type: file_type, name: name, path: path.split('/')[1..-2].join('/'), role: file_attributes[:role] || 'regular_file') if file_type.binary? - file_attributes.merge!(native_file: File.open(SeedsHelper.seed_file_path(path), 'r')) + file_attributes[:native_file] = File.open(SeedsHelper.seed_file_path(path), 'r') else - file_attributes.merge!(content: SeedsHelper.read_seed_file(path)) + file_attributes[:content] = SeedsHelper.read_seed_file(path) end exercise.add_file!(file_attributes) end diff --git a/spec/factories/external_user.rb b/spec/factories/external_user.rb index 41a9c3e8..d1439e1c 100644 --- a/spec/factories/external_user.rb +++ b/spec/factories/external_user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :external_user do association :consumer diff --git a/spec/factories/file_type.rb b/spec/factories/file_type.rb index f08e3b73..0dc823cc 100644 --- a/spec/factories/file_type.rb +++ b/spec/factories/file_type.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :dot_coffee, class: 'FileType' do created_by_admin diff --git a/spec/factories/lti_parameter.rb b/spec/factories/lti_parameter.rb index 3d2620ad..6d5044e1 100644 --- a/spec/factories/lti_parameter.rb +++ b/spec/factories/lti_parameter.rb @@ -1,10 +1,11 @@ -FactoryBot.define do +# frozen_string_literal: true +FactoryBot.define do LTI_PARAMETERS = { - lis_result_sourcedid: "c2db0c7c-4411-4b27-a52b-ddfc3dc32065", - lis_outcome_service_url: "http://172.16.54.235:3000/courses/0132156a-9afb-434d-83cc-704780104105/sections/21c6c6f4-1fb6-43b4-af3c-04fdc098879e/items/999b1fe6-d4b6-47b7-a577-ea2b4b1041ec/tool_grading", - launch_presentation_return_url: "http://172.16.54.235:3000/courses/0132156a-9afb-434d-83cc-704780104105/sections/21c6c6f4-1fb6-43b4-af3c-04fdc098879e/items/999b1fe6-d4b6-47b7-a577-ea2b4b1041ec/tool_return" - } + lis_result_sourcedid: 'c2db0c7c-4411-4b27-a52b-ddfc3dc32065', + lis_outcome_service_url: 'http://172.16.54.235:3000/courses/0132156a-9afb-434d-83cc-704780104105/sections/21c6c6f4-1fb6-43b4-af3c-04fdc098879e/items/999b1fe6-d4b6-47b7-a577-ea2b4b1041ec/tool_grading', + launch_presentation_return_url: 'http://172.16.54.235:3000/courses/0132156a-9afb-434d-83cc-704780104105/sections/21c6c6f4-1fb6-43b4-af3c-04fdc098879e/items/999b1fe6-d4b6-47b7-a577-ea2b4b1041ec/tool_return', + }.freeze factory :lti_parameter do association :consumer diff --git a/spec/factories/proxy_exercise.rb b/spec/factories/proxy_exercise.rb index a100f8d6..cefe808d 100644 --- a/spec/factories/proxy_exercise.rb +++ b/spec/factories/proxy_exercise.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + FactoryBot.define do factory :proxy_exercise, class: 'ProxyExercise' do created_by_teacher token { 'dummytoken' } title { 'Dummy' } end - end diff --git a/spec/factories/shared_traits.rb b/spec/factories/shared_traits.rb index 43847e8c..f9233cd6 100644 --- a/spec/factories/shared_traits.rb +++ b/spec/factories/shared_traits.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + FactoryBot.define do - [:admin, :external_user, :teacher].each do |factory_name| + %i[admin external_user teacher].each do |factory_name| trait :"created_by_#{factory_name}" do association :user, factory: factory_name end end trait :generated_email do - email { "#{name.underscore.gsub(' ', '.')}@example.org" } + email { "#{name.underscore.tr(' ', '.')}@example.org" } end trait :generated_user_name do diff --git a/spec/factories/structured_error_attributes.rb b/spec/factories/structured_error_attributes.rb index 5652f1b6..6349580d 100644 --- a/spec/factories/structured_error_attributes.rb +++ b/spec/factories/structured_error_attributes.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + FactoryBot.define do factory :structured_error_attribute do association :structured_error association :error_template_attribute - value { "MyString" } + value { 'MyString' } end end diff --git a/spec/factories/structured_errors.rb b/spec/factories/structured_errors.rb index 2b61e744..921e8ff6 100644 --- a/spec/factories/structured_errors.rb +++ b/spec/factories/structured_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :structured_error do association :error_template diff --git a/spec/factories/study_group.rb b/spec/factories/study_group.rb index 6256adde..be4ad0ae 100644 --- a/spec/factories/study_group.rb +++ b/spec/factories/study_group.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :study_group, class: 'StudyGroup' do association :consumer diff --git a/spec/factories/submission.rb b/spec/factories/submission.rb index 81cc33a9..39f9f338 100644 --- a/spec/factories/submission.rb +++ b/spec/factories/submission.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryBot.define do factory :submission do cause { 'save' } diff --git a/spec/factories/user_exercise_feedback.rb b/spec/factories/user_exercise_feedback.rb index ff0ff763..9c8de052 100644 --- a/spec/factories/user_exercise_feedback.rb +++ b/spec/factories/user_exercise_feedback.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + FactoryBot.define do factory :user_exercise_feedback, class: 'UserExerciseFeedback' do created_by_external_user feedback_text { 'Most suitable exercise ever' } association :exercise, factory: :math end - end diff --git a/spec/features/authentication_spec.rb b/spec/features/authentication_spec.rb index 31fd39fe..39704038 100644 --- a/spec/features/authentication_spec.rb +++ b/spec/features/authentication_spec.rb @@ -7,7 +7,7 @@ describe 'Authentication' do let(:password) { FactoryBot.attributes_for(:admin)[:password] } context 'when signed out' do - before(:each) { visit(root_path) } + before { visit(root_path) } it 'displays a sign in link' do expect(page).to have_content(I18n.t('sessions.new.link')) @@ -35,7 +35,7 @@ describe 'Authentication' do end context 'when signed in' do - before(:each) do + before do sign_in(user, password) visit(root_path) end diff --git a/spec/features/authorization_spec.rb b/spec/features/authorization_spec.rb index 97d7056d..4fedf09e 100644 --- a/spec/features/authorization_spec.rb +++ b/spec/features/authorization_spec.rb @@ -5,7 +5,8 @@ require 'rails_helper' describe 'Authorization' do context 'as an admin' do let(:user) { FactoryBot.create(:admin) } - before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } + + before { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } [Consumer, ExecutionEnvironment, Exercise, FileType, InternalUser].each do |model| expect_permitted_path(:"new_#{model.model_name.singular}_path") @@ -14,7 +15,8 @@ describe 'Authorization' do context 'as an external user' do let(:user) { FactoryBot.create(:external_user) } - before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } + + before { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } [Consumer, ExecutionEnvironment, Exercise, FileType, InternalUser].each do |model| expect_forbidden_path(:"new_#{model.model_name.singular}_path") @@ -23,7 +25,8 @@ describe 'Authorization' do context 'as a teacher' do let(:user) { FactoryBot.create(:teacher) } - before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } + + before { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } [Consumer, InternalUser, ExecutionEnvironment, FileType].each do |model| expect_forbidden_path(:"new_#{model.model_name.singular}_path") diff --git a/spec/features/editor_spec.rb b/spec/features/editor_spec.rb index f43451c8..74436cdc 100644 --- a/spec/features/editor_spec.rb +++ b/spec/features/editor_spec.rb @@ -19,7 +19,7 @@ describe 'Editor', js: true do score: 1.0, filename: 'index.html_spec.rb', message: 'Well done.', - weight: 2.0 + weight: 2.0, }] end let(:user) { FactoryBot.create(:teacher) } @@ -60,7 +60,7 @@ describe 'Editor', js: true do context 'when selecting a binary file' do context 'when selecting an audio file' do - let(:file) { exercise.files.detect { |file| file.file_type.audio? } } + let(:file) { exercise.files.detect {|file| file.file_type.audio? } } it 'contains an