├── .devcontainer ├── Dockerfile ├── compose.yaml └── devcontainer.json ├── .dockerignore ├── .gitattributes ├── .github ├── auto-merge.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── dependabot.yml │ └── sentry-release.yml ├── .gitignore ├── .gitlab-ci.yml ├── .rubocop.yml ├── .rubocop ├── layout.yml ├── lint.yml ├── metrics.yml ├── performance.yml ├── rails.yml ├── rspec.yml └── style.yml ├── .rubocop_todo.yml ├── .ruby-version ├── .slim-lint.yml ├── .yarnrc.yml ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── SECURITY.md ├── Vagrantfile ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ └── .keep │ ├── javascripts │ │ ├── application.js │ │ ├── base.js │ │ ├── bootstrap-dropdown-submenu.js │ │ ├── cable.js │ │ ├── channels │ │ │ ├── la_exercises.js │ │ │ ├── pg_matching_channel.js │ │ │ └── synchronized_editor_channel.js │ │ ├── codeharbor_link.js │ │ ├── community_solution.js │ │ ├── dashboard.js │ │ ├── editor.js │ │ ├── editor │ │ │ ├── ajax.js │ │ │ ├── editor.js.erb │ │ │ ├── evaluation.js │ │ │ ├── execution.js │ │ │ ├── participantsupport.js.erb │ │ │ ├── prompt.js │ │ │ ├── submissions.js │ │ │ ├── turtle.js │ │ │ └── websocket.js │ │ ├── error_templates.js │ │ ├── exercise_collections.js │ │ ├── exercise_graphs.js │ │ ├── exercises.js │ │ ├── external_users.js │ │ ├── file_types.js │ │ ├── forms.js │ │ ├── markdown_editor.js │ │ ├── programming_groups.js │ │ ├── request_for_comments.js │ │ ├── shell.js │ │ ├── statistics_activity_history.js │ │ ├── statistics_graphs.js │ │ ├── submission_statistics.js │ │ ├── turtle.js │ │ └── working_time_graphs.js │ ├── remote_scripts │ │ ├── macos.sh │ │ ├── ubuntu.sh │ │ └── windows.ps1 │ └── stylesheets │ │ ├── application.css │ │ ├── base.css.scss │ │ ├── bootstrap-dropdown-submenu.css.scss │ │ ├── comments.css.scss │ │ ├── editor.css.scss │ │ ├── error_templates.scss │ │ ├── exercise_collections.scss │ │ ├── exercises.css.scss │ │ ├── external_users.css.scss │ │ ├── file_templates.css.scss │ │ ├── flowrdata.css.scss │ │ ├── forms.css.scss │ │ ├── request-for-comments.css.scss │ │ └── statistics.css.scss ├── channels │ ├── application_cable │ │ ├── channel.rb │ │ └── connection.rb │ ├── la_exercises_channel.rb │ ├── pg_matching_channel.rb │ └── synchronized_editor_channel.rb ├── controllers │ ├── admin │ │ └── dashboard_controller.rb │ ├── application_controller.rb │ ├── code_ocean │ │ └── files_controller.rb │ ├── codeharbor_links_controller.rb │ ├── comments_controller.rb │ ├── community_solutions_controller.rb │ ├── concerns │ │ ├── common_behavior.rb │ │ ├── file_conversion.rb │ │ ├── file_parameters.rb │ │ ├── lti.rb │ │ ├── redirect_behavior.rb │ │ ├── remote_evaluation_parameters.rb │ │ ├── scoring_checks.rb │ │ ├── submission_parameters.rb │ │ └── webauthn │ │ │ ├── authentication.rb │ │ │ └── cookie.rb │ ├── consumers_controller.rb │ ├── error_template_attributes_controller.rb │ ├── error_templates_controller.rb │ ├── events_controller.rb │ ├── execution_environments_controller.rb │ ├── exercise_collections_controller.rb │ ├── exercises_controller.rb │ ├── external_users_controller.rb │ ├── file_templates_controller.rb │ ├── file_types_controller.rb │ ├── flowr_controller.rb │ ├── internal_users_controller.rb │ ├── live_streams_controller.rb │ ├── ping_controller.rb │ ├── programming_groups_controller.rb │ ├── proxy_exercises_controller.rb │ ├── rails_admin_controller.rb │ ├── remote_evaluation_controller.rb │ ├── request_for_comments_controller.rb │ ├── sessions_controller.rb │ ├── statistics_controller.rb │ ├── study_groups_controller.rb │ ├── submissions_controller.rb │ ├── subscriptions_controller.rb │ ├── tags_controller.rb │ ├── tips_controller.rb │ ├── user_exercise_feedbacks_controller.rb │ ├── webauthn_credential_authentication_controller.rb │ └── webauthn_credentials_controller.rb ├── errors │ ├── application_error.rb │ ├── proformaxml │ │ ├── exercise_not_owned.rb │ │ └── invalid_zip.rb │ └── runner │ │ ├── connection │ │ └── buffer │ │ │ └── error.rb │ │ └── error.rb ├── helpers │ ├── action_cable_helper.rb │ ├── admin │ │ └── dashboard_helper.rb │ ├── application_helper.rb │ ├── authenticated_url_helper.rb │ ├── exercise_helper.rb │ ├── i18n_helper.rb │ ├── lti_helper.rb │ ├── markdown_form_builder.rb │ ├── statistics_helper.rb │ └── time_helper.rb ├── javascript │ ├── application.js │ ├── chosen-dark.scss │ ├── d3-tip.js │ ├── highlight.js │ ├── highlight.scss │ ├── rails_admin.js │ ├── rails_admin.scss │ ├── sortable.js │ ├── stylesheets.scss │ ├── toast-ui.js │ ├── toast-ui.scss │ ├── vis.js │ ├── vis.scss │ └── webauthn.js ├── jobs │ ├── application_job.rb │ ├── concerns │ │ └── active_record_logging.rb │ └── detect_exercise_anomalies_job.rb ├── mailers │ ├── application_mailer.rb │ └── user_mailer.rb ├── models │ ├── anomaly_notification.rb │ ├── application_record.rb │ ├── authentication_token.rb │ ├── code_ocean │ │ └── file.rb │ ├── codeharbor_link.rb │ ├── comment.rb │ ├── community_solution.rb │ ├── community_solution_contribution.rb │ ├── community_solution_lock.rb │ ├── concerns │ │ ├── context.rb │ │ ├── contributor_creation.rb │ │ ├── creation.rb │ │ ├── default_values.rb │ │ └── ransack_object.rb │ ├── consumer.rb │ ├── contributor.rb │ ├── error_template.rb │ ├── error_template_attribute.rb │ ├── event.rb │ ├── event │ │ └── synchronized_editor.rb │ ├── execution_environment.rb │ ├── exercise.rb │ ├── exercise_collection.rb │ ├── exercise_collection_item.rb │ ├── exercise_tag.rb │ ├── exercise_tip.rb │ ├── external_user.rb │ ├── file_template.rb │ ├── file_type.rb │ ├── internal_user.rb │ ├── intervention.rb │ ├── linter_check.rb │ ├── linter_check_run.rb │ ├── lti_parameter.rb │ ├── pair_programming_exercise_feedback.rb │ ├── pair_programming_waiting_user.rb │ ├── programming_group.rb │ ├── programming_group_membership.rb │ ├── proxy_exercise.rb │ ├── remote_evaluation_mapping.rb │ ├── request_for_comment.rb │ ├── runner.rb │ ├── structured_error.rb │ ├── structured_error_attribute.rb │ ├── study_group.rb │ ├── study_group_membership.rb │ ├── submission.rb │ ├── subscription.rb │ ├── tag.rb │ ├── testrun.rb │ ├── testrun_execution_environment.rb │ ├── testrun_message.rb │ ├── tip.rb │ ├── user.rb │ ├── user_exercise_feedback.rb │ ├── user_exercise_intervention.rb │ ├── user_proxy_exercise_exercise.rb │ └── webauthn_credential.rb ├── policies │ ├── admin │ │ └── dashboard_policy.rb │ ├── admin_only_policy.rb │ ├── admin_or_author_policy.rb │ ├── application_policy.rb │ ├── code_ocean │ │ └── file_policy.rb │ ├── codeharbor_link_policy.rb │ ├── comment_policy.rb │ ├── community_solution_policy.rb │ ├── consumer_policy.rb │ ├── error_template_attribute_policy.rb │ ├── error_template_policy.rb │ ├── event_policy.rb │ ├── execution_environment_policy.rb │ ├── exercise_collection_policy.rb │ ├── exercise_policy.rb │ ├── external_user_policy.rb │ ├── file_template_policy.rb │ ├── file_type_policy.rb │ ├── internal_user_policy.rb │ ├── programming_group_policy.rb │ ├── proxy_exercise_policy.rb │ ├── request_for_comment_policy.rb │ ├── statistics_policy.rb │ ├── study_group_policy.rb │ ├── submission_policy.rb │ ├── subscription_policy.rb │ ├── tag_policy.rb │ ├── tip_policy.rb │ ├── user_exercise_feedback_policy.rb │ ├── webauthn_credential_authentication_policy.rb │ └── webauthn_credential_policy.rb ├── serializers │ └── hash_as_jsonb_serializer.rb ├── services │ ├── exercise_service.rb │ ├── exercise_service │ │ ├── check_external.rb │ │ └── push_external.rb │ ├── proforma_service │ │ ├── convert_exercise_to_task.rb │ │ ├── convert_task_to_exercise.rb │ │ ├── export_task.rb │ │ ├── import.rb │ │ └── uuid_from_zip.rb │ └── service_base.rb ├── uploaders │ ├── file_uploader.rb │ └── proforma_zip_uploader.rb ├── validators │ ├── array_validator.rb │ └── code_ocean │ │ └── file_name_validator.rb └── views │ ├── admin │ └── dashboard │ │ └── show.html.slim │ ├── application │ ├── _breadcrumbs_and_title.html.slim │ ├── _color_mode_selector.html.slim │ ├── _flash.html.slim │ ├── _locale_selector.html.slim │ ├── _navigation.html.slim │ ├── _navigation_collection_link.html.slim │ ├── _navigation_submenu.html.slim │ ├── _session.html.slim │ ├── help.html.slim │ └── welcome.html.slim │ ├── code_ocean │ └── files │ │ ├── _form.html.slim │ │ └── show.json.jbuilder │ ├── codeharbor_links │ ├── _form.html.slim │ ├── edit.html.slim │ └── new.html.slim │ ├── comments │ ├── index.json.jbuilder │ └── show.json.jbuilder │ ├── community_solutions │ ├── _form.html.slim │ ├── edit.html.slim │ └── index.html.slim │ ├── consumers │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── error_template_attributes │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── error_templates │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── execution_environments │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── shell.html.slim │ ├── show.html.slim │ └── statistics.html.slim │ ├── exercise_collections │ ├── _add_exercise_modal.slim │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── show.html.slim │ └── statistics.html.slim │ ├── exercises │ ├── _add_tip_modal.slim │ ├── _code_field.html.slim │ ├── _comment_dialogcontent.html.slim │ ├── _download_file_tree.html.slim │ ├── _editor.html.slim │ ├── _editor_button.html.slim │ ├── _editor_edit.html.slim │ ├── _editor_file_tree.html.slim │ ├── _editor_frame.html.slim │ ├── _editor_output.html.slim │ ├── _export_actions.html.slim │ ├── _file_form.html.slim │ ├── _form.html.slim │ ├── _import_actions.html.slim │ ├── _request_comment_dialogcontent.html.slim │ ├── _tips_content.html.slim │ ├── _transfer_dialogcontent.html.slim │ ├── edit.html.slim │ ├── external_users │ │ └── statistics.html.slim │ ├── feedback.html.slim │ ├── implement.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── reload.json.jbuilder │ ├── show.html.slim │ ├── statistics.html.slim │ └── study_group_dashboard.html.slim │ ├── external_users │ ├── index.html.slim │ ├── show.html.slim │ └── statistics.html.slim │ ├── file_templates │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── file_types │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── show.html.slim │ └── show.json.jbuilder │ ├── internal_users │ ├── _form.html.slim │ ├── activate.html.slim │ ├── change_password.html.slim │ ├── edit.html.slim │ ├── forgot_password.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── reset_password.html.slim │ └── show.html.slim │ ├── interventions │ ├── _break_intervention_modal.html.slim │ └── _tips_intervention_modal.html.slim │ ├── layouts │ ├── application.html.slim │ ├── mailer.html.slim │ └── mailer.text.slim │ ├── programming_groups │ ├── _form.html.slim │ ├── _form_edit.html.slim │ ├── _info_pair_programming.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── proxy_exercises │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── pwa │ ├── manifest.webmanifest.jbuilder │ └── service-worker.js │ ├── request_for_comments │ ├── _admin_menu.html.slim │ ├── _list_entry.html.slim │ ├── _mark_as_solved.html.slim │ ├── index.html.slim │ ├── index.json.jbuilder │ ├── show.html.slim │ └── show.json.jbuilder │ ├── sessions │ ├── destroy_through_lti.html.slim │ └── new.html.slim │ ├── shared │ ├── _edit_button.html.slim │ ├── _file.html.slim │ ├── _form_errors.html.slim │ ├── _form_filters.html.slim │ ├── _modal.html.slim │ ├── _new_button.html.slim │ ├── _pagination.html.slim │ └── _submit_button.html.slim │ ├── statistics │ ├── activity_history.html.slim │ ├── graphs.html.slim │ └── show.html.slim │ ├── study_groups │ ├── _form.html.slim │ ├── _table.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ └── show.html.slim │ ├── submissions │ ├── index.html.slim │ ├── show.html.slim │ ├── show.json.jbuilder │ └── statistics.html.slim │ ├── tags │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── tips │ ├── _collapsed_card.html.slim │ ├── _form.html.slim │ ├── _sortable_tip.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── user_exercise_feedbacks │ ├── _form.html.slim │ ├── edit.html.slim │ └── new.html.slim │ ├── user_mailer │ ├── activation_needed_email.html.slim │ ├── exercise_anomaly_detected.html.slim │ ├── exercise_anomaly_needs_feedback.html.slim │ ├── got_new_comment.slim │ ├── got_new_comment_for_subscription.html.slim │ ├── reset_password_email.html.slim │ └── send_thank_you_note.slim │ ├── webauthn_credential_authentication │ ├── _form.html.slim │ └── new.html.slim │ └── webauthn_credentials │ ├── _form.html.slim │ ├── _list.html.slim │ ├── edit.html.slim │ ├── new.html.slim │ └── show.html.slim ├── bin ├── brakeman ├── bundle ├── dev ├── docker-entrypoint ├── jobs ├── rails ├── rake ├── rubocop ├── setup ├── shakapacker ├── shakapacker-dev-server └── thrust ├── config.ru ├── config ├── action_mailer.yml.ci ├── action_mailer.yml.example ├── application.rb ├── boot.rb ├── brakeman.ignore ├── cable.yml ├── code_ocean.yml.ci ├── code_ocean.yml.example ├── content_security_policy.yml.ci ├── content_security_policy.yml.example ├── database.yml.ci ├── database.yml.example ├── docker.yml.erb.ci ├── docker.yml.erb.example ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ ├── staging.rb │ └── test.rb ├── i18n-tasks.yml ├── i18n.yml ├── initializers │ ├── action_mailer.rb │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── filter_parameter_logging.rb │ ├── github_codespaces.rb │ ├── i18n.rb │ ├── inflections.rb │ ├── js_routes.rb │ ├── mime_types.rb │ ├── monkey_patches.rb │ ├── permissions_policy.rb │ ├── prometheus.rb │ ├── rails_admin.rb │ ├── ransack.rb │ ├── sentry.rb │ ├── sentry_csp.rb │ ├── sentry_javascript.rb │ ├── session_store.rb │ ├── sorcery.rb │ ├── webauthn.rb │ ├── will_paginate.rb │ └── wrap_parameters.rb ├── locales │ ├── de │ │ ├── admin │ │ │ └── dashboard.yml │ │ ├── code_ocean │ │ │ └── file.yml │ │ ├── codeharbor_link.yml │ │ ├── comment.yml │ │ ├── community_solution.yml │ │ ├── consumer.yml │ │ ├── error_template.yml │ │ ├── error_template_attribute.yml │ │ ├── execution_environment.yml │ │ ├── exercise.yml │ │ ├── exercise_collection.yml │ │ ├── exercise_collection_item.yml │ │ ├── exercise_tip.yml │ │ ├── external_user.yml │ │ ├── file_template.yml │ │ ├── file_type.yml │ │ ├── hint.yml │ │ ├── internal_user.yml │ │ ├── intervention.yml │ │ ├── linter │ │ │ ├── _documentation.md │ │ │ ├── convention.yml │ │ │ ├── error.yml │ │ │ ├── refactor.yml │ │ │ └── warning.yml │ │ ├── mailers │ │ │ └── user_mailer.yml │ │ ├── meta │ │ │ ├── activerecord.errors.yml │ │ │ ├── application.yml │ │ │ ├── breadcrumbs.yml │ │ │ ├── locales.yml │ │ │ ├── navigation.yml │ │ │ ├── shared.yml │ │ │ └── will_paginate.yml │ │ ├── programming_group.yml │ │ ├── programming_group_membership.yml │ │ ├── proxy_exercise.yml │ │ ├── remote_evaluation.yml │ │ ├── request_for_comment.yml │ │ ├── session.yml │ │ ├── statistic.yml │ │ ├── study_group.yml │ │ ├── study_group_membership.yml │ │ ├── submission.yml │ │ ├── subscription.yml │ │ ├── tag.yml │ │ ├── tip.yml │ │ ├── user.yml │ │ ├── user_exercise_feedback.yml │ │ ├── webauthn_credential.yml │ │ └── webauthn_credential_authentication.yml │ └── en │ │ ├── admin │ │ └── dashboard.yml │ │ ├── code_ocean │ │ └── file.yml │ │ ├── codeharbor_link.yml │ │ ├── comment.yml │ │ ├── community_solution.yml │ │ ├── consumer.yml │ │ ├── error_template.yml │ │ ├── error_template_attribute.yml │ │ ├── execution_environment.yml │ │ ├── exercise.yml │ │ ├── exercise_collection.yml │ │ ├── exercise_collection_item.yml │ │ ├── exercise_tip.yml │ │ ├── external_user.yml │ │ ├── file_template.yml │ │ ├── file_type.yml │ │ ├── hint.yml │ │ ├── internal_user.yml │ │ ├── intervention.yml │ │ ├── mailers │ │ └── user_mailer.yml │ │ ├── meta │ │ ├── activerecord.errors.yml │ │ ├── application.yml │ │ ├── breadcrumbs.yml │ │ ├── locales.yml │ │ ├── navigation.yml │ │ ├── shared.yml │ │ └── will_paginate.yml │ │ ├── programming_group.yml │ │ ├── programming_group_membership.yml │ │ ├── proxy_exercise.yml │ │ ├── remote_evaluation.yml │ │ ├── request_for_comment.yml │ │ ├── session.yml │ │ ├── statistic.yml │ │ ├── study_group.yml │ │ ├── study_group_membership.yml │ │ ├── submission.yml │ │ ├── subscription.yml │ │ ├── tag.yml │ │ ├── tip.yml │ │ ├── user.yml │ │ ├── user_exercise_feedback.yml │ │ ├── webauthn_credential.yml │ │ └── webauthn_credential_authentication.yml ├── mnemosyne.yml.ci ├── mnemosyne.yml.example ├── puma.rb ├── queue.yml ├── recurring.yml ├── routes.rb ├── shakapacker.yml ├── solid_queue_defaults.rb ├── storage.yml └── webpack │ └── webpack.config.js ├── db ├── cable_migrate │ └── 20240930231316_create_compact_channel.rb ├── cable_schema.rb ├── migrate │ ├── 20140625134118_create_exercises.rb │ ├── 20140626143132_create_execution_environments.rb │ ├── 20140626144036_create_submissions.rb │ ├── 20140630093736_add_reference_implementation_to_exercises.rb │ ├── 20140630111215_add_indent_size_to_execution_environments.rb │ ├── 20140701120126_create_consumers.rb │ ├── 20140701122345_create_users.rb │ ├── 20140702100130_add_oauth_key_to_consumers.rb │ ├── 20140703070749_add_oauth_secret_to_consumers.rb │ ├── 20140716153147_add_role_to_users.rb │ ├── 20140717074902_add_user_id_to_exercises.rb │ ├── 20140722125431_add_run_command_to_execution_environments.rb │ ├── 20140723135530_add_test_command_to_execution_environments.rb │ ├── 20140723135747_add_test_code_to_exercises.rb │ ├── 20140724155359_add_cause_to_submissions.rb │ ├── 20140730114343_add_template_test_code_to_exercises.rb │ ├── 20140730115010_add_supports_user_defined_tests_to_exercises.rb │ ├── 20140805161431_add_testing_framework_to_execution_environments.rb │ ├── 20140812102114_create_file_types.rb │ ├── 20140812144733_create_files.rb │ ├── 20140812150607_remove_file_type_related_columns_from_execution_environments.rb │ ├── 20140812150925_remove_file_related_columns_from_exercises.rb │ ├── 20140813091722_remove_code_from_submissions.rb │ ├── 20140820170039_add_instructions_to_exercises.rb │ ├── 20140821064318_add_published_to_exercises.rb │ ├── 20140823172643_add_executable_to_file_types.rb │ ├── 20140823173923_add_renderable_to_file_types.rb │ ├── 20140825121336_create_external_users.rb │ ├── 20140825125801_create_internal_users.rb │ ├── 20140825154202_drop_users.rb │ ├── 20140825161350_add_user_type_to_exercises.rb │ ├── 20140825161358_add_user_type_to_file_types.rb │ ├── 20140825161406_add_user_type_to_submissions.rb │ ├── 20140826073318_sorcery_core.rb │ ├── 20140826073319_sorcery_brute_force_protection.rb │ ├── 20140826073320_sorcery_remember_me.rb │ ├── 20140826073321_sorcery_reset_password.rb │ ├── 20140826073322_sorcery_user_activation.rb │ ├── 20140827065359_add_binary_to_file_types.rb │ ├── 20140827083957_add_native_file_to_files.rb │ ├── 20140829141913_create_hints.rb │ ├── 20140903093436_remove_not_null_constraints_from_internal_users.rb │ ├── 20140903165113_create_errors.rb │ ├── 20140904082810_add_token_to_exercises.rb │ ├── 20140909115430_add_file_id_to_exercises.rb │ ├── 20140915095420_add_role_to_files.rb │ ├── 20140915122846_remove_file_id_from_exercises.rb │ ├── 20140918063522_add_hashed_content_to_files.rb │ ├── 20140922161120_add_feedback_message_to_files.rb │ ├── 20140922161226_add_weight_to_files.rb │ ├── 20141003072729_add_help_to_execution_environments.rb │ ├── 20141004114747_add_exposed_ports_to_execution_environments.rb │ ├── 20141009110434_add_permitted_execution_time_to_execution_environments.rb │ ├── 20141011145303_add_user_id_and_user_type_to_execution_environments.rb │ ├── 20141017110211_rename_published_to_public.rb │ ├── 20141031161603_add_path_to_files.rb │ ├── 20141119131607_create_comments.rb │ ├── 20150128083123_create_teams.rb │ ├── 20150128084834_create_internal_users_teams.rb │ ├── 20150128093003_add_team_id_to_exercises.rb │ ├── 20150204080832_add_pool_size_to_execution_environments.rb │ ├── 20150310150712_add_file_type_id_to_execution_environments.rb │ ├── 20150317083739_add_memory_limit_to_execution_environments.rb │ ├── 20150317115338_add_network_enabled_to_execution_environments.rb │ ├── 20150327141740_create_request_for_comments.rb │ ├── 20150408155923_add_submission_to_error.rb │ ├── 20150421074734_add_file_index_to_files.rb │ ├── 20150818141554_add_user_type_to_request_for_comments.rb │ ├── 20150818142251_correct_column_names.rb │ ├── 20150903152727_remove_requestor_from_request_for_comments.rb │ ├── 20150922125415_add_hide_file_tree_to_exercises.rb │ ├── 20160204094409_create_code_harbor_links.rb │ ├── 20160204111716_add_user_to_code_harbor_link.rb │ ├── 20160302133540_create_testruns.rb │ ├── 20160426114951_add_question_to_request_for_comments.rb │ ├── 20160510145341_add_allow_file_creation_to_exercises.rb │ ├── 20160512131539_change_comment_text_attribute_to_text_datatype.rb │ ├── 20160609185708_create_file_templates.rb │ ├── 20160610111602_add_file_template_to_file.rb │ ├── 20160624130951_add_solved_to_request_for_comments.rb │ ├── 20160630154310_add_submission_to_request_for_comments.rb │ ├── 20160701092140_remove_requested_at_from_request_for_comments.rb │ ├── 20160704143402_remove_teams.rb │ ├── 20160907123009_add_allow_auto_completion_to_exercises.rb │ ├── 20170112151637_create_lti_parameters.rb │ ├── 20170202170437_create_remote_evaluation_mappings.rb │ ├── 20170205163247_create_exercise_collections.rb │ ├── 20170205165450_create_proxy_exercises.rb │ ├── 20170205210357_create_interventions.rb │ ├── 20170206141210_add_tags.rb │ ├── 20170206152503_add_user_feedback.rb │ ├── 20170228165741_add_search.rb │ ├── 20170321150454_add_reason_to_user_proxy_exercise_exercise.rb │ ├── 20170323130756_add_index_to_submissions.rb │ ├── 20170403162848_set_default_for_request_for_comment_solved.rb │ ├── 20170411090543_improve_user_feedback.rb │ ├── 20170608141612_add_thank_you_note_to_request_for_comments.rb │ ├── 20170703075832_create_error_templates.rb │ ├── 20170703075959_create_error_template_attributes.rb │ ├── 20170703080205_create_structured_errors.rb │ ├── 20170703080355_create_structured_error_attributes.rb │ ├── 20170711170456_add_description_and_hint_to_error_template.rb │ ├── 20170711170928_change_error_template_attribute_relationship_to_n_to_m.rb │ ├── 20170719133351_add_match_to_structured_error_attribute.rb │ ├── 20170830083601_add_cause_to_testruns.rb │ ├── 20170906124500_create_subscriptions.rb │ ├── 20170913054203_rename_subscription_type.rb │ ├── 20170920145852_add_deleted_to_subscription.rb │ ├── 20171002131135_remove_expected_working_time.rb │ ├── 20171115121125_add_anomaly_detection_flag_to_exercise_collection.rb │ ├── 20171120153705_add_timestamps_to_user_exercise_feedbacks.rb │ ├── 20171122124222_add_index_to_exercises.rb │ ├── 20171210172208_add_user_to_exercise_collection.rb │ ├── 20180130101645_add_submission_to_structured_errors.rb │ ├── 20180130172021_add_reached_full_score_to_request_for_comment.rb │ ├── 20180202132034_add_times_featured_to_request_for_comments.rb │ ├── 20180222145909_fix_timestamps_on_feedback.rb │ ├── 20180226131340_create_anomaly_notifications.rb │ ├── 20180515110030_remove_file_id_from_structured_errors.rb │ ├── 20180703125302_create_exercise_collection_items.rb │ ├── 20180814145059_create_events.rb │ ├── 20180814154055_rename_events_type_to_category.rb │ ├── 20180815115351_remove_event_indices.rb │ ├── 20180823135317_add_index_for_testrun_submission_id.rb │ ├── 20180904115948_add_index_for_lti_parameters_external_user_id.rb │ ├── 20181116143743_add_role_to_external_users.rb │ ├── 20181119161514_add_user_to_proxy_exercise.rb │ ├── 20181122084546_create_study_groups.rb │ ├── 20181122090243_create_study_group_memberships.rb │ ├── 20181122090244_add_study_group_to_submission.rb │ ├── 20181126163428_add_user_type_to_remote_evaluation_mappings.rb │ ├── 20181127160857_drop_hints.rb │ ├── 20181129093207_drop_errors.rb │ ├── 20190213131802_add_indices_for_request_for_comments.rb │ ├── 20190818104802_rename_code_harbor_links_to_codeharbor_links.rb │ ├── 20190818104954_add_push_url_rename_oauth2token_in_codeharbor_links.rb │ ├── 20190830142809_add_uuid_to_exercise.rb │ ├── 20191008163045_add_unpublished_to_exercise.rb │ ├── 20200326115249_add_container_execution_time_to_testruns.rb │ ├── 20200506093054_add_deadline_to_exercises.rb │ ├── 20201007104221_create_tips.rb │ ├── 20201019090123_add_normalized_score_and_submission_to_user_exercise_feedback.rb │ ├── 20201026184633_create_linter_checks.rb │ ├── 20201208095929_add_index_to_rfc.rb │ ├── 20201208132844_add_index_to_unpublished_exercises.rb │ ├── 20201210113500_add_index_to_exercise_title.rb │ ├── 20210426113125_add_study_group_to_remote_evaluation_mapping.rb │ ├── 20210510174452_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb │ ├── 20210512133611_add_service_name_to_active_storage_blobs.active_storage.rb │ ├── 20210512133612_create_active_storage_variant_records.active_storage.rb │ ├── 20210519134938_create_runners.rb │ ├── 20210601095654_add_cpu_limit_to_execution_environment.rb │ ├── 20210602071834_change_type_of_exposed_ports_in_execution_environment.rb │ ├── 20211114145024_create_tips_intervention.rb │ ├── 20211118185051_create_community_solution.rb │ ├── 20220415125948_add_testrun_execution_environment.rb │ ├── 20220415215111_add_details_to_testruns.rb │ ├── 20220415215112_migrate_testruns.rb │ ├── 20220721131946_create_authentication_tokens.rb │ ├── 20220906142041_add_study_group_authorization.rb │ ├── 20220906142550_migrate_permissions_to_study_group.rb │ ├── 20220906142603_remove_role_from_users.rb │ ├── 20220923214003_add_privileged_execution_to_execution_environment.rb │ ├── 20221204002837_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb │ ├── 20221204120508_add_precision_to_timestamps.rb │ ├── 20221206221333_set_database_interval_style.rb │ ├── 20230120185807_add_algorithm_to_proxy_exercise.rb │ ├── 20230206203117_migrate_filetype_extensions_not_nil.rb │ ├── 20230219113125_add_rfc_visibility_to_consumer.rb │ ├── 20230314084733_add_index_for_recommended_rfcs.rb │ ├── 20230320220011_add_foreign_keys_to_structured_errors.rb │ ├── 20230320220012_add_foreign_keys_and_index_to_structured_error_attributes.rb │ ├── 20230710130036_rename_user_columns_to_contributor_in_submissions.rb │ ├── 20230710130037_require_contributor_on_submission.rb │ ├── 20230710130038_require_submission_on_testrun.rb │ ├── 20230710130039_add_user_to_testrun.rb │ ├── 20230710131250_create_programming_groups.rb │ ├── 20230710132428_create_programming_group_memberships.rb │ ├── 20230727080619_add_hidden_feedback_to_files.rb │ ├── 20230819084916_add_study_group_to_lti_parameters.rb │ ├── 20230819084917_unify_lti_parameters.rb │ ├── 20230820182149_rename_user_to_contributor_in_runners.rb │ ├── 20230821062816_rename_user_to_contributor_in_anomaly_notifications.rb │ ├── 20230821062901_add_foreign_keys_to_anomaly_notifications.rb │ ├── 20230821063101_convert_reason_to_json_in_anomaly_notifications.rb │ ├── 20230904174803_add_contributor_and_study_group_to_events.rb │ ├── 20230904180123_create_events_synchronized_editor.rb │ ├── 20230905190519_add_pair_programming_exercise_feedbacks.rb │ ├── 20230906163923_rename_columns_in_events_synchronized_editor.rb │ ├── 20230908091810_add_session_id_to_events_synrhonized_editor.rb │ ├── 20230912142620_remove_outdated_columns_from_events_synchronized_editor.rb │ ├── 20230912162208_require_session_id_for_event_synchronized_editor.rb │ ├── 20230920094122_create_pair_programming_waiting_users.rb │ ├── 20231013194635_add_internal_title_to_exercises.rb │ ├── 20231029172331_add_reserved_until_to_runners.rb │ ├── 20231101222855_add_programming_group_to_remote_evalution_mapping.rb │ ├── 20231208194632_add_index_to_user_exercise_interventions.rb │ ├── 20240830132933_add_webauthn_credentials.rb │ ├── 20240912101506_drop_action_cable_large_payloads.rb │ ├── 20241007204319_add_xml_path_to_files.rb │ ├── 20241105212201_add_indices_to_submission.rb │ ├── 20241107004238_move_updated_at_index_to_created_at_on_submission.rb │ ├── 20241116105338_backfill_user_type_to_codeharbor_links.rb │ ├── 20250502125320_add_uniqueness_constraint_to_external_user_external_id.rb │ ├── 20250502130326_change_uniqueness_constraint_for_study_group_external_id.rb │ ├── 20250502133509_add_constraints_to_runner.rb │ ├── 20250502170658_add_uniqueness_constraint_to_user_proxy_exercise_exercises.rb │ └── 20250513141128_delete_invalid_assess_testruns.rb ├── queue_schema.rb ├── schema.rb ├── scripts │ ├── migrate_exercise.sql │ ├── migrate_external_user.sql │ └── migrate_study_group.sql ├── seeds.rb └── seeds │ ├── audio_video │ ├── chai.ogg │ ├── devstories.mp4 │ ├── devstories.webm │ ├── index.html │ ├── index.html_spec.rb │ ├── index.js │ └── poster.png │ ├── development.rb │ ├── even_odd │ ├── exercise.py │ ├── exercise_tests.py │ └── reference.py │ ├── fibonacci │ ├── exercise.rb │ ├── exercise_spec_1.rb │ ├── exercise_spec_2.rb │ ├── exercise_spec_3.rb │ └── reference.rb │ ├── files │ ├── data.txt │ ├── exercise.rb │ └── exercise_spec.rb │ ├── geolocation │ ├── index.html │ └── index.js │ ├── hello_world │ ├── exercise.rb │ └── exercise_spec.rb │ ├── math │ ├── Makefile │ └── org │ │ └── example │ │ ├── RecursiveMath.java │ │ ├── RecursiveMathTest1.java │ │ └── RecursiveMathTest2.java │ ├── primes │ └── exercise.js │ ├── production.rb │ ├── sql_select │ ├── comparator.rb │ ├── exercise.sql │ └── reference.sql │ ├── tdd │ ├── exercise.rb │ ├── exercise_spec.rb │ └── instructions.md │ └── web_app │ └── app.rb ├── docs ├── LOCAL_SETUP.md ├── LOCAL_SETUP_DEVCONTAINER.md ├── LOCAL_SETUP_VAGRANT.md ├── backup.md ├── codeocean-dockerconfig.md ├── environment_variables.md ├── grafana │ └── prometheus_exporter_grafana_dashboard.json ├── implement.png ├── lti_parameters.md ├── provision_server.sh └── remote_evaluation.yml ├── lib ├── assessor.rb ├── assets │ ├── javascripts │ │ ├── color_mode_picker.js │ │ └── flash.js │ └── stylesheets │ │ └── flash.css.scss ├── code_ocean │ ├── config.rb │ └── remote-evaluation.schema.json ├── cpp_catch2_adapter.rb ├── file_io.rb ├── file_tree.rb ├── generators │ └── testing_framework_adapter_generator.rb ├── i18n_tasks │ ├── js_erb_locale_matcher.rb │ └── slim_row_locale_matcher.rb ├── java21_study.rb ├── julia_adapter.rb ├── junit5_adapter.rb ├── junit_adapter.rb ├── middleware │ └── web_socket_sentry_headers.rb ├── mocha_adapter.rb ├── nonce_store.rb ├── prometheus.rb ├── prometheus │ ├── controller.rb │ └── record.rb ├── py_lint_adapter.rb ├── py_unit_adapter.rb ├── py_unit_and_py_lint_adapter.rb ├── r_script_adapter.rb ├── rspec_adapter.rb ├── runner │ ├── backend-output.schema.json │ ├── connection.rb │ ├── connection │ │ └── buffer.rb │ ├── event_loop.rb │ ├── strategy.rb │ └── strategy │ │ ├── docker_container_pool.rb │ │ ├── null.rb │ │ └── poseidon.rb ├── seeds_helper.rb ├── shakapacker │ ├── sri_helper_extensions.rb │ └── sri_manifest_extensions.rb ├── sql_result_set_comparator_adapter.rb ├── tasks │ ├── before_assets_tasks.rake │ ├── export_public_exercises.rake │ ├── gdpr_delete.rake │ ├── sourcemap.rake │ └── write_displaynames.rake ├── testing_framework_adapter.rb └── user_group_separator.rb ├── package.json ├── provision ├── Dockerfile ├── provision.docker.root.sh ├── provision.docker.user.sh └── provision.vagrant.sh ├── public ├── 400.html ├── 404.html ├── 406-unsupported-browser.html ├── 422.html ├── 500.html ├── icon.png ├── icon.svg └── robots.txt ├── spec ├── concerns │ ├── file_parameters_spec.rb │ └── lti_spec.rb ├── controllers │ ├── admin │ │ └── dashboard_controller_spec.rb │ ├── application_controller_spec.rb │ ├── code_ocean │ │ └── files_controller_spec.rb │ ├── codeharbor_links_controller_spec.rb │ ├── comments_controller_spec.rb │ ├── consumers_controller_spec.rb │ ├── error_template_attributes_controller_spec.rb │ ├── error_templates_controller_spec.rb │ ├── events_controller_spec.rb │ ├── execution_environments_controller_spec.rb │ ├── exercises_controller_spec.rb │ ├── external_users_controller_spec.rb │ ├── file_types_controller_spec.rb │ ├── internal_users_controller_spec.rb │ ├── ping_controller_spec.rb │ ├── programming_groups_controller_spec.rb │ ├── remote_evaluation_controller_spec.rb │ ├── request_for_comments_controller_spec.rb │ ├── sessions_controller_spec.rb │ ├── statistics_controller_spec.rb │ └── submissions_controller_spec.rb ├── db │ └── seeds_spec.rb ├── factories │ ├── authentication_token.rb │ ├── code_ocean │ │ └── file.rb │ ├── codeharbor_link.rb │ ├── consumer.rb │ ├── error_template_attributes.rb │ ├── error_templates.rb │ ├── execution_environment.rb │ ├── exercise.rb │ ├── external_user.rb │ ├── file_type.rb │ ├── internal_user.rb │ ├── lti_parameter.rb │ ├── programming_group.rb │ ├── proxy_exercise.rb │ ├── remote_evaluation_mapping.rb │ ├── request_for_comment.rb │ ├── runner.rb │ ├── shared_traits.rb │ ├── structured_error_attributes.rb │ ├── structured_errors.rb │ ├── study_group.rb │ ├── submission.rb │ └── user_exercise_feedback.rb ├── fixtures │ └── files │ │ └── proforma_import │ │ ├── corrupt.zip │ │ ├── empty.zip │ │ └── testfile.zip ├── helpers │ ├── admin │ │ └── dashboard_helper_spec.rb │ ├── application_helper_spec.rb │ ├── authenticated_url_helper_spec.rb │ ├── exercise_helper_spec.rb │ └── yaml_spec.rb ├── lib │ ├── assessor_spec.rb │ ├── code_ocean │ │ └── config_spec.rb │ ├── file_tree_spec.rb │ ├── generators │ │ └── testing_framework_adapter_generator_spec.rb │ ├── junit_adapter_spec.rb │ ├── mocha_adapter_spec.rb │ ├── nonce_store_spec.rb │ ├── py_unit_adapter_spec.rb │ ├── rspec_adapter_spec.rb │ ├── runner │ │ └── strategy │ │ │ ├── docker_container_pool_spec.rb │ │ │ ├── poseidon │ │ │ └── connection_spec.rb │ │ │ └── poseidon_spec.rb │ ├── sql_result_set_comparator_adapter_spec.rb │ └── testing_framework_adapter_spec.rb ├── mailers │ ├── previews │ │ └── user_mailer_preview.rb │ └── user_mailer_spec.rb ├── models │ ├── code_ocean │ │ └── file_spec.rb │ ├── codeharbor_link_spec.rb │ ├── consumer_spec.rb │ ├── execution_environment_spec.rb │ ├── exercise_spec.rb │ ├── external_user_spec.rb │ ├── file_type_spec.rb │ ├── internal_user_spec.rb │ ├── request_for_comment_spec.rb │ ├── runner_spec.rb │ └── submission_spec.rb ├── other │ ├── factories_spec.rb │ └── i18n_spec.rb ├── policies │ ├── admin │ │ └── dashboard_policy_spec.rb │ ├── application_policy_spec.rb │ ├── code_ocean │ │ └── file_policy_spec.rb │ ├── codeharbor_link_policy_spec.rb │ ├── community_solution_policy_spec.rb │ ├── consumer_policy_spec.rb │ ├── execution_environment_policy_spec.rb │ ├── exercise_policy_spec.rb │ ├── external_user_policy_spec.rb │ ├── file_type_policy_spec.rb │ ├── internal_user_policy_spec.rb │ ├── programming_group_policy_spec.rb │ ├── request_for_comment_policy_spec.rb │ └── submission_policy_spec.rb ├── rails_helper.rb ├── routing │ └── ping_controller_routing_spec.rb ├── services │ ├── exercise_service │ │ ├── check_external_spec.rb │ │ └── push_external_spec.rb │ └── proforma_service │ │ ├── convert_exercise_to_task_spec.rb │ │ ├── convert_task_to_exercise_spec.rb │ │ ├── export_task_spec.rb │ │ ├── import_spec.rb │ │ └── uuid_from_zip_spec.rb ├── spec_helper.rb ├── support │ ├── anonymous_controller.rb │ ├── authentication.rb │ ├── capybara.rb │ ├── controllers.rb │ ├── expectations.rb │ ├── expectations │ │ ├── equal_exercise.rb │ │ └── has_content.rb │ ├── export_js_sources.rb │ ├── factory_bot.rb │ ├── features.rb │ ├── matchers.rb │ ├── prometheus_client_stub.rb │ ├── runner.rb │ ├── silencer.rb │ ├── sorcery.rb │ ├── wait_for_ajax.rb │ ├── wait_for_websocket.rb │ └── webmock.rb ├── system │ ├── authentication_system_spec.rb │ ├── authorization_system_spec.rb │ ├── editor_system_spec.rb │ ├── external_user_statistics_system_spec.rb │ ├── prometheus │ │ └── controller_system_spec.rb │ ├── request_for_comments_filter_system_spec.rb │ └── score_system_spec.rb ├── uploaders │ ├── file_uploader_spec.rb │ └── proforma_zip_uploader_spec.rb └── views │ ├── execution_environments │ └── shell.html.slim_spec.rb │ ├── exercises │ ├── external_users │ │ └── statistics.html.slim_spec.rb │ └── implement.html.slim_spec.rb │ └── sessions │ └── destroy_through_lti.html.slim_spec.rb ├── storage └── .keep ├── tmp ├── pids │ └── .keep ├── screenshots │ └── .keep ├── sockets │ └── .keep └── storage │ └── .keep └── yarn.lock /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Make sure RUBY_VERSION matches the Ruby version in .ruby-version 2 | ARG RUBY_VERSION=3.4.4 3 | FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/*schema.rb linguist-generated 5 | 6 | # Mark any vendored files as having been vendored. 7 | vendor/* linguist-vendored 8 | config/credentials/*.yml.enc diff=rails_credentials 9 | config/credentials.yml.enc diff=rails_credentials 10 | -------------------------------------------------------------------------------- /.github/auto-merge.yml: -------------------------------------------------------------------------------- 1 | - match: 2 | dependency_type: all 3 | update_type: semver:minor # includes patch updates! 4 | -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot Automerge Check 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | auto-merge: 7 | if: github.actor == 'dependabot[bot]' 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v4 12 | - name: Automerge dependabot dependencies 13 | uses: ahmadnassri/action-dependabot-auto-merge@v2 14 | with: 15 | github-token: ${{ secrets.OPENHPI_BOT_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/sentry-release.yml: -------------------------------------------------------------------------------- 1 | name: Create a Sentry release 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | create-release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Create Sentry release 13 | uses: getsentry/action-release@v3 14 | with: 15 | projects: ${{ secrets.SENTRY_PROJECT }} 16 | env: 17 | SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} 18 | SENTRY_ORG: ${{ secrets.SENTRY_ORG }} 19 | -------------------------------------------------------------------------------- /.rubocop/lint.yml: -------------------------------------------------------------------------------- 1 | # lint cop settings 2 | 3 | # 4 | # False positives: 5 | # * expect { something }.to change { something } often triggers this 6 | # 7 | Lint/AmbiguousBlockAssociation: 8 | Exclude: 9 | - "spec/**/*_spec.rb" 10 | -------------------------------------------------------------------------------- /.rubocop/performance.yml: -------------------------------------------------------------------------------- 1 | # performance cop settings 2 | 3 | # The policy specs should be easy to read 4 | # 5 | Performance/CollectionLiteralInLoop: 6 | Exclude: 7 | - 'spec/policies/**' 8 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-3.4.4 2 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Add your own tasks in files placed in lib/tasks ending in .rake, 4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 5 | 6 | require_relative 'config/application' 7 | 8 | Rails.application.load_tasks 9 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../javascripts .js.map 4 | //= link_directory ../stylesheets .css 5 | //= link_directory ../stylesheets .css.map 6 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the `rails generate channel` command. 3 | // 4 | //= require actioncable 5 | //= require_self 6 | //= require_tree ./channels 7 | 8 | (function() { 9 | this.App || (this.App = {}); 10 | 11 | App.cable = ActionCable.createConsumer(); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /app/assets/javascripts/editor/ajax.js: -------------------------------------------------------------------------------- 1 | CodeOceanEditorAJAX = { 2 | ajax: function(options) { 3 | return $.ajax(_.extend({ 4 | dataType: 'json', 5 | method: 'POST', 6 | }, options)); 7 | }, 8 | 9 | ajaxError: function(response) { 10 | const responseJSON = ((response || {}).responseJSON || {}); 11 | const message = responseJSON.message || responseJSON.error || ''; 12 | 13 | $.flash.danger({ 14 | text: message.length > 0 ? message : $('#flash').data('message-failure'), 15 | showPermanent: response.status === 422, 16 | }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/error_templates.scss: -------------------------------------------------------------------------------- 1 | #add-attribute { 2 | display: flex; 3 | max-width: 400px; 4 | margin-top: 30px; 5 | 6 | button { 7 | margin-left: 10px; 8 | } 9 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/external_users.css.scss: -------------------------------------------------------------------------------- 1 | #no-elements { 2 | display: none; 3 | } 4 | 5 | #tag-grid { 6 | display: grid; 7 | grid-template-columns: 25% 25% 25% 25%; 8 | grid-column-gap: 10px; 9 | grid-row-gap: 15px; 10 | 11 | .progress { 12 | .progress-bar { 13 | min-width: 2em; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/file_templates.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the FileTemplates controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: https://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/flowrdata.css.scss: -------------------------------------------------------------------------------- 1 | #flowrHint { 2 | display: none; 3 | margin-top: 10px; 4 | } 5 | -------------------------------------------------------------------------------- /app/assets/stylesheets/forms.css.scss: -------------------------------------------------------------------------------- 1 | .alternative-input { 2 | display: none; 3 | } 4 | 5 | .chosen-container { 6 | min-width: 250px !important; 7 | width: 100% !important; 8 | } 9 | 10 | .chosen-inline { 11 | .chosen-container { 12 | min-width: unset !important; 13 | width: unset !important; 14 | } 15 | } 16 | 17 | .code-field { 18 | font-family: monospace; 19 | } 20 | 21 | .filter-form { 22 | .row:not(:last-child) { 23 | margin-bottom: 1em; 24 | } 25 | 26 | input, select { 27 | min-width: 200px !important; 28 | } 29 | } 30 | 31 | .toggle-input { 32 | font-size: 80%; 33 | } 34 | -------------------------------------------------------------------------------- /app/controllers/admin/dashboard_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Admin 4 | class DashboardController < ApplicationController 5 | include DashboardHelper 6 | 7 | def policy_class 8 | DashboardPolicy 9 | end 10 | 11 | def show 12 | authorize(self) 13 | respond_to do |format| 14 | format.html 15 | format.json { render(json: dashboard_data) } 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/concerns/remote_evaluation_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RemoteEvaluationParameters 4 | include FileParameters 5 | 6 | def remote_evaluation_params 7 | if params[:remote_evaluation].present? 8 | params[:remote_evaluation].permit(:validation_token, files_attributes: file_attributes) 9 | end 10 | end 11 | private :remote_evaluation_params 12 | end 13 | -------------------------------------------------------------------------------- /app/controllers/rails_admin_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RailsAdminController < ApplicationController 4 | # RailsAdmin does not include translations. Therefore, we fallback to English locales 5 | skip_around_action :switch_locale 6 | # We check for permissions in the RailsAdmin config. Therefore, we skip Pundit checks here. 7 | skip_after_action :verify_authorized 8 | end 9 | -------------------------------------------------------------------------------- /app/errors/application_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationError < StandardError 4 | end 5 | -------------------------------------------------------------------------------- /app/errors/proformaxml/exercise_not_owned.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ProformaXML 4 | class ExerciseNotOwned < ApplicationError; end 5 | end 6 | -------------------------------------------------------------------------------- /app/errors/proformaxml/invalid_zip.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ProformaXML 4 | class InvalidZip < ApplicationError; end 5 | end 6 | -------------------------------------------------------------------------------- /app/errors/runner/connection/buffer/error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Runner::Connection::Buffer 4 | class Error < ApplicationError 5 | class NotEmpty < Error; end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/helpers/exercise_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ExerciseHelper 4 | include LtiHelper 5 | 6 | def embedding_parameters(exercise) 7 | "locale=#{I18n.locale}&token=#{exercise.token}" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/javascript/d3-tip.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 */ 2 | 3 | // JS 4 | import * as d3Tip from 'd3-tip/dist' 5 | window.d3.tip = d3Tip; 6 | -------------------------------------------------------------------------------- /app/javascript/highlight.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 */ 2 | 3 | // JS 4 | import hljs from 'highlight.js/lib/common' 5 | import julia from 'highlight.js/lib/languages/julia'; 6 | hljs.registerLanguage('julia', julia); 7 | window.hljs = hljs; 8 | -------------------------------------------------------------------------------- /app/javascript/highlight.scss: -------------------------------------------------------------------------------- 1 | // CSS for highlight.js 2 | 3 | html[data-bs-theme="light"] { 4 | @import 'highlight.js/styles/base16/tomorrow'; 5 | } 6 | 7 | html[data-bs-theme="dark"] { 8 | @import 'highlight.js/styles/base16/tomorrow-night'; 9 | } 10 | -------------------------------------------------------------------------------- /app/javascript/rails_admin.js: -------------------------------------------------------------------------------- 1 | import "rails_admin/src/rails_admin/base"; 2 | -------------------------------------------------------------------------------- /app/javascript/rails_admin.scss: -------------------------------------------------------------------------------- 1 | @import "rails_admin/src/rails_admin/styles/base"; 2 | -------------------------------------------------------------------------------- /app/javascript/sortable.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 */ 2 | 3 | // JS 4 | import Sortable from 'sortablejs' 5 | window.Sortable = Sortable; 6 | -------------------------------------------------------------------------------- /app/javascript/toast-ui.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 */ 2 | 3 | // JS 4 | import ToastUi from "@toast-ui/editor"; 5 | // Import German locales (english ones are included by default) 6 | import "@toast-ui/editor/dist/i18n/de-de"; 7 | window.ToastUi = ToastUi 8 | -------------------------------------------------------------------------------- /app/javascript/vis.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console:0 */ 2 | 3 | // JS 4 | import * as vis from 'vis'; 5 | window.vis = vis; 6 | -------------------------------------------------------------------------------- /app/javascript/vis.scss: -------------------------------------------------------------------------------- 1 | // CSS 2 | 3 | @import 'vis-timeline/dist/vis-timeline-graph2d'; 4 | 5 | html[data-bs-theme="dark"] { 6 | // Color overwrites for dark mode 7 | 8 | .vis-legend { 9 | background-color: rgba(var(--bs-secondary-bg-rgb), 0.65) !important; 10 | } 11 | 12 | .vis-timeline .vis-outline { 13 | fill: var(--bs-body-bg) !important; 14 | } 15 | 16 | .vis-data-axis .vis-major, .vis-time-axis .vis-text { 17 | color: var(--bs-secondary-text-emphasis) !important; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationJob < ActiveJob::Base 4 | include ActiveRecordLogging 5 | 6 | # Automatically retry jobs that encountered a deadlock 7 | retry_on ActiveRecord::Deadlocked 8 | 9 | # Most jobs are safe to ignore if the underlying records are no longer available 10 | discard_on ActiveJob::DeserializationError 11 | end 12 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationMailer < ActionMailer::Base 4 | layout 'mailer' 5 | end 6 | -------------------------------------------------------------------------------- /app/models/anomaly_notification.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AnomalyNotification < ApplicationRecord 4 | include ContributorCreation 5 | belongs_to :exercise 6 | belongs_to :exercise_collection 7 | end 8 | -------------------------------------------------------------------------------- /app/models/authentication_token.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'securerandom' 4 | 5 | class AuthenticationToken < ApplicationRecord 6 | include Creation 7 | belongs_to :study_group, optional: true 8 | 9 | def self.generate!(user, study_group) 10 | create!( 11 | shared_secret: SecureRandom.hex(32), 12 | user:, 13 | expire_at: 7.days.from_now, 14 | study_group: 15 | ) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/codeharbor_link.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CodeharborLink < ApplicationRecord 4 | include Creation 5 | 6 | validates :push_url, presence: true 7 | validates :check_uuid_url, presence: true 8 | validates :api_key, presence: true 9 | 10 | def to_s 11 | "#{model_name.human} #{id}" 12 | end 13 | 14 | def self.parent_resource 15 | User 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/community_solution.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CommunitySolution < ApplicationRecord 4 | ALLOWED_USER_TYPES = [InternalUser, ExternalUser].map(&:to_s).freeze 5 | belongs_to :exercise 6 | has_many :community_solution_locks 7 | has_many :community_solution_contributions 8 | has_and_belongs_to_many :users, polymorphic: true, through: :community_solution_contributions 9 | has_many :files, class_name: 'CodeOcean::File', through: :community_solution_contributions 10 | 11 | def to_s 12 | "Gemeinschaftslösung für #{exercise}" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/models/community_solution_contribution.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CommunitySolutionContribution < ApplicationRecord 4 | include Creation 5 | include Context 6 | 7 | belongs_to :community_solution 8 | belongs_to :community_solution_lock 9 | 10 | validates :proposed_changes, inclusion: [true, false] 11 | validates :timely_contribution, inclusion: [true, false] 12 | validates :autosave, inclusion: [true, false] 13 | validates :working_time, presence: true 14 | end 15 | -------------------------------------------------------------------------------- /app/models/community_solution_lock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CommunitySolutionLock < ApplicationRecord 4 | include Creation 5 | 6 | belongs_to :community_solution 7 | has_many :community_solution_contributions 8 | 9 | validates :locked_until, presence: true 10 | 11 | def active? 12 | Time.zone.now <= locked_until 13 | end 14 | 15 | def working_time 16 | ActiveSupport::Duration.build(locked_until - created_at) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/models/concerns/context.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Context 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | has_many :files, as: :context, class_name: 'CodeOcean::File' 8 | accepts_nested_attributes_for :files 9 | end 10 | 11 | def add_file(file_attributes) 12 | files.create(file_attributes).tap { save } 13 | end 14 | 15 | def add_file!(file_attributes) 16 | files.create!(file_attributes).tap { save! } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/models/concerns/contributor_creation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ContributorCreation 4 | extend ActiveSupport::Concern 5 | 6 | ALLOWED_CONTRIBUTOR_TYPES = [InternalUser, ExternalUser, ProgrammingGroup].map(&:to_s).freeze 7 | 8 | included do 9 | belongs_to :contributor, polymorphic: true 10 | alias_method :user, :contributor 11 | alias_method :user=, :contributor= 12 | alias_method :author, :user 13 | alias_method :creator, :user 14 | 15 | validates :contributor_type, inclusion: {in: ALLOWED_CONTRIBUTOR_TYPES} 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/concerns/creation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Creation 4 | extend ActiveSupport::Concern 5 | 6 | ALLOWED_USER_TYPES = [InternalUser, ExternalUser].map(&:to_s).freeze 7 | 8 | included do 9 | belongs_to :user, polymorphic: true 10 | alias_method :author, :user 11 | alias_method :creator, :user 12 | 13 | validates :user_type, inclusion: {in: ALLOWED_USER_TYPES} 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/concerns/default_values.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module DefaultValues 4 | def set_default_values_if_present(options = {}) 5 | options.each do |attribute, value| 6 | send(:"#{attribute}=", send(:"#{attribute}") || value) if has_attribute?(attribute) 7 | end 8 | end 9 | private :set_default_values_if_present 10 | end 11 | -------------------------------------------------------------------------------- /app/models/concerns/ransack_object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module RansackObject 4 | # Case insensitive search with Postgres and Ransack. 5 | # Adapted from https://activerecord-hackery.github.io/ransack/getting-started/simple-mode/#case-insensitive-sorting-in-postgresql 6 | def self.included(base) 7 | base.columns.each do |column| 8 | next unless column.type == :string 9 | 10 | base.ransacker column.name.to_sym, type: :string do 11 | Arel::Nodes::NamedFunction.new('LOWER', [base.arel_table[column.name]]) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/error_template.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ErrorTemplate < ApplicationRecord 4 | belongs_to :execution_environment 5 | has_and_belongs_to_many :error_template_attributes 6 | 7 | delegate :to_s, to: :name 8 | end 9 | -------------------------------------------------------------------------------- /app/models/error_template_attribute.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ErrorTemplateAttribute < ApplicationRecord 4 | has_and_belongs_to_many :error_template 5 | 6 | delegate :to_s, to: :key 7 | end 8 | -------------------------------------------------------------------------------- /app/models/exercise_collection_item.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ExerciseCollectionItem < ApplicationRecord 4 | belongs_to :exercise_collection 5 | belongs_to :exercise 6 | end 7 | -------------------------------------------------------------------------------- /app/models/exercise_tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ExerciseTag < ApplicationRecord 4 | belongs_to :tag 5 | belongs_to :exercise 6 | 7 | before_save :destroy_if_empty_exercise_or_tag 8 | 9 | private 10 | 11 | def destroy_if_empty_exercise_or_tag 12 | destroy if exercise_id.blank? || tag_id.blank? 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/models/external_user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ExternalUser < User 4 | validates :external_id, presence: true, uniqueness: {scope: :consumer_id} 5 | has_many :lti_parameters, dependent: :destroy 6 | 7 | def displayname 8 | name.presence || "#{model_name.human} #{id}" 9 | end 10 | 11 | def webauthn_name 12 | "#{consumer.name}: #{displayname}" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/models/file_template.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FileTemplate < ApplicationRecord 4 | belongs_to :file_type 5 | 6 | delegate :to_s, to: :name 7 | end 8 | -------------------------------------------------------------------------------- /app/models/linter_check.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class LinterCheck < ApplicationRecord 4 | has_many :linter_check_runs 5 | end 6 | -------------------------------------------------------------------------------- /app/models/lti_parameter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class LtiParameter < ApplicationRecord 4 | belongs_to :exercise 5 | belongs_to :external_user 6 | belongs_to :study_group, optional: true 7 | delegate :consumer, to: :external_user 8 | 9 | validates :external_user_id, uniqueness: {scope: %i[study_group_id exercise_id]} 10 | 11 | scope :lis_outcome_service_url?, lambda { 12 | where("lti_parameters.lti_parameters ? 'lis_outcome_service_url'") 13 | } 14 | end 15 | -------------------------------------------------------------------------------- /app/models/remote_evaluation_mapping.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # TODO: reference to lti_param_model 4 | class RemoteEvaluationMapping < ApplicationRecord 5 | include Creation 6 | before_create :generate_token, unless: :validation_token? 7 | belongs_to :exercise 8 | belongs_to :programming_group, optional: true 9 | belongs_to :study_group, optional: true 10 | 11 | def generate_token 12 | self.validation_token = SecureRandom.urlsafe_base64 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/models/structured_error_attribute.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class StructuredErrorAttribute < ApplicationRecord 4 | belongs_to :structured_error 5 | belongs_to :error_template_attribute 6 | 7 | def self.create_from_template(attribute, message_buffer) 8 | value = nil 9 | result = message_buffer.match(attribute.regex) 10 | if !result.nil? && result.captures.size.positive? 11 | value = result.captures[0] 12 | end 13 | create(error_template_attribute: attribute, value:, match: !result.nil?) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/study_group_membership.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class StudyGroupMembership < ApplicationRecord 4 | include Creation 5 | belongs_to :study_group 6 | 7 | before_save :destroy_if_empty_study_group_or_user 8 | 9 | ROLES = %w[learner teacher].freeze 10 | 11 | def destroy_if_empty_study_group_or_user 12 | destroy if study_group.blank? || user.blank? 13 | end 14 | 15 | enum :role, { 16 | learner: 0, 17 | teacher: 1, 18 | }, default: :learner, prefix: true 19 | 20 | validates :role, presence: true 21 | validates :user_id, uniqueness: {scope: %i[user_type study_group_id]} 22 | end 23 | -------------------------------------------------------------------------------- /app/models/subscription.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Subscription < ApplicationRecord 4 | include Creation 5 | belongs_to :request_for_comment 6 | belongs_to :study_group, optional: true 7 | end 8 | -------------------------------------------------------------------------------- /app/models/tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Tag < ApplicationRecord 4 | has_many :exercise_tags 5 | has_many :exercises, through: :exercise_tags 6 | 7 | validates :name, uniqueness: true 8 | 9 | before_destroy :can_be_destroyed?, prepend: true 10 | 11 | delegate :to_s, to: :name 12 | 13 | def can_be_destroyed? 14 | exercises.none? 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/models/testrun_execution_environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TestrunExecutionEnvironment < ApplicationRecord 4 | belongs_to :testrun 5 | belongs_to :execution_environment 6 | end 7 | -------------------------------------------------------------------------------- /app/models/user_exercise_intervention.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UserExerciseIntervention < ApplicationRecord 4 | include ContributorCreation 5 | belongs_to :intervention 6 | belongs_to :exercise 7 | end 8 | -------------------------------------------------------------------------------- /app/models/user_proxy_exercise_exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UserProxyExerciseExercise < ApplicationRecord 4 | include Creation 5 | belongs_to :exercise 6 | belongs_to :proxy_exercise 7 | 8 | validates :user_id, uniqueness: {scope: %i[proxy_exercise_id user_type]} 9 | end 10 | -------------------------------------------------------------------------------- /app/models/webauthn_credential.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class WebauthnCredential < ApplicationRecord 4 | belongs_to :user, polymorphic: true 5 | 6 | validates :external_id, :public_key, :label, :sign_count, presence: true 7 | validates :external_id, uniqueness: true 8 | validates :label, uniqueness: {scope: %i[user_id user_type]} 9 | validates :sign_count, numericality: {only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: (2**32) - 1} 10 | 11 | delegate :to_s, to: :label 12 | 13 | def self.parent_resource 14 | User 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/policies/admin/dashboard_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Admin 4 | class DashboardPolicy < AdminOnlyPolicy 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/policies/admin_only_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AdminOnlyPolicy < ApplicationPolicy 4 | %i[create? destroy? edit? index? new? show? update?].each do |action| 5 | define_method(action) { admin? } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/admin_or_author_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AdminOrAuthorPolicy < ApplicationPolicy 4 | %i[create? index? new?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | 8 | %i[destroy? edit? show? update?].each do |action| 9 | define_method(action) { admin? || author? } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/policies/comment_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CommentPolicy < ApplicationPolicy 4 | def create? 5 | everyone 6 | end 7 | 8 | def show? 9 | everyone 10 | end 11 | 12 | %i[new? destroy? update? edit?].each do |action| 13 | define_method(action) { admin? || author? || teacher_in_study_group? } 14 | end 15 | 16 | def index? 17 | everyone 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/policies/error_template_attribute_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ErrorTemplateAttributePolicy < AdminOnlyPolicy 4 | %i[index? show?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/error_template_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ErrorTemplatePolicy < AdminOnlyPolicy 4 | %i[index? show?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | 8 | def add_attribute? 9 | admin? 10 | end 11 | 12 | def remove_attribute? 13 | admin? 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/policies/event_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class EventPolicy < AdminOnlyPolicy 4 | def create? 5 | everyone 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/execution_environment_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ExecutionEnvironmentPolicy < AdminOnlyPolicy 4 | # download_arbitrary_file? is used in the live_streams_controller.rb 5 | %i[index? execute_command? shell? list_files? show? download_arbitrary_file?].each do |action| 6 | define_method(action) { admin? || teacher? } 7 | end 8 | 9 | %i[statistics? sync_to_runner_management?].each do |action| 10 | define_method(action) { admin? || author? } 11 | end 12 | 13 | def sync_all_to_runner_management? 14 | admin? 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/policies/exercise_collection_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ExerciseCollectionPolicy < AdminOnlyPolicy 4 | def statistics? 5 | admin? 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/file_template_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FileTemplatePolicy < AdminOnlyPolicy 4 | %i[index? show?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | 8 | def by_file_type? 9 | everyone 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/policies/file_type_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FileTypePolicy < AdminOnlyPolicy 4 | %i[index? show?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/statistics_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class StatisticsPolicy < AdminOnlyPolicy 4 | %i[graphs? user_activity? user_activity_history? rfc_activity? rfc_activity_history?].each do |action| 5 | define_method(action) { admin? } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/policies/subscription_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SubscriptionPolicy < ApplicationPolicy 4 | def create? 5 | everyone 6 | end 7 | 8 | def destroy? 9 | author? || admin? 10 | end 11 | 12 | def author? 13 | @user == @record.user 14 | end 15 | private :author? 16 | end 17 | -------------------------------------------------------------------------------- /app/policies/tag_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TagPolicy < AdminOnlyPolicy 4 | %i[index? show?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | 8 | class Scope < Scope 9 | def resolve 10 | if @user.admin? || @user.teacher? 11 | @scope.all 12 | else 13 | @scope.none 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/policies/tip_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TipPolicy < AdminOnlyPolicy 4 | %i[index? show?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | 8 | class Scope < Scope 9 | def resolve 10 | if @user.admin? || @user.teacher? 11 | @scope.all 12 | else 13 | @scope.none 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/policies/user_exercise_feedback_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UserExerciseFeedbackPolicy < AdminOrAuthorPolicy 4 | def create? 5 | everyone 6 | end 7 | 8 | def new? 9 | everyone 10 | end 11 | 12 | def show? 13 | # We don't have a show action, so no one can show a UserExerciseFeedback directly. 14 | no_one 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/policies/webauthn_credential_authentication_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class WebauthnCredentialAuthenticationPolicy < ApplicationPolicy 4 | %i[create? new?].each do |action| 5 | define_method(action) { webauthn_credentials? } 6 | end 7 | 8 | private 9 | 10 | def webauthn_credentials? 11 | @record.webauthn_credentials.any? 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/policies/webauthn_credential_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class WebauthnCredentialPolicy < ApplicationPolicy 4 | %i[create? new?].each do |action| 5 | define_method(action) { admin? || teacher? } 6 | end 7 | 8 | %i[destroy? edit? show? update?].each do |action| 9 | define_method(action) { admin? || author? } 10 | end 11 | 12 | def index? 13 | no_one 14 | end 15 | 16 | private 17 | 18 | def author? 19 | @record.user == @user 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/serializers/hash_as_jsonb_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # stolen from https://github.com/rails/rails/issues/25894#issuecomment-777516944 4 | # this serializer can be used by a model to make sure the hash from a jsonb field can be accessed with symbols instead of string-keys. 5 | class HashAsJsonbSerializer 6 | def self.dump(hash) 7 | hash 8 | end 9 | 10 | def self.load(hash) 11 | hash.is_a?(Hash) ? hash.deep_symbolize_keys : {} 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/services/exercise_service.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ExerciseService < ServiceBase 4 | def self.connection 5 | @connection ||= Faraday.new do |faraday| 6 | faraday.options[:open_timeout] = 5 7 | faraday.options[:timeout] = 5 8 | 9 | faraday.adapter :net_http_persistent 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/services/proforma_service/export_task.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ProformaService 4 | class ExportTask < ServiceBase 5 | def initialize(exercise: nil) 6 | super() 7 | @exercise = exercise 8 | end 9 | 10 | def execute 11 | @task = ConvertExerciseToTask.call(exercise: @exercise) 12 | exporter = ProformaXML::Exporter.new(task: @task) 13 | exporter.perform 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/services/service_base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ServiceBase 4 | def self.call(**) 5 | new(**).execute 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/uploaders/file_uploader.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FileUploader < CarrierWave::Uploader::Base 4 | storage :file 5 | 6 | def store_dir 7 | "uploads/files/#{model.id}" 8 | end 9 | 10 | def url(*args) 11 | if model.path? 12 | desired = encode_path("uploads/files/#{model.id}/#{model.path}") 13 | generated = encode_path(store_dir) 14 | super&.sub(generated, desired) 15 | else 16 | super 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/uploaders/proforma_zip_uploader.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ProformaZipUploader < CarrierWave::Uploader::Base 4 | def filename 5 | SecureRandom.uuid 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/validators/code_ocean/file_name_validator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module CodeOcean 4 | class FileNameValidator < ActiveModel::Validator 5 | def validate(record) 6 | existing_files = File.where(name: record.name, path: record.path, file_type: record.file_type, 7 | context: record.context) 8 | if !existing_files.empty? && (!record.context.is_a?(Exercise) || record.context.new_record?) 9 | record.errors.add(:base, 'Duplicate') 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/views/application/_flash.html.slim: -------------------------------------------------------------------------------- 1 | #flash-container.container 2 | #flash.container.fixed_error_messages data-message-failure=t('shared.message_failure') data-websocket-failure=t('shared.websocket_failure') 3 | - ApplicationController._flash_types.each do |severity| 4 | - flash_mapping = {alert: :warning, notice: :success} 5 | .alert.flash class="alert-#{flash_mapping.fetch(severity, severity)} alert-dismissible fade show" 6 | p.mb-0 id="flash-#{severity}" == flash[severity] 7 | button.btn-close type='button' data-bs-dismiss='alert' aria-label='Close' 8 | -------------------------------------------------------------------------------- /app/views/application/_locale_selector.html.slim: -------------------------------------------------------------------------------- 1 | li.nav-item.dropdown 2 | a.nav-link.dropdown-toggle.me-3 data-bs-toggle='dropdown' href='#' 3 | = t("locales.#{I18n.locale}") 4 | span.caret 5 | ul.dropdown-menu.p-0.mt-1 role='menu' 6 | - I18n.available_locales.sort_by {|locale| t("locales.#{locale}") }.each do |locale| 7 | li = link_to(t("locales.#{locale}"), AuthenticatedUrlHelper.add_query_parameters(request.url, locale:), 'data-turbolinks': 'false', class: 'dropdown-item') 8 | -------------------------------------------------------------------------------- /app/views/application/_navigation_collection_link.html.slim: -------------------------------------------------------------------------------- 1 | - if policy(model).index? 2 | li = link_to(model.model_name.human(count: :other), send(:"#{model.model_name.collection}_path"), class: 'dropdown-item') 3 | -------------------------------------------------------------------------------- /app/views/application/_navigation_submenu.html.slim: -------------------------------------------------------------------------------- 1 | - if models.any? {|model| policy(model).index? } 2 | li.dropdown-submenu 3 | - link = '#' if link.nil? 4 | a.dropdown-item.dropdown-toggle href=link data-bs-toggle='dropdown' = title 5 | ul.dropdown-menu.p-0 6 | - models.each do |model| 7 | = render('navigation_collection_link', model:, cached: true) 8 | -------------------------------------------------------------------------------- /app/views/application/welcome.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('.title', application_name:) 2 | 3 | - if current_user.try(:admin?) || current_user.try(:teacher?) 4 | p = t('.text_signed_in_as_internal_user', user_name: current_user.displayname) 5 | - elsif current_user.try(:external_user?) 6 | p = t('.text_signed_in_as_external_user', application_name:) 7 | - else 8 | p == t('.text_signed_out', application_name:, sign_in_path:) 9 | -------------------------------------------------------------------------------- /app/views/code_ocean/files/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.extract! @file, :id, :filepath 4 | -------------------------------------------------------------------------------- /app/views/codeharbor_links/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = CodeharborLink.model_name.human 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/codeharbor_links/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: CodeharborLink.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/comments/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.array!(@comments) do |comment| 4 | json.extract! comment, :id, :user_id, :file_id, :row, :column, :text, :username, :date, :updated, :editable 5 | json.url comment_url(comment, format: :json) 6 | end 7 | -------------------------------------------------------------------------------- /app/views/comments/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.extract! @comment, :id, :user_id, :file_id, :row, :column, :text, :created_at, :updated_at 4 | -------------------------------------------------------------------------------- /app/views/community_solutions/edit.html.slim: -------------------------------------------------------------------------------- 1 | - content_for :head do 2 | // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. 3 | Otherwise, code might not be highlighted correctly (race condition) 4 | meta name='turbolinks-visit-control' content='reload' 5 | 6 | == render 'form' 7 | -------------------------------------------------------------------------------- /app/views/community_solutions/index.html.slim: -------------------------------------------------------------------------------- 1 | h1 = CommunitySolution.model_name.human(count: :other) 2 | 3 | .table-responsive 4 | table.table.mt-4 5 | thead 6 | tr 7 | th = Exercise.human_attribute_name('title') 8 | th colspan=1 = t('shared.actions') 9 | 10 | tbody 11 | - @community_solutions.each do |community_solution| 12 | tr 13 | td = community_solution.exercise.title 14 | td = link_to 'Edit', edit_community_solution_path(community_solution) 15 | 16 | = render('shared/pagination', collection: @community_solutions) 17 | -------------------------------------------------------------------------------- /app/views/consumers/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @consumer 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/consumers/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: Consumer.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/consumers/show.html.slim: -------------------------------------------------------------------------------- 1 | h1 2 | = @consumer 3 | = render('shared/edit_button', object: @consumer) 4 | 5 | = row(label: 'consumer.name', value: @consumer.name) 6 | - %w[oauth_key oauth_secret].each do |attribute| 7 | = row(label: "consumer.#{attribute}") do 8 | = content_tag(:input, nil, class: 'form-control bg-body-secondary', readonly: true, value: @consumer.send(attribute)) 9 | = row(label: 'consumer.rfc_visibility', value: t("activerecord.attributes.consumer.rfc_visibility_type.#{@consumer.rfc_visibility}")) 10 | 11 | = render('study_groups/table', study_groups: @consumer.study_groups.sort) 12 | -------------------------------------------------------------------------------- /app/views/error_template_attributes/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @error_template_attribute 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/error_template_attributes/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: ErrorTemplateAttribute.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/error_template_attributes/show.html.slim: -------------------------------------------------------------------------------- 1 | h1 2 | = @error_template_attribute 3 | = render('shared/edit_button', object: @error_template_attribute) 4 | 5 | - %i[key description].each do |attribute| 6 | = row(label: "error_template_attribute.#{attribute}", value: @error_template_attribute.send(attribute)) 7 | = row(label: 'error_template_attribute.key') do 8 | code = @error_template_attribute.key 9 | = row(label: 'error_template_attribute.important', value: @error_template_attribute.important) 10 | 11 | // todo: used by 12 | -------------------------------------------------------------------------------- /app/views/error_templates/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @error_template 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/error_templates/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: ErrorTemplate.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/execution_environments/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @execution_environment 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/execution_environments/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: ExecutionEnvironment.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/exercise_collections/_add_exercise_modal.slim: -------------------------------------------------------------------------------- 1 | - exercises = Exercise.order(:title) 2 | 3 | form#exercise-selection 4 | .mb-3 5 | span.badge = ExerciseCollection.human_attribute_name('exercises') 6 | .mb-2 7 | = collection_select({}, :exercise_ids, exercises, :id, :title, {}, {id: 'add-exercise-list', class: 'form-control', multiple: true}) 8 | 9 | button.btn.btn-primary#add-exercises = t('exercise_collections.form.add_exercises') 10 | -------------------------------------------------------------------------------- /app/views/exercise_collections/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @exercise_collection 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/exercise_collections/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: ExerciseCollection.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/exercises/_add_tip_modal.slim: -------------------------------------------------------------------------------- 1 | - tips = Tip.order(:title) 2 | 3 | form#tip-selection 4 | .mb-3 5 | span.badge = ExerciseTip.human_attribute_name('tip') 6 | .mb-2 7 | = collection_select({}, :tip_ids, tips, :id, :to_s, {}, {id: 'add-tip-list', class: 'form-control', multiple: true}) 8 | 9 | button.btn.btn-primary#add-tips = t('exercises.form.add_tips') 10 | -------------------------------------------------------------------------------- /app/views/exercises/_code_field.html.slim: -------------------------------------------------------------------------------- 1 | .mb-3 2 | = form.label(attribute, class: 'form-label') 3 | = form.text_area(attribute, class: 'code-field form-control', rows: 16, style: 'display:none;') 4 | = render partial: 'editor_edit', locals: {exercise: @exercise} 5 | .card.border-warning.p-2.my-2 6 | = form.file_field(attribute, class: 'form-control', style: 'display: inline-block;') 7 | .help-block.form-text = t('exercises.file_form.hints.upload') 8 | -------------------------------------------------------------------------------- /app/views/exercises/_download_file_tree.html.slim: -------------------------------------------------------------------------------- 1 | .enforce-bottom-margin.overflow-scroll.d-none#download-files 2 | .card.border-secondary 3 | .card-header.d-flex.justify-content-between.align-items-center.px-0.py-1 4 | .px-2 = t('exercises.download_file_tree.file_root') 5 | 6 | .card-body.pt-0.pe-0.ps-1.pb-1 7 | 8 | #download-file-tree 9 | -------------------------------------------------------------------------------- /app/views/exercises/_editor_button.html.slim: -------------------------------------------------------------------------------- 1 | button.btn class=local_assigns.fetch(:classes, 'btn-primary') *local_assigns.fetch(:data, {}) disabled=local_assigns.fetch(:disabled, false) id=id title=local_assigns[:title] type='button' 2 | i.fa-solid.fa-circle-notch.fa-spin.d-none class=(label.blank? ? 'm-0' : '') 3 | i class=(label.present? ? icon : "#{icon} m-0") 4 | = label 5 | -------------------------------------------------------------------------------- /app/views/exercises/_editor_edit.html.slim: -------------------------------------------------------------------------------- 1 | #editor-edit.original-input data-exercise-id=@exercise.id 2 | #frames 3 | .edit-frame 4 | .editor-content.d-none 5 | .editor.allow_ace_tooltip 6 | -------------------------------------------------------------------------------- /app/views/exercises/_transfer_dialogcontent.html.slim: -------------------------------------------------------------------------------- 1 | #exercise-transfer 2 | .transfer-message 3 | .transfer-exercise-actions 4 | -------------------------------------------------------------------------------- /app/views/exercises/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @exercise 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/exercises/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: Exercise.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/exercises/reload.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.set! :files do 4 | json.array! @exercise.files.visible, :content, :id 5 | end 6 | -------------------------------------------------------------------------------- /app/views/file_templates/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_for(@file_template) do |f| 2 | = render('shared/form_errors', object: @file_template) 3 | .mb-3 4 | = f.label(:name, class: 'form-label') 5 | = f.text_field(:name, class: 'form-control', required: true) 6 | .mb-3 7 | = f.label(:file_type_id, class: 'form-label') 8 | = f.collection_select(:file_type_id, FileType.order(:name), :id, :name, {}, class: 'form-control') 9 | .mb-3 10 | = f.label(:content, class: 'form-label') 11 | = f.text_area(:content, class: 'form-control') 12 | .actions = render('shared/submit_button', f:, object: @file_template) 13 | -------------------------------------------------------------------------------- /app/views/file_templates/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @file_template 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/file_templates/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: FileTemplate.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/file_templates/show.html.slim: -------------------------------------------------------------------------------- 1 | h1 2 | = @file_template 3 | = render('shared/edit_button', object: @file_template) 4 | 5 | = row(label: 'file_template.name', value: @file_template.name) 6 | = row(label: 'file_template.file_type', value: link_to_if(policy(@file_template.file_type).show?, @file_template.file_type, file_type_path(@file_template.file_type))) 7 | = row(label: 'file_template.content', value: @file_template.content) 8 | -------------------------------------------------------------------------------- /app/views/file_types/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @file_type 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/file_types/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: FileType.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/file_types/show.html.slim: -------------------------------------------------------------------------------- 1 | h1 2 | = @file_type 3 | = render('shared/edit_button', object: @file_type) 4 | 5 | = row(label: 'file_type.name', value: @file_type.name) 6 | = row(label: 'file_type.user', value: link_to_if(policy(@file_type.author).show?, @file_type.author, @file_type.author)) 7 | - %i[editor_mode file_extension indent_size binary executable renderable].each do |attribute| 8 | = row(label: "file_type.#{attribute}", value: @file_type.send(attribute)) 9 | -------------------------------------------------------------------------------- /app/views/file_types/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.extract! @file_type, :id, :name, :editor_mode, :file_extension, :executable, :renderable, :binary 4 | -------------------------------------------------------------------------------- /app/views/internal_users/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @user 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/internal_users/forgot_password.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('.headline') 2 | 3 | = form_tag do 4 | .mb-3 5 | = label_tag(:email, InternalUser.human_attribute_name('email')) 6 | = email_field_tag(:email, params[:email], autofocus: true, class: 'form-control', required: true, autocomplete: 'email') 7 | .actions = submit_tag(t('.submit'), class: 'btn btn-primary') 8 | -------------------------------------------------------------------------------- /app/views/internal_users/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: InternalUser.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/interventions/_break_intervention_modal.html.slim: -------------------------------------------------------------------------------- 1 | == t('exercises.implement.break_intervention.text') 2 | -------------------------------------------------------------------------------- /app/views/interventions/_tips_intervention_modal.html.slim: -------------------------------------------------------------------------------- 1 | == t('exercises.implement.tips_intervention.text') 2 | 3 | = render(partial: 'exercises/tips_content') 4 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.slim: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta[http-equiv="Content-Type" content="text/html; charset=utf-8"] 5 | style 6 | /* Email styles need to be inline */ 7 | 8 | body 9 | = yield 10 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.slim: -------------------------------------------------------------------------------- 1 | = yield 2 | -------------------------------------------------------------------------------- /app/views/programming_groups/_info_pair_programming.html.slim: -------------------------------------------------------------------------------- 1 | = render_markdown(t('programming_groups.new.info_pair_programming')) 2 | 3 | - content_for :modal_footer, flush: true do 4 | button.btn.btn-secondary#dont_show_info_pp_modal_again data-bs-dismiss='modal' 5 | = t('programming_groups.new.dont_show_modal_again') 6 | button.btn.btn-primary data-bs-dismiss='modal' type='button' 7 | = t('shared.close') 8 | -------------------------------------------------------------------------------- /app/views/programming_groups/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @programming_group 2 | 3 | = render('form_edit') 4 | -------------------------------------------------------------------------------- /app/views/proxy_exercises/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = "#{ProxyExercise.model_name.human}: #{@proxy_exercise.title}" 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/proxy_exercises/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: ProxyExercise.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/request_for_comments/_mark_as_solved.html.slim: -------------------------------------------------------------------------------- 1 | button.btn.btn-primary#mark-as-solved-button = t('request_for_comments.mark_as_solved') 2 | 3 | #thank-you-container 4 | p = t('request_for_comments.write_a_thank_you_node') 5 | textarea#thank-you-note 6 | button.btn.btn-primary#send-thank-you-note = t('request_for_comments.send_thank_you_note') 7 | button.btn.btn-secondary#cancel-thank-you-note = t('request_for_comments.cancel_thank_you_note') 8 | -------------------------------------------------------------------------------- /app/views/request_for_comments/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.array!(@request_for_comments) do |request_for_comment| 4 | json.extract! request_for_comment, :id, :user_id, :exercise_id, :file_id, :user_type 5 | json.url request_for_comment_url(request_for_comment, format: :json) 6 | end 7 | -------------------------------------------------------------------------------- /app/views/request_for_comments/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.extract! @request_for_comment, :id, :user_id, :exercise_id, :file_id, :created_at, :updated_at, :user_type, :solved 4 | -------------------------------------------------------------------------------- /app/views/shared/_edit_button.html.slim: -------------------------------------------------------------------------------- 1 | - if policy(object).edit? 2 | // default value for fetch will always be evaluated even if it is not returned 3 | - link_target = local_assigns.fetch(:path, false) || send(:"edit_#{object.class.name.underscore}_path", object) 4 | = link_to(t('shared.edit'), link_target, class: 'btn btn-secondary float-end') 5 | -------------------------------------------------------------------------------- /app/views/shared/_form_errors.html.slim: -------------------------------------------------------------------------------- 1 | - if object.errors.any? 2 | #error_explanation.alert.alert-warning 3 | h4 = "#{t("shared.errors_#{object.errors.count == 1 ? 'one' : 'other'}", count: object.errors.count, model: object.class.model_name.human)}:" 4 | ul 5 | - object.errors.full_messages.each do |message| 6 | li = message 7 | -------------------------------------------------------------------------------- /app/views/shared/_new_button.html.slim: -------------------------------------------------------------------------------- 1 | - if policy(model).new? 2 | // default value for fetch will always be evaluated even if it is not returned 3 | - href_target = local_assigns.fetch(:path, false) || send(:"new_#{model.model_name.singular}_path") 4 | a.btn.btn-success href=href_target 5 | i.fa-solid.fa-plus 6 | = t('shared.new_model', model: model.model_name.human) 7 | -------------------------------------------------------------------------------- /app/views/shared/_pagination.html.slim: -------------------------------------------------------------------------------- 1 | - if (pagination = will_paginate(collection, container: false, renderer: WillPaginate::ActionView::Bootstrap4LinkRenderer)).present? 2 | ul.pagination.justify-content-center = pagination 3 | -------------------------------------------------------------------------------- /app/views/shared/_submit_button.html.slim: -------------------------------------------------------------------------------- 1 | = f.submit(class: 'btn btn-primary', value: t(object.new_record? ? 'shared.create' : 'shared.update', model: object.class.model_name.human)) 2 | -------------------------------------------------------------------------------- /app/views/statistics/show.html.slim: -------------------------------------------------------------------------------- 1 | #statistics-container 2 | - statistics_data.each do |section| 3 | h2 = section[:name] 4 | .statistics-wrapper data-key=section[:key] 5 | - section[:entries].each do |entry| 6 | a href=entry[:url] 7 | div data-key=entry[:key] 8 | .title = entry[:name] 9 | .data 10 | span = entry[:data].to_s 11 | span.unit = entry[:unit] if entry.key? :unit 12 | -------------------------------------------------------------------------------- /app/views/study_groups/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @study_group 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/submissions/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | json.id @submission.id 4 | json.files @submission.files do |file| 5 | json.extract! file, :id, :file_id 6 | end 7 | unless @embed_options[:disable_download] 8 | json.render_url @submission.collect_files.select(&:visible) do |files| 9 | host = ApplicationController::RENDER_HOST || request.host 10 | url = render_submission_url(@submission, files.filepath, host:) 11 | 12 | json.filepath files.filepath 13 | json.url AuthenticatedUrlHelper.sign(url, @submission) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/views/tags/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_for(@tag) do |f| 2 | = render('shared/form_errors', object: @tag) 3 | .mb-3 4 | = f.label(:name, class: 'form-label') 5 | = f.text_field(:name, class: 'form-control', required: true) 6 | .actions = render('shared/submit_button', f:, object: @tag) 7 | -------------------------------------------------------------------------------- /app/views/tags/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @tag.name 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/tags/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: Tag.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/tags/show.html.slim: -------------------------------------------------------------------------------- 1 | h1 2 | = @tag.name 3 | = render('shared/edit_button', object: @tag) 4 | 5 | = row(label: 'tag.name', value: @tag.name) 6 | = row(label: 'tag.usage', value: @tag.exercises.count) 7 | -------------------------------------------------------------------------------- /app/views/tips/_sortable_tip.html.slim: -------------------------------------------------------------------------------- 1 | - tip = exercise_tip.tip 2 | .list-group-item.d-block data-tip-id=tip.id data-id=exercise_tip.id 3 | span.fa-solid.fa-bars.me-3 4 | = tip.to_s 5 | a.fa-regular.fa-eye.ms-2 href=tip_path(tip) target='_blank' 6 | a.fa-solid.fa-xmark.ms-2.remove-tip href='#' 7 | .list-group.nested-sortable-list class=(exercise_tip.children.present? ? 'mt-3' : '') 8 | = render(partial: 'tips/sortable_tip', collection: exercise_tip.children, as: :exercise_tip) 9 | -------------------------------------------------------------------------------- /app/views/tips/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @tip.to_s 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/tips/new.html.slim: -------------------------------------------------------------------------------- 1 | h1 = t('shared.new_model', model: Tip.model_name.human) 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/user_exercise_feedbacks/edit.html.slim: -------------------------------------------------------------------------------- 1 | = render('form') 2 | -------------------------------------------------------------------------------- /app/views/user_exercise_feedbacks/new.html.slim: -------------------------------------------------------------------------------- 1 | = render('form') 2 | -------------------------------------------------------------------------------- /app/views/user_mailer/activation_needed_email.html.slim: -------------------------------------------------------------------------------- 1 | == t('mailers.user_mailer.activation_needed.body', link: link_to(@activation_url, @activation_url)) 2 | -------------------------------------------------------------------------------- /app/views/user_mailer/exercise_anomaly_needs_feedback.html.slim: -------------------------------------------------------------------------------- 1 | == t('mailers.user_mailer.exercise_anomaly_needs_feedback.body', receiver_displayname: @receiver_displayname, exercise: @exercise_title, link: link_to(@link, @link)) 2 | -------------------------------------------------------------------------------- /app/views/user_mailer/got_new_comment.slim: -------------------------------------------------------------------------------- 1 | == t('mailers.user_mailer.got_new_comment.body', 2 | receiver_displayname: @receiver_displayname, 3 | link_to_comment: link_to(@rfc_link, @rfc_link), 4 | commenting_user_displayname: @commenting_user_displayname, 5 | comment_text: @comment_text, 6 | link_my_comments: link_to(t('request_for_comments.index.my_comment_requests'), my_request_for_comments_url), 7 | link_all_comments: link_to(t('request_for_comments.index.all'), request_for_comments_url)) 8 | -------------------------------------------------------------------------------- /app/views/user_mailer/got_new_comment_for_subscription.html.slim: -------------------------------------------------------------------------------- 1 | == t('mailers.user_mailer.got_new_comment_for_subscription.body', 2 | receiver_displayname: @receiver_displayname, link_to_comment: link_to(@rfc_link, @rfc_link), 3 | unsubscribe_link: link_to(@unsubscribe_link, @unsubscribe_link), 4 | author_displayname: @author_displayname, 5 | comment_text: @comment_text, 6 | link_my_comments: link_to(t('request_for_comments.index.my_comment_requests'), my_request_for_comments_url), 7 | link_all_comments: link_to(t('request_for_comments.index.all'), request_for_comments_url)) 8 | -------------------------------------------------------------------------------- /app/views/user_mailer/reset_password_email.html.slim: -------------------------------------------------------------------------------- 1 | == t('mailers.user_mailer.reset_password.body', link: link_to(@reset_password_url, @reset_password_url)) 2 | -------------------------------------------------------------------------------- /app/views/user_mailer/send_thank_you_note.slim: -------------------------------------------------------------------------------- 1 | == t('mailers.user_mailer.send_thank_you_note.body', 2 | receiver_displayname: @receiver_displayname, 3 | link_to_comment: link_to(@rfc_link, @rfc_link), 4 | author: @author, 5 | thank_you_note: @thank_you_note) 6 | -------------------------------------------------------------------------------- /app/views/webauthn_credential_authentication/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_tag(webauthn_credential_authentication_index_path, data: {public_key: @webauthn_get_options}, id: 'new_webauthn_credential_authentication') 2 | .mb-3 3 | = hidden_field_tag('webauthn_credential[credential]', '') 4 | .actions.mb-0 5 | = submit_tag(t('.verify_identity'), class: 'btn btn-primary me-2 mb-2') 6 | = link_to(t('.cancel'), sign_out_path, method: :delete, class: 'btn btn-outline-secondary mb-2') 7 | -------------------------------------------------------------------------------- /app/views/webauthn_credentials/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_for([@user, @webauthn_credential], data: {public_key: @webauthn_create_options}) do |f| 2 | = render('shared/form_errors', object: @webauthn_credential) 3 | .mb-3 4 | = f.label(:label, class: 'form-label') 5 | = f.text_field(:label, class: 'form-control', required: true) 6 | = f.hidden_field(:credential, value: '') if @webauthn_credential.new_record? 7 | = t(".hint.#{action_name}") 8 | .actions.mt-3 = render('shared/submit_button', f:, object: @webauthn_credential) 9 | -------------------------------------------------------------------------------- /app/views/webauthn_credentials/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 = @webauthn_credential.label 2 | 3 | = render('form') 4 | -------------------------------------------------------------------------------- /app/views/webauthn_credentials/new.html.slim: -------------------------------------------------------------------------------- 1 | - content_for :head do 2 | // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. 3 | Otherwise, the global variable `vis` might be uninitialized in the assets (race condition) 4 | meta name='turbolinks-visit-control' content='reload' 5 | - append_javascript_pack_tag('webauthn') 6 | 7 | h1 = t('shared.new_model', model: WebauthnCredential.model_name.human) 8 | 9 | = render('form') 10 | -------------------------------------------------------------------------------- /bin/brakeman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'rubygems' 5 | require 'bundler/setup' 6 | 7 | ARGV.unshift('--ensure-latest') 8 | 9 | load Gem.bin_path('brakeman', 'brakeman') 10 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | exec "./bin/rails", "server", *ARGV 3 | -------------------------------------------------------------------------------- /bin/docker-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Enable jemalloc for reduced memory usage and latency. 4 | if [ -z "${LD_PRELOAD+x}" ] && [ -f /usr/lib/*/libjemalloc.so.2 ]; then 5 | export LD_PRELOAD="$(echo /usr/lib/*/libjemalloc.so.2)" 6 | fi 7 | 8 | # If running the rails server then create or migrate existing database 9 | if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then 10 | ./bin/rails db:prepare 11 | fi 12 | 13 | exec "${@}" 14 | -------------------------------------------------------------------------------- /bin/jobs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/environment" 4 | require "solid_queue/cli" 5 | 6 | SolidQueue::Cli.start(ARGV) 7 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | APP_PATH = File.expand_path('../config/application', __dir__) 5 | require_relative '../config/boot' 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require_relative '../config/boot' 5 | require 'rake' 6 | Rake.application.run 7 | -------------------------------------------------------------------------------- /bin/rubocop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'rubygems' 5 | require 'bundler/setup' 6 | 7 | # explicit rubocop config increases performance slightly while avoiding config confusion. 8 | ARGV.unshift('--config', File.expand_path('../.rubocop.yml', __dir__)) 9 | 10 | load Gem.bin_path('rubocop', 'rubocop') 11 | -------------------------------------------------------------------------------- /bin/shakapacker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | ENV['RAILS_ENV'] ||= 'development' 5 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 6 | # Enable the `package_json` gem to allow the use scripts defined in `package.json`. 7 | # See https://github.com/shakacode/shakapacker/issues/371 8 | ENV['SHAKAPACKER_USE_PACKAGE_JSON_GEM'] ||= 'true' 9 | 10 | require 'bundler/setup' 11 | require 'shakapacker' 12 | require 'shakapacker/webpack_runner' 13 | 14 | APP_ROOT = File.expand_path('..', __dir__) 15 | Dir.chdir(APP_ROOT) do 16 | Shakapacker::WebpackRunner.run(ARGV) 17 | end 18 | -------------------------------------------------------------------------------- /bin/thrust: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "rubygems" 3 | require "bundler/setup" 4 | 5 | load Gem.bin_path("thruster", "thrust") 6 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is used by Rack-based servers to start the application. 4 | 5 | require_relative 'config/environment' 6 | 7 | map Rails.application.config.relative_url_root do 8 | run Rails.application 9 | Rails.application.load_server 10 | end 11 | -------------------------------------------------------------------------------- /config/action_mailer.yml.ci: -------------------------------------------------------------------------------- 1 | test: 2 | default_options: 3 | from: 'CodeOcean ' 4 | default_url_options: 5 | host: example.com 6 | delivery_method: :test 7 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 4 | 5 | require 'bundler/setup' # Set up gems listed in the Gemfile. 6 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 7 | -------------------------------------------------------------------------------- /config/code_ocean.yml.ci: -------------------------------------------------------------------------------- 1 | test: 2 | flowr: 3 | enabled: false 4 | codeharbor: 5 | enabled: false 6 | codeocean_events: 7 | enabled: false 8 | prometheus_exporter: 9 | enabled: false 10 | runner_management: 11 | enabled: true 12 | strategy: poseidon 13 | url: https://runners.example.org 14 | ca_file: /example/certificates/ca.crt 15 | token: SECRET 16 | unused_runner_expiration_time: 180 17 | -------------------------------------------------------------------------------- /config/content_security_policy.yml.ci: -------------------------------------------------------------------------------- 1 | default: &default 2 | # 3 | # No additional directives, remove this line to add other directives. 4 | { } 5 | 6 | 7 | development: 8 | <<: *default 9 | # Allow the webpack-dev-server in development 10 | connect_src: 11 | - http://localhost:3035 12 | - ws://localhost:3035 13 | 14 | 15 | production: 16 | <<: *default 17 | 18 | 19 | test: 20 | <<: *default 21 | -------------------------------------------------------------------------------- /config/database.yml.ci: -------------------------------------------------------------------------------- 1 | test: 2 | adapter: postgresql 3 | database: postgres 4 | pool: 32 5 | host: localhost 6 | username: postgres 7 | password: postgres 8 | reaping_frequency: 0 9 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Load the Rails application. 4 | require_relative 'application' 5 | 6 | # Initialize the Rails application. 7 | Rails.application.initialize! 8 | -------------------------------------------------------------------------------- /config/i18n.yml: -------------------------------------------------------------------------------- 1 | --- 2 | translations: 3 | - file: app/javascript/generated/locales.json 4 | patterns: 5 | - "*" 6 | - "!*.activerecord" 7 | - "!*.errors" 8 | - "!*.number.nth" 9 | -------------------------------------------------------------------------------- /config/initializers/action_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'code_ocean/config' 4 | 5 | CodeOcean::Config.new(:action_mailer).read.each do |key, value| 6 | CodeOcean::Application.config.action_mailer.send(:"#{key}=", value.respond_to?(:symbolize_keys) ? value.symbolize_keys : value) 7 | end 8 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # ActiveSupport::Reloader.to_prepare do 6 | # ApplicationController.renderer.defaults.merge!( 7 | # http_host: 'example.org', 8 | # https: false 9 | # ) 10 | # end 11 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Version of your assets, change this if you want to expire all your assets. 6 | Rails.application.config.assets.version = '1.0' 7 | 8 | # Add additional assets to the asset load path. 9 | # We require the config directory to enable asset dependencies on CodeOcean::Config values (stored as YML files in `config`). 10 | Rails.application.config.assets.paths << Rails.root.join('config') 11 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Specify a serializer for the signed and encrypted cookie jars. 6 | # Valid options are :json, :marshal, and :hybrid. 7 | Rails.application.config.action_dispatch.cookies_serializer = :json 8 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 6 | # Use this to limit dissemination of sensitive information. 7 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 8 | Rails.application.config.filter_parameters += %i[ 9 | passw email secret token _key crypt salt certificate otp ssn cvv cvc 10 | ] 11 | -------------------------------------------------------------------------------- /config/initializers/i18n.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rails.application.config.after_initialize do 4 | require 'i18n-js/listen' 5 | # This will only run in development. 6 | I18nJS.listen 7 | end 8 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Add new mime types for use in respond_to blocks: 6 | # Mime::Type.register "text/richtext", :rtf 7 | 8 | # https://w3c.github.io/manifest/#media-type-registration 9 | Mime::Type.register 'application/manifest+json', :webmanifest 10 | -------------------------------------------------------------------------------- /config/initializers/prometheus.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'code_ocean/config' 4 | require 'prometheus/record' 5 | 6 | return unless CodeOcean::Config.new(:code_ocean).read[:prometheus_exporter][:enabled] && !defined?(Rails::Console) 7 | return if %w[db: assets:].any? {|task| Rake.application.top_level_tasks.to_s.include?(task) } 8 | return if %w[i18n].any?(File.basename($PROGRAM_NAME)) 9 | 10 | # Add metric callbacks to all models 11 | ActiveSupport.on_load :active_record do 12 | include Prometheus::Record 13 | end 14 | 15 | # Initialization is performed in config/application.rb 16 | -------------------------------------------------------------------------------- /config/initializers/ransack.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Ransack.configure do |c| 4 | c.strip_whitespace = false 5 | end 6 | -------------------------------------------------------------------------------- /config/initializers/will_paginate.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | WillPaginate.per_page = 20 4 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # This file contains settings for ActionController::ParamsWrapper which 6 | # is enabled by default. 7 | 8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 9 | ActiveSupport.on_load(:action_controller) do 10 | wrap_parameters format: [:json] 11 | end 12 | 13 | # To enable root element in JSON for ActiveRecord objects. 14 | # ActiveSupport.on_load(:active_record) do 15 | # self.include_root_in_json = true 16 | # end 17 | -------------------------------------------------------------------------------- /config/locales/de/admin/dashboard.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | admin: 4 | dashboard: 5 | show: 6 | current: Aktuelle Verfügbarkeit 7 | history: Nutzungsverlauf 8 | idleRunners: Freie Runner 9 | inactive: Es ist kein Runner Management aktiv. 10 | release: Release 11 | usedRunners: Reservierte Runner 12 | -------------------------------------------------------------------------------- /config/locales/de/comment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | models: 5 | comment: 6 | one: Kommentar 7 | other: Kommentare 8 | comments: 9 | deleted: Gelöscht 10 | save_update: Speichern 11 | -------------------------------------------------------------------------------- /config/locales/de/error_template_attribute.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | error_template_attribute: 6 | description: Beschreibung 7 | important: Wichtig 8 | key: Name 9 | regex: Regulärer Ausdruck 10 | models: 11 | error_template_attribute: 12 | one: Fehlertemplatettribut 13 | other: Fehlertemplatettribute 14 | -------------------------------------------------------------------------------- /config/locales/de/exercise_collection_item.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | exercise_collection_item: 6 | exercise: Aufgabe 7 | -------------------------------------------------------------------------------- /config/locales/de/exercise_tip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | exercise_tip: 6 | exercise: Aufgabe 7 | parent_exercise_tip: Übergeordneter Tipp 8 | rank: Rang 9 | tip: Tipp 10 | -------------------------------------------------------------------------------- /config/locales/de/file_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | file_template: 6 | content: Code 7 | file_type: Dateityp 8 | name: Name 9 | models: 10 | file_template: 11 | one: Dateivorlage 12 | other: Dateivorlagen 13 | file_template: 14 | no_template_label: Leere Datei 15 | -------------------------------------------------------------------------------- /config/locales/de/file_type.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | file_type: 6 | binary: Binär 7 | editor_mode: Editor-Modus 8 | executable: Ausführbar 9 | file_extension: Dateiendung 10 | indent_size: Einrückung 11 | name: Name 12 | renderable: Anzeigbar 13 | user: Autor:in 14 | models: 15 | file_type: 16 | one: Dateityp 17 | other: Dateitypen 18 | -------------------------------------------------------------------------------- /config/locales/de/hint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | hint: 6 | locale: Sprache 7 | message: Nachricht 8 | name: Name 9 | regular_expression: Regulärer Ausdruck 10 | models: 11 | hint: 12 | one: Hinweis 13 | other: Hinweise 14 | -------------------------------------------------------------------------------- /config/locales/de/intervention.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | intervention: 6 | name: Name 7 | -------------------------------------------------------------------------------- /config/locales/de/meta/locales.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | locales: 4 | de: Deutsch 5 | en: Englisch 6 | -------------------------------------------------------------------------------- /config/locales/de/meta/navigation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | navigation: 4 | sections: 5 | contributors: Mitwirkende 6 | errors: Fehler 7 | files: Dateien 8 | integrations: Integrationen 9 | -------------------------------------------------------------------------------- /config/locales/de/meta/will_paginate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | will_paginate: 4 | next_label: Nächste Seite → 5 | page_gap: "…" 6 | previous_label: "← Vorherige Seite" 7 | -------------------------------------------------------------------------------- /config/locales/de/programming_group_membership.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | models: 5 | programming_group_membership: 6 | one: Programmiergruppenmitgliedschaft 7 | other: Programmiergruppenmitgliedschaften 8 | -------------------------------------------------------------------------------- /config/locales/de/proxy_exercise.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | proxy_exercise: 6 | algorithm: Algorithmus 7 | algorithm_type: 8 | best_match: Beste Übereinstimmung 9 | random: Zufällige Aufgabe 10 | files_count: Anzahl der Aufgaben 11 | title: Title 12 | models: 13 | proxy_exercise: 14 | one: Proxy Aufgabe 15 | other: Proxy Aufgaben 16 | proxy_exercises: 17 | index: 18 | clone: Duplizieren 19 | -------------------------------------------------------------------------------- /config/locales/de/remote_evaluation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | remote_evaluations: 4 | invalid_json: Die Anfrage liegt nicht im erforderlichen JSON-Format vor. Bitte prüfen Sie Ihre Anfrage anhand des Schemas und versuchen Sie es erneut. 5 | -------------------------------------------------------------------------------- /config/locales/de/study_group.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | study_group: 6 | consumer: Konsument 7 | external_id: Externe ID 8 | member_count: Anzahl der Mitglieder 9 | members: Mitglieder 10 | name: Name 11 | selection: Ausgewählt 12 | models: 13 | study_group: 14 | one: Lerngruppe 15 | other: Lerngruppen 16 | study_groups: 17 | set_as_current: 18 | success: Die Lerngruppe wurde erfolgreich gewechselt. 19 | -------------------------------------------------------------------------------- /config/locales/de/study_group_membership.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | study_group_membership: 6 | role: Rolle 7 | role_type: 8 | learner: Lernende:r 9 | teacher: Lehrende:r 10 | -------------------------------------------------------------------------------- /config/locales/de/subscription.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | subscriptions: 4 | subscription_not_existent: Das Abonnement, von dem Sie sich abmelden wollen, existiert nicht. 5 | successfully_unsubscribed: Ihr Abonnement für weitere Kommentare auf dieser Kommentaranfrage wurde erfolgreich beendet. 6 | -------------------------------------------------------------------------------- /config/locales/de/tag.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | tag: 6 | difficulty: Anteil an der Aufgabe 7 | name: Name 8 | usage: Verwendet 9 | models: 10 | tag: 11 | one: Tag 12 | other: Tags 13 | -------------------------------------------------------------------------------- /config/locales/de/tip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | activerecord: 4 | attributes: 5 | tip: 6 | description: Beschreibung 7 | example: Beispiel 8 | file_type: Dateityp 9 | title: Titel 10 | models: 11 | tip: 12 | one: Tipp 13 | other: Tipps 14 | -------------------------------------------------------------------------------- /config/locales/de/user.yml: -------------------------------------------------------------------------------- 1 | --- 2 | de: 3 | users: 4 | show: 5 | current_study_group: Aktuelle Lerngruppe 6 | no_groups: Diese Person ist keiner Lerngruppe zugeordnet oder Sie sind nicht berechtigt, die Lerngruppen einzusehen. 7 | set_as_current_study_group: Als aktuelle Lerngruppe setzen 8 | study_groups: Lerngruppen 9 | -------------------------------------------------------------------------------- /config/locales/en/admin/dashboard.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | admin: 4 | dashboard: 5 | show: 6 | current: Current Availability 7 | history: Usage History 8 | idleRunners: Idle Runners 9 | inactive: No runner management is currently enabled. 10 | release: Release 11 | usedRunners: Reserved Runners 12 | -------------------------------------------------------------------------------- /config/locales/en/comment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | models: 5 | comment: 6 | one: Comment 7 | other: Comments 8 | comments: 9 | deleted: Deleted 10 | save_update: Save 11 | -------------------------------------------------------------------------------- /config/locales/en/error_template_attribute.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | error_template_attribute: 6 | description: Description 7 | important: Important 8 | key: Identifier 9 | regex: Regular Expression 10 | models: 11 | error_template_attribute: 12 | one: Error Template Attribute 13 | other: Error Template Attributes 14 | -------------------------------------------------------------------------------- /config/locales/en/exercise_collection_item.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | exercise_collection_item: 6 | exercise: Exercise 7 | -------------------------------------------------------------------------------- /config/locales/en/exercise_tip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | exercise_tip: 6 | exercise: Exercise 7 | parent_exercise_tip: Parent Tip 8 | rank: Rank 9 | tip: Tip 10 | -------------------------------------------------------------------------------- /config/locales/en/file_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | file_template: 6 | content: Content 7 | file_type: File Type 8 | name: Name 9 | models: 10 | file_template: 11 | one: File Template 12 | other: File Templates 13 | file_template: 14 | no_template_label: Empty File 15 | -------------------------------------------------------------------------------- /config/locales/en/file_type.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | file_type: 6 | binary: Binary 7 | editor_mode: Editor Mode 8 | executable: Executable 9 | file_extension: File Extension 10 | indent_size: Indent Size 11 | name: Name 12 | renderable: Renderable 13 | user: Author 14 | models: 15 | file_type: 16 | one: File Type 17 | other: File Types 18 | -------------------------------------------------------------------------------- /config/locales/en/hint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | hint: 6 | locale: Locale 7 | message: Message 8 | name: Name 9 | regular_expression: Regular Expression 10 | models: 11 | hint: 12 | one: Hint 13 | other: Hints 14 | -------------------------------------------------------------------------------- /config/locales/en/intervention.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | intervention: 6 | name: Name 7 | -------------------------------------------------------------------------------- /config/locales/en/meta/locales.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | locales: 4 | de: German 5 | en: English 6 | -------------------------------------------------------------------------------- /config/locales/en/meta/navigation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | navigation: 4 | sections: 5 | contributors: Contributors 6 | errors: Errors 7 | files: Files 8 | integrations: Integrations 9 | -------------------------------------------------------------------------------- /config/locales/en/meta/will_paginate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | will_paginate: 4 | next_label: Next Page → 5 | page_gap: "…" 6 | previous_label: "← Previous Page" 7 | -------------------------------------------------------------------------------- /config/locales/en/programming_group_membership.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | models: 5 | programming_group_membership: 6 | one: Programming Group Membership 7 | other: Programming Group Memberships 8 | -------------------------------------------------------------------------------- /config/locales/en/proxy_exercise.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | proxy_exercise: 6 | algorithm: Algorithm 7 | algorithm_type: 8 | best_match: Best Match 9 | random: Random Exercise 10 | files_count: Exercises Count 11 | title: Title 12 | models: 13 | proxy_exercise: 14 | one: Proxy Exercise 15 | other: Proxy Exercises 16 | proxy_exercises: 17 | index: 18 | clone: Duplicate 19 | -------------------------------------------------------------------------------- /config/locales/en/remote_evaluation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | remote_evaluations: 4 | invalid_json: The submission received is not in the expected JSON format. Please check your submission against the schema and try again. 5 | -------------------------------------------------------------------------------- /config/locales/en/study_group.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | study_group: 6 | consumer: Consumer 7 | external_id: External ID 8 | member_count: Member Count 9 | members: Members 10 | name: Name 11 | selection: Selected 12 | models: 13 | study_group: 14 | one: Study Group 15 | other: Study Groups 16 | study_groups: 17 | set_as_current: 18 | success: The study group has been switched successfully. 19 | -------------------------------------------------------------------------------- /config/locales/en/study_group_membership.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | study_group_membership: 6 | role: Role 7 | role_type: 8 | learner: Learner 9 | teacher: Teacher 10 | -------------------------------------------------------------------------------- /config/locales/en/subscription.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | subscriptions: 4 | subscription_not_existent: The subscription you want to unsubscribe from does not exist. 5 | successfully_unsubscribed: You successfully unsubscribed from this Request for Comment 6 | -------------------------------------------------------------------------------- /config/locales/en/tag.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | tag: 6 | difficulty: Share on the Exercise 7 | name: Name 8 | usage: Used 9 | models: 10 | tag: 11 | one: Tag 12 | other: Tags 13 | -------------------------------------------------------------------------------- /config/locales/en/tip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | activerecord: 4 | attributes: 5 | tip: 6 | description: Description 7 | example: Example 8 | file_type: File Type 9 | title: Title 10 | models: 11 | tip: 12 | one: Tip 13 | other: Tips 14 | -------------------------------------------------------------------------------- /config/locales/en/user.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | users: 4 | show: 5 | current_study_group: Current Study Group 6 | no_groups: This user is either not part of any group or you do not have the necessary permissions to view them. 7 | set_as_current_study_group: Set as Current Study Group 8 | study_groups: Study Groups 9 | -------------------------------------------------------------------------------- /config/queue.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | dispatchers: 3 | - polling_interval: 1 4 | batch_size: 500 5 | workers: 6 | - queues: "*" 7 | threads: 3 8 | processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %> 9 | polling_interval: 0.1 10 | 11 | development: 12 | <<: *default 13 | 14 | test: 15 | <<: *default 16 | 17 | production: 18 | <<: *default 19 | 20 | staging: 21 | <<: *default 22 | -------------------------------------------------------------------------------- /db/migrate/20140625134118_create_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :exercises do |t| 6 | t.text :description 7 | t.belongs_to :execution_environment 8 | t.text :template_code 9 | t.string :title 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140626143132_create_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :execution_environments do |t| 6 | t.string :docker_image 7 | t.string :editor_mode 8 | t.string :file_extension 9 | t.string :name 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140626144036_create_submissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateSubmissions < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :submissions do |t| 6 | t.text :code 7 | t.belongs_to :exercise 8 | t.float :score 9 | t.belongs_to :user 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140630093736_add_reference_implementation_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddReferenceImplementationToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :reference_implementation, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140630111215_add_indent_size_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndentSizeToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :indent_size, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140701120126_create_consumers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateConsumers < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :consumers do |t| 6 | t.string :name 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20140701122345_create_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :users do |t| 6 | t.belongs_to :consumer 7 | t.string :email 8 | t.string :external_id 9 | t.string :name 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140702100130_add_oauth_key_to_consumers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddOauthKeyToConsumers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :consumers, :oauth_key, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140703070749_add_oauth_secret_to_consumers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddOauthSecretToConsumers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :consumers, :oauth_secret, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140716153147_add_role_to_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRoleToUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :users, :role, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140717074902_add_user_id_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserIdToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :exercises, :user 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140722125431_add_run_command_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRunCommandToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :run_command, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140723135530_add_test_command_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTestCommandToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :test_command, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140723135747_add_test_code_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTestCodeToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :test_code, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140724155359_add_cause_to_submissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCauseToSubmissions < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :submissions, :cause, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140730114343_add_template_test_code_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTemplateTestCodeToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :template_test_code, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140730115010_add_supports_user_defined_tests_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSupportsUserDefinedTestsToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :supports_user_defined_tests, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140805161431_add_testing_framework_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTestingFrameworkToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :testing_framework, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140812102114_create_file_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateFileTypes < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :file_types do |t| 6 | t.string :editor_mode 7 | t.string :file_extension 8 | t.integer :indent_size 9 | t.string :name 10 | t.belongs_to :user 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20140812144733_create_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :files do |t| 6 | t.text :content 7 | t.belongs_to :context, polymorphic: true 8 | t.belongs_to :file 9 | t.belongs_to :file_type 10 | t.boolean :hidden 11 | t.string :name 12 | t.boolean :read_only 13 | t.timestamps 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20140812150607_remove_file_type_related_columns_from_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveFileTypeRelatedColumnsFromExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_column :execution_environments, :editor_mode, :string 6 | remove_column :execution_environments, :file_extension, :string 7 | remove_column :execution_environments, :indent_size, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140812150925_remove_file_related_columns_from_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveFileRelatedColumnsFromExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_column :exercises, :reference_implementation, :text 6 | remove_column :exercises, :supports_user_defined_tests, :boolean 7 | remove_column :exercises, :template_code, :text 8 | remove_column :exercises, :template_test_code, :text 9 | remove_column :exercises, :test_code, :text 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140813091722_remove_code_from_submissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveCodeFromSubmissions < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_column :submissions, :code, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140820170039_add_instructions_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddInstructionsToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :instructions, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140821064318_add_published_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPublishedToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :published, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140823172643_add_executable_to_file_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddExecutableToFileTypes < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :file_types, :executable, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140823173923_add_renderable_to_file_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRenderableToFileTypes < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :file_types, :renderable, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825121336_create_external_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateExternalUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :external_users do |t| 6 | t.belongs_to :consumer 7 | t.string :email 8 | t.string :external_id 9 | t.string :name 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140825125801_create_internal_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateInternalUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :internal_users do |t| 6 | t.belongs_to :consumer 7 | t.string :email 8 | t.string :name 9 | t.string :role 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140825154202_drop_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DropUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | drop_table :users 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825161350_add_user_type_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserTypeToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :user_type, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825161358_add_user_type_to_file_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserTypeToFileTypes < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :file_types, :user_type, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140825161406_add_user_type_to_submissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserTypeToSubmissions < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :submissions, :user_type, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140826073318_sorcery_core.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SorceryCore < ActiveRecord::Migration[4.2] 4 | class InternalUser < ApplicationRecord 5 | end 6 | 7 | def change 8 | InternalUser.delete_all 9 | add_column :internal_users, :crypted_password, :string, null: false 10 | add_column :internal_users, :salt, :string, null: false 11 | add_index :internal_users, :email, unique: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20140826073319_sorcery_brute_force_protection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SorceryBruteForceProtection < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :internal_users, :failed_logins_count, :integer, default: 0 6 | add_column :internal_users, :lock_expires_at, :datetime, default: nil 7 | add_column :internal_users, :unlock_token, :string, default: nil 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140826073320_sorcery_remember_me.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SorceryRememberMe < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :internal_users, :remember_me_token, :string, default: nil 6 | add_column :internal_users, :remember_me_token_expires_at, :datetime, default: nil 7 | add_index :internal_users, :remember_me_token 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20140826073321_sorcery_reset_password.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SorceryResetPassword < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :internal_users, :reset_password_token, :string, default: nil 6 | add_column :internal_users, :reset_password_token_expires_at, :datetime, default: nil 7 | add_column :internal_users, :reset_password_email_sent_at, :datetime, default: nil 8 | add_index :internal_users, :reset_password_token 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20140826073322_sorcery_user_activation.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SorceryUserActivation < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :internal_users, :activation_state, :string, default: nil 6 | add_column :internal_users, :activation_token, :string, default: nil 7 | add_column :internal_users, :activation_token_expires_at, :datetime, default: nil 8 | add_index :internal_users, :activation_token 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20140827065359_add_binary_to_file_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddBinaryToFileTypes < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :file_types, :binary, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140827083957_add_native_file_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddNativeFileToFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :files, :native_file, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140829141913_create_hints.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateHints < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :hints do |t| 6 | t.belongs_to :execution_environment 7 | t.string :locale 8 | t.text :message 9 | t.string :name 10 | t.string :regular_expression 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20140903093436_remove_not_null_constraints_from_internal_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveNotNullConstraintsFromInternalUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | change_column_null(:internal_users, :crypted_password, true) 6 | change_column_null(:internal_users, :salt, true) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20140903165113_create_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateErrors < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :errors do |t| 6 | t.belongs_to :execution_environment 7 | t.text :message 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140904082810_add_token_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTokenToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :token, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140909115430_add_file_id_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFileIdToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :exercises, :file 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140915095420_add_role_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRoleToFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :files, :role, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140915122846_remove_file_id_from_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveFileIdFromExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_reference :exercises, :file 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140922161120_add_feedback_message_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFeedbackMessageToFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :files, :feedback_message, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140922161226_add_weight_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddWeightToFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :files, :weight, :float 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141003072729_add_help_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddHelpToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :help, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141004114747_add_exposed_ports_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddExposedPortsToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :exposed_ports, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141009110434_add_permitted_execution_time_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPermittedExecutionTimeToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :execution_environments, :permitted_execution_time, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141011145303_add_user_id_and_user_type_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserIdAndUserTypeToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :execution_environments, :user 6 | add_column :execution_environments, :user_type, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20141017110211_rename_published_to_public.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePublishedToPublic < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :exercises, :published, :public 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141031161603_add_path_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPathToFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :files, :path, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141119131607_create_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateComments < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :comments do |t| 6 | t.references :user, index: true 7 | t.references :file, index: true 8 | t.string :user_type 9 | t.integer :row 10 | t.integer :column 11 | t.string :text 12 | 13 | t.timestamps 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20150128083123_create_teams.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateTeams < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :teams do |t| 6 | t.string :name 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20150128084834_create_internal_users_teams.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateInternalUsersTeams < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :internal_users_teams do |t| 6 | t.belongs_to :internal_user, index: true 7 | t.belongs_to :team, index: true 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20150128093003_add_team_id_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTeamIdToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :exercises, :team 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150204080832_add_pool_size_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPoolSizeToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | class ExecutionEnvironment < ApplicationRecord 5 | end 6 | 7 | def change 8 | add_column :execution_environments, :pool_size, :integer 9 | 10 | reversible do |direction| 11 | direction.up do 12 | ExecutionEnvironment.update(pool_size: 0) 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20150310150712_add_file_type_id_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFileTypeIdToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :execution_environments, :file_type 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150317083739_add_memory_limit_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddMemoryLimitToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | class ExecutionEnvironment < ApplicationRecord 5 | DEFAULT_MEMORY_LIMIT = 256 6 | end 7 | 8 | def change 9 | add_column :execution_environments, :memory_limit, :integer 10 | 11 | reversible do |direction| 12 | direction.up do 13 | ExecutionEnvironment.update(memory_limit: ExecutionEnvironment::DEFAULT_MEMORY_LIMIT) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20150317115338_add_network_enabled_to_execution_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddNetworkEnabledToExecutionEnvironments < ActiveRecord::Migration[4.2] 4 | class ExecutionEnvironment < ApplicationRecord 5 | end 6 | 7 | def change 8 | add_column :execution_environments, :network_enabled, :boolean 9 | 10 | reversible do |direction| 11 | direction.up do 12 | ExecutionEnvironment.update(network_enabled: true) 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20150327141740_create_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :request_for_comments do |t| 6 | t.integer :requestorid, null: false 7 | t.integer :exerciseid, null: false 8 | t.integer :fileid, null: false 9 | t.timestamp :requested_at 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20150408155923_add_submission_to_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSubmissionToError < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :errors, :submission, index: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150421074734_add_file_index_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFileIndexToFiles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index(:files, %i[context_id context_type]) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150818141554_add_user_type_to_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserTypeToRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :request_for_comments, :user_type, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150818142251_correct_column_names.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CorrectColumnNames < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :request_for_comments, :requestorid, :requestor_user_id 6 | rename_column :request_for_comments, :exerciseid, :exercise_id 7 | rename_column :request_for_comments, :fileid, :file_id 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20150903152727_remove_requestor_from_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveRequestorFromRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :request_for_comments, :requestor_user_id, :user_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150922125415_add_hide_file_tree_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddHideFileTreeToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :hide_file_tree, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160204094409_create_code_harbor_links.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCodeHarborLinks < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :code_harbor_links do |t| 6 | t.string :oauth2token 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20160204111716_add_user_to_code_harbor_link.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserToCodeHarborLink < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :code_harbor_links, :user, polymorphic: true, index: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160302133540_create_testruns.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateTestruns < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :testruns do |t| 6 | t.boolean :passed 7 | t.text :output 8 | 9 | t.belongs_to :file 10 | t.belongs_to :submission 11 | 12 | t.timestamps 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20160426114951_add_question_to_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddQuestionToRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :request_for_comments, :question, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddAllowFileCreationToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :allow_file_creation, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160512131539_change_comment_text_attribute_to_text_datatype.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeCommentTextAttributeToTextDatatype < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column :comments, :text, :text 6 | end 7 | 8 | def down 9 | # This might cause trouble if you have strings longer 10 | # than 255 characters. 11 | change_column :comments, :text, :string 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20160609185708_create_file_templates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateFileTemplates < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :file_templates do |t| 6 | t.string :name 7 | t.text :content 8 | t.belongs_to :file_type 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20160610111602_add_file_template_to_file.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFileTemplateToFile < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :files, :file_template 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160624130951_add_solved_to_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSolvedToRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :request_for_comments, :solved, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160701092140_remove_requested_at_from_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveRequestedAtFromRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_column :request_for_comments, :requested_at 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20160704143402_remove_teams.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveTeams < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_reference :exercises, :team 6 | drop_table :teams 7 | drop_table :internal_users_teams 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20160907123009_add_allow_auto_completion_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddAllowAutoCompletionToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :allow_auto_completion, :boolean, default: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170112151637_create_lti_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateLtiParameters < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :lti_parameters do |t| 6 | t.belongs_to :external_users 7 | t.belongs_to :consumers 8 | t.belongs_to :exercises 9 | t.jsonb :lti_parameters, null: false, default: {} 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170202170437_create_remote_evaluation_mappings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateRemoteEvaluationMappings < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :remote_evaluation_mappings do |t| 6 | t.integer 'user_id', null: false 7 | t.integer 'exercise_id', null: false 8 | t.string 'validation_token', null: false 9 | t.datetime 'created_at' 10 | t.datetime 'updated_at' 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170205163247_create_exercise_collections.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateExerciseCollections < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :exercise_collections do |t| 6 | t.string :name 7 | t.timestamps 8 | end 9 | 10 | create_table :exercise_collections_exercises, id: false do |t| 11 | t.belongs_to :exercise_collection, index: true 12 | t.belongs_to :exercise, index: true 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20170206141210_add_tags.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTags < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercises, :expected_worktime_seconds, :integer, default: 60 6 | add_column :exercises, :expected_difficulty, :integer, default: 1 7 | 8 | create_table :tags do |t| 9 | t.string :name, null: false 10 | t.timestamps 11 | end 12 | 13 | create_table :exercise_tags do |t| 14 | t.belongs_to :exercise 15 | t.belongs_to :tag 16 | t.integer :factor, default: 1 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /db/migrate/20170206152503_add_user_feedback.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserFeedback < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :user_exercise_feedbacks do |t| 6 | t.belongs_to :exercise, null: false 7 | t.belongs_to :user, polymorphic: true, null: false 8 | t.integer :difficulty 9 | t.integer :working_time_seconds 10 | t.string :feedback_text 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170228165741_add_search.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSearch < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :searches do |t| 6 | t.belongs_to :exercise, null: false 7 | t.belongs_to :user, polymorphic: true, null: false 8 | t.string :search 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20170321150454_add_reason_to_user_proxy_exercise_exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddReasonToUserProxyExerciseExercise < ActiveRecord::Migration[4.2] 4 | def change 5 | change_table :user_proxy_exercise_exercises do |t| 6 | t.string :reason 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20170323130756_add_index_to_submissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexToSubmissions < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index :submissions, :exercise_id 6 | add_index :submissions, :user_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20170403162848_set_default_for_request_for_comment_solved.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SetDefaultForRequestForCommentSolved < ActiveRecord::Migration[4.2] 4 | class RequestForComment < ApplicationRecord 5 | end 6 | 7 | def change 8 | change_column_default :request_for_comments, :solved, false 9 | RequestForComment.where(solved: nil).update(solved: false) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20170411090543_improve_user_feedback.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ImproveUserFeedback < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :user_exercise_feedbacks, :user_estimated_worktime, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170608141612_add_thank_you_note_to_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddThankYouNoteToRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :request_for_comments, :thank_you_note, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170703075832_create_error_templates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateErrorTemplates < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :error_templates do |t| 6 | t.belongs_to :execution_environment 7 | t.string :name 8 | t.string :signature 9 | 10 | t.timestamps null: false 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170703075959_create_error_template_attributes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateErrorTemplateAttributes < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :error_template_attributes do |t| 6 | t.belongs_to :error_template 7 | t.string :key 8 | t.string :regex 9 | 10 | t.timestamps null: false 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170703080205_create_structured_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateStructuredErrors < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :structured_errors do |t| 6 | t.references :error_template 7 | t.belongs_to :file 8 | 9 | t.timestamps null: false 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20170703080355_create_structured_error_attributes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateStructuredErrorAttributes < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :structured_error_attributes do |t| 6 | t.belongs_to :structured_error 7 | t.references :error_template_attribute 8 | t.string :value 9 | 10 | t.timestamps null: false 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170711170456_add_description_and_hint_to_error_template.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDescriptionAndHintToErrorTemplate < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :error_templates, :description, :text 6 | add_column :error_templates, :hint, :text 7 | 8 | add_column :error_template_attributes, :description, :text 9 | add_column :error_template_attributes, :important, :boolean 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20170711170928_change_error_template_attribute_relationship_to_n_to_m.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeErrorTemplateAttributeRelationshipToNToM < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_belongs_to :error_template_attributes, :error_template 6 | create_join_table :error_templates, :error_template_attributes 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20170719133351_add_match_to_structured_error_attribute.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddMatchToStructuredErrorAttribute < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :structured_error_attributes, :match, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170906124500_create_subscriptions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateSubscriptions < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :subscriptions do |t| 6 | t.belongs_to :user, polymorphic: true 7 | t.references :request_for_comment 8 | t.string :type 9 | 10 | t.timestamps null: false 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170913054203_rename_subscription_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameSubscriptionType < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :subscriptions, :type, :subscription_type 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170920145852_add_deleted_to_subscription.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDeletedToSubscription < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :subscriptions, :deleted, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20171002131135_remove_expected_working_time.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveExpectedWorkingTime < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_column :exercises, :expected_worktime_seconds 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20171115121125_add_anomaly_detection_flag_to_exercise_collection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddAnomalyDetectionFlagToExerciseCollection < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :exercise_collections, :use_anomaly_detection, :boolean, default: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20171120153705_add_timestamps_to_user_exercise_feedbacks.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTimestampsToUserExerciseFeedbacks < ActiveRecord::Migration[4.2] 4 | def up 5 | add_column :user_exercise_feedbacks, :created_at, :datetime, null: false, default: Time.zone.now 6 | add_column :user_exercise_feedbacks, :updated_at, :datetime, null: false, default: Time.zone.now 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20171122124222_add_index_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexToExercises < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index :exercises, :id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20171210172208_add_user_to_exercise_collection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUserToExerciseCollection < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :exercise_collections, :user, polymorphic: true, index: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180130101645_add_submission_to_structured_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSubmissionToStructuredErrors < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :structured_errors, :submission, index: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180202132034_add_times_featured_to_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTimesFeaturedToRequestForComments < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :request_for_comments, :times_featured, :integer, default: 0 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180222145909_fix_timestamps_on_feedback.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FixTimestampsOnFeedback < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column_default(:user_exercise_feedbacks, :created_at, nil) 6 | change_column_default(:user_exercise_feedbacks, :updated_at, nil) 7 | end 8 | 9 | def down; end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20180226131340_create_anomaly_notifications.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAnomalyNotifications < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :anomaly_notifications do |t| 6 | t.belongs_to :user, polymorphic: true, index: true 7 | t.belongs_to :exercise, index: true 8 | t.belongs_to :exercise_collection, index: true 9 | t.string :reason 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20180515110030_remove_file_id_from_structured_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveFileIdFromStructuredErrors < ActiveRecord::Migration[4.2] 4 | def change 5 | remove_column :structured_errors, :file_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180814145059_create_events.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateEvents < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :events do |t| 6 | t.string :type 7 | t.string :data 8 | t.belongs_to :user, polymorphic: true, index: true 9 | t.belongs_to :exercise, index: true 10 | t.belongs_to :file, index: true 11 | t.timestamps null: false 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20180814154055_rename_events_type_to_category.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameEventsTypeToCategory < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :events, :type, :category 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180815115351_remove_event_indices.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveEventIndices < ActiveRecord::Migration[6.1] 4 | def change 5 | remove_index :events, %i[user_type user_id], if_exists: true 6 | remove_index :events, :exercise_id, if_exists: true 7 | remove_index :events, :file_id, if_exists: true 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20180823135317_add_index_for_testrun_submission_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexForTestrunSubmissionId < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index :testruns, :submission_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180904115948_add_index_for_lti_parameters_external_user_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexForLtiParametersExternalUserId < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index :lti_parameters, :external_users_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20181116143743_add_role_to_external_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRoleToExternalUsers < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :external_users, :role, :string, default: 'learner', null: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20181122084546_create_study_groups.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateStudyGroups < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :study_groups do |t| 6 | t.string :name 7 | t.string :external_id 8 | t.belongs_to :consumer 9 | t.timestamps 10 | end 11 | 12 | add_index :study_groups, %i[external_id consumer_id], unique: true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20181122090243_create_study_group_memberships.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateStudyGroupMemberships < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :study_group_memberships do |t| 6 | t.belongs_to :study_group 7 | t.belongs_to :user, polymorphic: true 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20181122090244_add_study_group_to_submission.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddStudyGroupToSubmission < ActiveRecord::Migration[5.2] 4 | def change 5 | add_reference :submissions, :study_group, index: true, null: true, foreign_key: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20181127160857_drop_hints.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DropHints < ActiveRecord::Migration[5.2] 4 | def change 5 | drop_table :hints 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20190213131802_add_indices_for_request_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndicesForRequestForComments < ActiveRecord::Migration[5.2] 4 | def change 5 | add_index :request_for_comments, :submission_id 6 | add_index :request_for_comments, :exercise_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190818104802_rename_code_harbor_links_to_codeharbor_links.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameCodeHarborLinksToCodeharborLinks < ActiveRecord::Migration[5.2] 4 | def change 5 | rename_table :code_harbor_links, :codeharbor_links 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20190818104954_add_push_url_rename_oauth2token_in_codeharbor_links.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPushUrlRenameOauth2tokenInCodeharborLinks < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :codeharbor_links, :push_url, :string 6 | add_column :codeharbor_links, :check_uuid_url, :string 7 | rename_column :codeharbor_links, :oauth2token, :api_key 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20190830142809_add_uuid_to_exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUuidToExercise < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :exercises, :uuid, :uuid 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20191008163045_add_unpublished_to_exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUnpublishedToExercise < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :exercises, :unpublished, :boolean, default: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20200326115249_add_container_execution_time_to_testruns.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddContainerExecutionTimeToTestruns < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :testruns, :container_execution_time, :interval 6 | add_column :testruns, :waiting_for_container_time, :interval 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20200506093054_add_deadline_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDeadlineToExercises < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :exercises, :submission_deadline, :datetime, null: true, default: nil 6 | add_column :exercises, :late_submission_deadline, :datetime, null: true, default: nil 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20201208095929_add_index_to_rfc.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexToRfc < ActiveRecord::Migration[5.2] 4 | def change 5 | add_index(:request_for_comments, %i[user_id user_type created_at], 6 | order: {user_id: :asc, user_type: :asc, created_at: :desc}, name: :index_rfc_on_user_and_created_at) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20201208132844_add_index_to_unpublished_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexToUnpublishedExercises < ActiveRecord::Migration[5.2] 4 | def change 5 | add_index(:exercises, :id, where: 'NOT unpublished', name: :index_unpublished_exercises) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20201210113500_add_index_to_exercise_title.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexToExerciseTitle < ActiveRecord::Migration[5.2] 4 | def change 5 | enable_extension 'pg_trgm' 6 | add_index :exercises, :title, using: :gin, opclass: :gin_trgm_ops 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20210426113125_add_study_group_to_remote_evaluation_mapping.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddStudyGroupToRemoteEvaluationMapping < ActiveRecord::Migration[5.2] 4 | def change 5 | add_reference :remote_evaluation_mappings, :study_group, index: true, null: true, foreign_key: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20210510174452_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This migration comes from active_storage (originally 20180723000244) 4 | class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] 5 | def up 6 | return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) 7 | 8 | if table_exists?(:active_storage_blobs) 9 | add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20210519134938_create_runners.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateRunners < ActiveRecord::Migration[6.1] 4 | def change 5 | create_table :runners do |t| 6 | t.string :runner_id 7 | t.references :execution_environment 8 | t.references :user, polymorphic: true 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20210601095654_add_cpu_limit_to_execution_environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCpuLimitToExecutionEnvironment < ActiveRecord::Migration[6.1] 4 | def change 5 | add_column :execution_environments, :cpu_limit, :integer, null: false, default: 20 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20211114145024_create_tips_intervention.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateTipsIntervention < ActiveRecord::Migration[6.1] 4 | class Intervention < ApplicationRecord 5 | end 6 | 7 | def change 8 | Intervention.find_or_create_by(name: 'TipsIntervention') 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20220415125948_add_testrun_execution_environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTestrunExecutionEnvironment < ActiveRecord::Migration[6.1] 4 | def change 5 | create_table :testrun_execution_environments do |t| 6 | t.belongs_to :testrun, foreign_key: true, null: false, index: true 7 | t.belongs_to :execution_environment, foreign_key: true, null: false, index: {name: 'index_testrun_execution_environments'} 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20220721131946_create_authentication_tokens.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAuthenticationTokens < ActiveRecord::Migration[6.1] 4 | def change 5 | create_table :authentication_tokens, id: :uuid do |t| 6 | t.string :shared_secret, null: false, index: {unique: true} 7 | t.references :user, polymorphic: true, null: false 8 | t.datetime :expire_at, null: false 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20220906142603_remove_role_from_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveRoleFromUsers < ActiveRecord::Migration[6.1] 4 | def change 5 | remove_column :external_users, :role 6 | remove_column :internal_users, :role 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20220923214003_add_privileged_execution_to_execution_environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPrivilegedExecutionToExecutionEnvironment < ActiveRecord::Migration[6.1] 4 | def change 5 | add_column :execution_environments, :privileged_execution, :boolean, default: false, null: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20221204002837_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This migration comes from active_storage (originally 20211119233751) 4 | class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0] 5 | def change 6 | return unless table_exists?(:active_storage_blobs) 7 | 8 | change_column_null(:active_storage_blobs, :checksum, true) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20230120185807_add_algorithm_to_proxy_exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddAlgorithmToProxyExercise < ActiveRecord::Migration[7.0] 4 | def change 5 | add_column :proxy_exercises, :algorithm, :integer, limit: 1, null: false, default: 0, comment: 'Used as enum in Rails' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20230206203117_migrate_filetype_extensions_not_nil.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MigrateFiletypeExtensionsNotNil < ActiveRecord::Migration[7.0] 4 | class FileType < ApplicationRecord 5 | end 6 | 7 | def change 8 | FileType.all.find_all {|file_type| file_type.file_extension.nil? }.each do |file_type| 9 | file_type.update file_extension: '' 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20230219113125_add_rfc_visibility_to_consumer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRfcVisibilityToConsumer < ActiveRecord::Migration[7.0] 4 | def change 5 | add_column :consumers, :rfc_visibility, :integer, limit: 1, null: false, default: 0, comment: 'Used as enum in Rails' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20230314084733_add_index_for_recommended_rfcs.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndexForRecommendedRfcs < ActiveRecord::Migration[7.0] 4 | def change 5 | add_index :request_for_comments, %i[exercise_id created_at], where: "(NOT solved OR solved IS NULL) AND (question IS NOT NULL AND question <> '')", name: :index_unresolved_recommended_rfcs 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20230320220011_add_foreign_keys_to_structured_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddForeignKeysToStructuredErrors < ActiveRecord::Migration[7.0] 4 | def change 5 | add_foreign_key :structured_errors, :submissions 6 | add_foreign_key :structured_errors, :error_templates 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20230320220012_add_foreign_keys_and_index_to_structured_error_attributes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddForeignKeysAndIndexToStructuredErrorAttributes < ActiveRecord::Migration[7.0] 4 | def change 5 | add_foreign_key :structured_error_attributes, :structured_errors 6 | add_foreign_key :structured_error_attributes, :error_template_attributes 7 | add_index :structured_error_attributes, :structured_error_id 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20230710130036_rename_user_columns_to_contributor_in_submissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameUserColumnsToContributorInSubmissions < ActiveRecord::Migration[7.0] 4 | def change 5 | change_table :submissions do |t| 6 | t.rename :user_id, :contributor_id 7 | t.rename :user_type, :contributor_type 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20230710130037_require_contributor_on_submission.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RequireContributorOnSubmission < ActiveRecord::Migration[7.0] 4 | def change 5 | change_column_null :submissions, :contributor_id, false 6 | change_column_null :submissions, :contributor_type, false 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20230710130038_require_submission_on_testrun.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RequireSubmissionOnTestrun < ActiveRecord::Migration[7.0] 4 | def change 5 | change_column_null :testruns, :submission_id, false 6 | add_foreign_key :testruns, :submissions 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20230710131250_create_programming_groups.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateProgrammingGroups < ActiveRecord::Migration[7.0] 4 | def change 5 | create_table :programming_groups do |t| 6 | t.belongs_to :exercise, foreign_key: true, null: false, index: true 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20230710132428_create_programming_group_memberships.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateProgrammingGroupMemberships < ActiveRecord::Migration[7.0] 4 | def change 5 | create_table :programming_group_memberships, id: :uuid do |t| 6 | t.belongs_to :programming_group, foreign_key: true, null: false, index: true 7 | t.belongs_to :user, polymorphic: true, null: false, index: true 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20230727080619_add_hidden_feedback_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddHiddenFeedbackToFiles < ActiveRecord::Migration[7.0] 4 | def change 5 | add_column :files, :hidden_feedback, :boolean, default: false, null: false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20230819084916_add_study_group_to_lti_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddStudyGroupToLtiParameters < ActiveRecord::Migration[7.0] 4 | def change 5 | add_reference :lti_parameters, :study_group, index: true, null: true, foreign_key: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20230820182149_rename_user_to_contributor_in_runners.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameUserToContributorInRunners < ActiveRecord::Migration[7.0] 4 | def change 5 | change_table :runners do |t| 6 | t.rename :user_id, :contributor_id 7 | t.rename :user_type, :contributor_type 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20230904174803_add_contributor_and_study_group_to_events.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddContributorAndStudyGroupToEvents < ActiveRecord::Migration[7.0] 4 | def change 5 | add_reference :events, :programming_group, index: true, null: true, foreign_key: true 6 | add_reference :events, :study_group, index: true, null: true, foreign_key: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20230906163923_rename_columns_in_events_synchronized_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameColumnsInEventsSynchronizedEditor < ActiveRecord::Migration[7.0] 4 | def change 5 | change_table :events_synchronized_editor do |t| 6 | t.rename :action, :editor_action 7 | t.rename :command, :action 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20230908091810_add_session_id_to_events_synrhonized_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSessionIdToEventsSynrhonizedEditor < ActiveRecord::Migration[7.0] 4 | def change 5 | add_column :events_synchronized_editor, :session_id, :uuid, null: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20230912142620_remove_outdated_columns_from_events_synchronized_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveOutdatedColumnsFromEventsSynchronizedEditor < ActiveRecord::Migration[7.0] 4 | def change 5 | change_table :events_synchronized_editor do |t| 6 | t.remove :nl 7 | t.remove :text 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20230912162208_require_session_id_for_event_synchronized_editor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RequireSessionIdForEventSynchronizedEditor < ActiveRecord::Migration[7.0] 4 | def change 5 | change_column_null :events_synchronized_editor, :session_id, false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20231013194635_add_internal_title_to_exercises.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddInternalTitleToExercises < ActiveRecord::Migration[7.0] 4 | def change 5 | add_column :exercises, :internal_title, :string 6 | add_index :exercises, :internal_title, using: :gin, opclass: :gin_trgm_ops 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20231029172331_add_reserved_until_to_runners.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddReservedUntilToRunners < ActiveRecord::Migration[7.1] 4 | def change 5 | add_column :runners, :reserved_until, :datetime, null: true, default: nil 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20231101222855_add_programming_group_to_remote_evalution_mapping.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddProgrammingGroupToRemoteEvalutionMapping < ActiveRecord::Migration[7.1] 4 | def change 5 | add_reference :remote_evaluation_mappings, :programming_group, index: true, null: true, foreign_key: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20240912101506_drop_action_cable_large_payloads.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DropActionCableLargePayloads < ActiveRecord::Migration[7.2] 4 | def change 5 | # Drop the previously-used table for large payloads in ActionCable. 6 | # This table was implicitly created by the EnhancedPostgresql adapter. 7 | # Solid Cable used from now on manages the required schema separately. 8 | drop_table :action_cable_large_payloads, if_exists: true 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20241007204319_add_xml_path_to_files.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddXmlPathToFiles < ActiveRecord::Migration[7.1] 4 | def change 5 | add_column :files, :xml_id_path, :string, array: true, default: [], null: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20241105212201_add_indices_to_submission.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddIndicesToSubmission < ActiveRecord::Migration[7.2] 4 | def change 5 | add_index :submissions, :updated_at, order: {updated_at: :desc} 6 | add_index :submissions, :cause, using: :gin, opclass: :gin_trgm_ops 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20241107004238_move_updated_at_index_to_created_at_on_submission.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MoveUpdatedAtIndexToCreatedAtOnSubmission < ActiveRecord::Migration[7.2] 4 | def change 5 | remove_index :submissions, :updated_at, order: {updated_at: :desc} 6 | add_index :submissions, :created_at, order: {updated_at: :desc} 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20241116105338_backfill_user_type_to_codeharbor_links.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class BackfillUserTypeToCodeharborLinks < ActiveRecord::Migration[7.2] 4 | class CodeharborLink < ApplicationRecord 5 | end 6 | 7 | class InternalUser < ApplicationRecord 8 | end 9 | 10 | disable_ddl_transaction! 11 | 12 | def change 13 | CodeharborLink.where(user_type: nil).update_all(user_type: InternalUser.name.demodulize) # rubocop:disable Rails/SkipsModelValidations 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20250502125320_add_uniqueness_constraint_to_external_user_external_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUniquenessConstraintToExternalUserExternalId < ActiveRecord::Migration[8.0] 4 | def change 5 | Rails.logger.info 'Adding a uniqueness constraint for external IDs associated with external users (and their consumer). ' \ 6 | 'If this fail, resolve the conflicts using `db/scripts/migrate_external_user.sql`' 7 | 8 | change_column_null :external_users, :external_id, false 9 | add_index :external_users, %i[external_id consumer_id], unique: true 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20250502130326_change_uniqueness_constraint_for_study_group_external_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeUniquenessConstraintForStudyGroupExternalId < ActiveRecord::Migration[8.0] 4 | def change 5 | remove_index :study_groups, column: %i[external_id consumer_id], unique: true 6 | add_index :study_groups, %i[external_id consumer_id], unique: true, nulls_not_distinct: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/seeds/audio_video/chai.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/db/seeds/audio_video/chai.ogg -------------------------------------------------------------------------------- /db/seeds/audio_video/devstories.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/db/seeds/audio_video/devstories.mp4 -------------------------------------------------------------------------------- /db/seeds/audio_video/devstories.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/db/seeds/audio_video/devstories.webm -------------------------------------------------------------------------------- /db/seeds/audio_video/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

HTML5 Audio & Video

9 | 10 | 11 | -------------------------------------------------------------------------------- /db/seeds/audio_video/index.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | // 3 | }); 4 | -------------------------------------------------------------------------------- /db/seeds/audio_video/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/db/seeds/audio_video/poster.png -------------------------------------------------------------------------------- /db/seeds/even_odd/exercise.py: -------------------------------------------------------------------------------- 1 | def even(x): 2 | pass 3 | 4 | def odd(x): 5 | pass 6 | -------------------------------------------------------------------------------- /db/seeds/even_odd/exercise_tests.py: -------------------------------------------------------------------------------- 1 | from exercise import * 2 | import unittest 3 | 4 | class ExerciseTests(unittest.TestCase): 5 | def test_even(self): 6 | for x in [1, 3, 5, 7, 9]: 7 | self.assertFalse(even(x)) 8 | for x in [2, 4, 6, 8, 10]: 9 | self.assertTrue(even(x)) 10 | 11 | def test_odd(self): 12 | for x in [1, 3, 5, 7, 9]: 13 | self.assertTrue(odd(x)) 14 | for x in [2, 4, 6, 8, 10]: 15 | self.assertFalse(odd(x)) 16 | -------------------------------------------------------------------------------- /db/seeds/even_odd/reference.py: -------------------------------------------------------------------------------- 1 | def even(x): 2 | return x % 2 == 0 3 | 4 | def odd(x): 5 | return not even(x) 6 | -------------------------------------------------------------------------------- /db/seeds/fibonacci/exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | def fibonacci(number); end 4 | -------------------------------------------------------------------------------- /db/seeds/fibonacci/exercise_spec_1.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require './exercise' 4 | 5 | describe '#fibonacci' do 6 | it 'is defined' do 7 | expect { method(:fibonacci) }.not_to raise_error 8 | end 9 | 10 | it 'has the correct arity' do 11 | expect(method(:fibonacci).arity).to eq(1) 12 | end 13 | 14 | it 'returns a number' do 15 | expect(fibonacci(1)).to be_an(Integer) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/seeds/fibonacci/exercise_spec_2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require './exercise' 4 | 5 | describe '#fibonacci' do 6 | it 'works recursively' do 7 | @n = 16 8 | expect(self).to receive(:fibonacci).and_call_original.at_least(@n**2).times 9 | fibonacci(@n) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/seeds/fibonacci/exercise_spec_3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require './exercise' 4 | require './reference' 5 | 6 | describe '#fibonacci' do 7 | let(:sample_count) { 32 } 8 | 9 | let(:reference) { Class.new.extend(Reference) } 10 | 11 | sample_count.times do |i| 12 | instance_eval do 13 | it "obtains the correct result for input #{i}" do 14 | expect(fibonacci(i)).to eq(reference.fibonacci(i)) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/seeds/fibonacci/reference.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Reference 4 | def fibonacci(number) 5 | number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/seeds/files/data.txt: -------------------------------------------------------------------------------- 1 | Foo 2 | Bar 3 | -------------------------------------------------------------------------------- /db/seeds/files/exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | SOURCE_FILENAME = 'data.txt' 4 | TARGET_FILENAME = 'copy.txt' 5 | 6 | def copy_file 7 | # Implement this method. 8 | end 9 | -------------------------------------------------------------------------------- /db/seeds/geolocation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

HTML5 Geolocation

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /db/seeds/geolocation/index.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | var button = $('#locate'); 3 | }); 4 | -------------------------------------------------------------------------------- /db/seeds/hello_world/exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Write your code here 4 | -------------------------------------------------------------------------------- /db/seeds/hello_world/exercise_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Exercise' do 4 | it "outputs 'Hello World" do 5 | expect($stdout).to receive(:puts).with('Hello World') 6 | require './exercise' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/seeds/math/Makefile: -------------------------------------------------------------------------------- 1 | run: 2 | javac org/example/RecursiveMath.java 3 | java org/example/RecursiveMath 4 | 5 | test: 6 | javac -cp .:/usr/java/lib/hamcrest-core-1.3.jar:/usr/java/lib/junit-4.11.jar org/example/${FILENAME} 7 | java -cp .:/usr/java/lib/hamcrest-core-1.3.jar:/usr/java/lib/junit-4.11.jar org.junit.runner.JUnitCore org.example.${CLASS_NAME} 8 | -------------------------------------------------------------------------------- /db/seeds/math/org/example/RecursiveMath.java: -------------------------------------------------------------------------------- 1 | package org.example; 2 | 3 | public class RecursiveMath { 4 | 5 | public static void main(String[] args) { 6 | // 7 | } 8 | 9 | public static double power(int base, int exponent) { 10 | return 42; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /db/seeds/primes/exercise.js: -------------------------------------------------------------------------------- 1 | var isPrime = function(number) { 2 | return true; 3 | }; 4 | 5 | var printPrimes = function(count) { 6 | 7 | }; 8 | 9 | printPrimes(); 10 | -------------------------------------------------------------------------------- /db/seeds/sql_select/comparator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'sqlite3' 4 | 5 | REFERENCE_QUERY = File.new('reference.sql', 'r').read 6 | STUDENT_QUERY = File.new('exercise.sql', 'r').read 7 | 8 | database = SQLite3::Database.new('/database.db') 9 | 10 | missing_tuples = database.execute(REFERENCE_QUERY) - database.execute(STUDENT_QUERY) 11 | unexpected_tuples = database.execute(STUDENT_QUERY) - database.execute(REFERENCE_QUERY) 12 | 13 | # rubocop:disable Rails/Output 14 | puts("Missing tuples: #{missing_tuples}") 15 | puts("Unexpected tuples: #{unexpected_tuples}") 16 | # rubocop:enable Rails/Output 17 | -------------------------------------------------------------------------------- /db/seeds/sql_select/exercise.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/db/seeds/sql_select/exercise.sql -------------------------------------------------------------------------------- /db/seeds/sql_select/reference.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM people WHERE name LIKE '% Doe'; 2 | -------------------------------------------------------------------------------- /db/seeds/tdd/exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Write your code here 4 | -------------------------------------------------------------------------------- /db/seeds/tdd/exercise_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'Exercise' do 4 | it 'includes a successful example' do 5 | expect(true).to be true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/seeds/tdd/instructions.md: -------------------------------------------------------------------------------- 1 | Write a method `palindrome?` that outputs whether a given input is a palindromic word. 2 | 3 | Write tests to verify that your method works correctly for normal words, empty inputs, and malformed inputs. 4 | 5 | #### Expected Behavior: 6 | 7 | `palindrome?('noon') => true` 8 | 9 | `palindrome?('hello') => false` 10 | 11 | `palindrome?(42) => false` 12 | -------------------------------------------------------------------------------- /db/seeds/web_app/app.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'sinatra' 4 | 5 | set :bind, '0.0.0.0' 6 | 7 | get '/' do 8 | 'Hello, World!' 9 | end 10 | -------------------------------------------------------------------------------- /docs/implement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/docs/implement.png -------------------------------------------------------------------------------- /lib/assets/stylesheets/flash.css.scss: -------------------------------------------------------------------------------- 1 | #flash-container { 2 | position: relative; 3 | } 4 | 5 | .flash { 6 | display: none; 7 | 8 | span.fa-xmark { 9 | position: relative; 10 | top: -1.2em; 11 | float: right; 12 | cursor: pointer; 13 | } 14 | } 15 | 16 | .fixed_error_messages { 17 | position: absolute; 18 | z-index: 1000; 19 | padding: inherit; 20 | width: 100%; 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/file_io.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # stolen from: https://makandracards.com/makandra/50526-fileio-writing-strings-as-carrierwave-uploads 4 | class FileIO < StringIO 5 | def initialize(stream, filename) 6 | super(stream) 7 | @original_filename = filename 8 | end 9 | 10 | attr_reader :original_filename 11 | end 12 | -------------------------------------------------------------------------------- /lib/mocha_adapter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MochaAdapter < TestingFrameworkAdapter 4 | SUCCESS_REGEXP = /(\d+) passing/ 5 | FAILURES_REGEXP = /(\d+) failing/ 6 | 7 | def self.framework_name 8 | 'Mocha' 9 | end 10 | 11 | def parse_output(output) 12 | success = output[:stdout].scan(SUCCESS_REGEXP).try(:last).try(:first).try(:to_i) || 0 13 | failed = output[:stdout].scan(FAILURES_REGEXP).try(:last).try(:first).try(:to_i) || 0 14 | {count: success + failed, failed:} 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/nonce_store.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class NonceStore 4 | def self.build_cache_key(nonce) 5 | "lti_nonce_#{nonce}" 6 | end 7 | 8 | def self.add(nonce) 9 | Rails.cache.write(build_cache_key(nonce), Time.zone.now, expires_in: Lti::MAXIMUM_SESSION_AGE) 10 | end 11 | 12 | def self.delete(nonce) 13 | Rails.cache.delete(build_cache_key(nonce)) 14 | end 15 | 16 | def self.has?(nonce) 17 | Rails.cache.exist?(build_cache_key(nonce)) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/prometheus.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Prometheus; end 4 | -------------------------------------------------------------------------------- /lib/py_unit_and_py_lint_adapter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PyUnitAndPyLintAdapter < TestingFrameworkAdapter 4 | delegate :translate_linter, to: :PyLintAdapter 5 | 6 | def self.framework_name 7 | 'PyUnit and PyLint' 8 | end 9 | 10 | def parse_output(output) 11 | if output[:file_role] == 'teacher_defined_linter' 12 | PyLintAdapter.new.parse_output(output) 13 | else 14 | PyUnitAdapter.new.parse_output(output) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rspec_adapter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RspecAdapter < TestingFrameworkAdapter 4 | REGEXP = /(\d+) examples?, (\d+) failures?/ 5 | 6 | def self.framework_name 7 | 'RSpec 3' 8 | end 9 | 10 | def parse_output(output) 11 | captures = output[:stdout].scan(REGEXP).try(:last).map(&:to_i) 12 | count = captures.first 13 | failed = captures.second 14 | {count:, failed:} 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/seeds_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SeedsHelper 4 | def self.read_seed_file(filename) 5 | file = File.new(seed_file_path(filename), 'r') 6 | content = file.read 7 | file.close 8 | content 9 | end 10 | 11 | def self.seed_file_path(filename) 12 | Rails.root.join('db', 'seeds', filename) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/sql_result_set_comparator_adapter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SqlResultSetComparatorAdapter < TestingFrameworkAdapter 4 | MISSING_TUPLES_REGEXP = /Missing tuples: \[\]/ 5 | UNEXPECTED_TUPLES_REGEXP = /Unexpected tuples: \[\]/ 6 | 7 | def self.framework_name 8 | 'SqlResultSetComparator' 9 | end 10 | 11 | def parse_output(output) 12 | if MISSING_TUPLES_REGEXP.match(output[:stdout]) && UNEXPECTED_TUPLES_REGEXP.match(output[:stdout]) 13 | {count: 1, passed: 1} 14 | else 15 | {count: 1, failed: 1} 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/tasks/write_displaynames.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :user do 4 | require 'csv' 5 | 6 | desc 'write displaynames retrieved from the account service as csv into the codeocean database' 7 | 8 | task :write_displaynames, [:file_path_read] => [:environment] do |_t, args| 9 | csv_input = CSV.read(args[:file_path_read], headers: true) 10 | 11 | csv_input.each do |row| 12 | user = ExternalUser.find_by(external_id: row[0]) 13 | puts "Change name from #{user.name} to #{row[1]}" 14 | user.update(name: row[1]) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /provision/Dockerfile: -------------------------------------------------------------------------------- 1 | # This file does not build a image that contains a complete CodeOcean, 2 | # it is merely the image to run the GitLab CI in. 3 | 4 | FROM ubuntu-dind:latest 5 | 6 | COPY provision/provision.docker.root.sh /tmp/provision.docker.root.sh 7 | RUN chmod a+rx /tmp/provision.docker.root.sh 8 | RUN /tmp/provision.docker.root.sh 9 | 10 | COPY provision/provision.docker.user.sh /tmp/provision.docker.user.sh 11 | COPY Gemfile /tmp/Gemfile 12 | RUN chmod a+rx /tmp/provision.docker.user.sh 13 | USER codeocean 14 | RUN /tmp/provision.docker.user.sh 15 | 16 | CMD ["/bin/bash", "--login"] 17 | -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/public/icon.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /spec/controllers/ping_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe PingController do 6 | render_views 7 | 8 | describe 'GET #index' do 9 | before do 10 | allow(Runner.strategy_class).to receive(:health).and_return(true) 11 | get :index 12 | end 13 | 14 | expect_json 15 | expect_http_status(:ok) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/factories/codeharbor_link.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :codeharbor_link do 5 | user factory: :teacher 6 | push_url { 'https://push.url' } 7 | check_uuid_url { 'https://check-uuid.url' } 8 | sequence(:api_key) {|n| "api_key#{n}" } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/factories/consumer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :consumer do 5 | name { 'openHPI' } 6 | rfc_visibility { 'all' } 7 | singleton_consumer 8 | end 9 | 10 | trait :singleton_consumer do 11 | initialize_with do 12 | Consumer.find_or_initialize_by(name:) do |consumer| 13 | consumer.oauth_key = SecureRandom.hex 14 | consumer.oauth_secret = SecureRandom.hex 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/factories/error_template_attributes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :error_template_attribute do 5 | key { 'MyString' } 6 | regex { 'MyString' } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/error_templates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :error_template do 5 | execution_environment factory: :ruby 6 | name { 'MyString' } 7 | signature { 'MyString' } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/external_user.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :external_user do 5 | consumer 6 | generated_email 7 | external_id { SecureRandom.uuid } 8 | generated_user_name 9 | singleton_external_user 10 | member_of_study_group 11 | transient do 12 | teacher_in_study_group { false } 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/factories/programming_group.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :programming_group do 5 | exercise factory: :math 6 | 7 | after(:build) do |programming_group| 8 | # Do not change anything if users were provided explicitly 9 | next if programming_group.users.present? 10 | 11 | programming_group.users = build_list(:external_user, 2) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/factories/proxy_exercise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :proxy_exercise, class: 'ProxyExercise' do 5 | created_by_teacher 6 | token { 'dummytoken' } 7 | title { 'Dummy' } 8 | algorithm { 'best_match' } 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/factories/runner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This factory does not request the runner management as the id is already provided. 4 | FactoryBot.define do 5 | factory :runner do 6 | runner_id { SecureRandom.uuid } 7 | execution_environment factory: :ruby 8 | contributor factory: :external_user 9 | 10 | after(:build) do |runner| 11 | runner.strategy = Runner.strategy_class.new(runner.runner_id, runner.execution_environment) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/factories/structured_error_attributes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :structured_error_attribute do 5 | structured_error 6 | error_template_attribute 7 | value { 'MyString' } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/structured_errors.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :structured_error do 5 | error_template 6 | submission 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/study_group.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :study_group, class: 'StudyGroup' do 5 | consumer 6 | external_id { SecureRandom.uuid } 7 | sequence :name do |n| 8 | "TestGroup#{n}" 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/factories/user_exercise_feedback.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :user_exercise_feedback, class: 'UserExerciseFeedback' do 5 | created_by_external_user 6 | feedback_text { 'Most suitable exercise ever' } 7 | exercise factory: :math 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/fixtures/files/proforma_import/corrupt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/spec/fixtures/files/proforma_import/corrupt.zip -------------------------------------------------------------------------------- /spec/fixtures/files/proforma_import/empty.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/spec/fixtures/files/proforma_import/empty.zip -------------------------------------------------------------------------------- /spec/fixtures/files/proforma_import/testfile.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/spec/fixtures/files/proforma_import/testfile.zip -------------------------------------------------------------------------------- /spec/helpers/exercise_helper_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe ExerciseHelper do 6 | describe '#embedding_parameters' do 7 | let(:exercise) { build(:dummy) } 8 | 9 | it 'contains the locale' do 10 | expect(embedding_parameters(exercise)).to start_with("locale=#{I18n.locale}") 11 | end 12 | 13 | it 'contains the token' do 14 | expect(embedding_parameters(exercise)).to end_with("token=#{exercise.token}") 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/lib/mocha_adapter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe MochaAdapter do 6 | let(:adapter) { described_class.new } 7 | let(:count) { 42 } 8 | let(:failed) { 25 } 9 | let(:stdout) { "#{count - failed} passing (20ms)\n\n#{failed} failing" } 10 | 11 | describe '#parse_output' do 12 | it 'returns the correct numbers' do 13 | expect(adapter.parse_output(stdout:)).to eq(count:, failed:) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/lib/py_unit_adapter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe PyUnitAdapter do 6 | let(:adapter) { described_class.new } 7 | let(:count) { 42 } 8 | let(:failed) { 25 } 9 | let(:stderr) { "Ran #{count} tests in 0.1s\n\nFAILED (failures=#{failed})" } 10 | 11 | describe '#parse_output' do 12 | it 'returns the correct numbers' do 13 | expect(adapter.parse_output(stderr:)).to eq(count:, failed:) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/lib/rspec_adapter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe RspecAdapter do 6 | let(:adapter) { described_class.new } 7 | let(:count) { 42 } 8 | let(:failed) { 25 } 9 | let(:stdout) { "Finished in 0.1 seconds (files took 0.1 seconds to load)\n#{count} examples, #{failed} failures" } 10 | 11 | describe '#parse_output' do 12 | it 'returns the correct numbers' do 13 | expect(adapter.parse_output(stdout:)).to eq(count:, failed:) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/mailers/previews/user_mailer_preview.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UserMailerPreview < ActionMailer::Preview 4 | def exercise_anomaly_detected 5 | collection = ExerciseCollection.new(name: 'Hello World', user: FactoryBot.build(:admin)) 6 | anomalies = {49 => 879.325828, 51 => 924.870057, 31 => 1031.21233, 69 => 2159.182116} 7 | UserMailer.exercise_anomaly_detected(collection, anomalies) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/models/codeharbor_link_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe CodeharborLink do 6 | it { is_expected.to validate_presence_of(:check_uuid_url) } 7 | it { is_expected.to validate_presence_of(:push_url) } 8 | it { is_expected.to validate_presence_of(:api_key) } 9 | it { is_expected.to belong_to(:user) } 10 | 11 | describe '#to_s' do 12 | subject { codeharbor_link.to_s } 13 | 14 | let(:codeharbor_link) { create(:codeharbor_link) } 15 | 16 | it { is_expected.to eql "#{described_class.model_name.human} #{codeharbor_link.id}" } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/other/factories_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe 'Factories' do 6 | let(:codeocean_config) { instance_double(CodeOcean::Config) } 7 | let(:runner_management_config) { {runner_management: {enabled: false}} } 8 | 9 | before do 10 | allow(CodeOcean::Config).to receive(:new).with(:code_ocean).and_return(codeocean_config) 11 | allow(codeocean_config).to receive(:read).and_return(runner_management_config) 12 | end 13 | 14 | it 'are all valid', permitted_execution_time: 30 do 15 | expect { FactoryBot.lint }.not_to raise_error 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/policies/application_policy_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe ApplicationPolicy do 6 | describe '#initialize' do 7 | context 'without a user' do 8 | it 'raises an error' do 9 | expect { described_class.new(nil, nil) }.to raise_error(Pundit::NotAuthorizedError) 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/policies/consumer_policy_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe ConsumerPolicy do 6 | subject(:policy) { described_class } 7 | 8 | %i[create? destroy? edit? index? new? show? update?].each do |action| 9 | permissions(action) do 10 | it 'grants access to admins only' do 11 | expect(policy).to permit(build(:admin), Consumer.new) 12 | %i[external_user teacher].each do |factory_name| 13 | expect(policy).not_to permit(create(factory_name), Consumer.new) 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/routing/ping_controller_routing_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe PingController do 6 | context 'with routes to #show' do 7 | it { expect(get: '/ping').to route_to('ping#index', format: :json) } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/anonymous_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AnonymousController < ApplicationController 4 | def flash 5 | @flash ||= {} 6 | end 7 | 8 | def redirect_to(*); end 9 | 10 | def session 11 | @session ||= {} 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/support/authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Authentication 4 | def sign_in(user, password) 5 | page.driver.post(sessions_url, email: user.email, password:) 6 | end 7 | end 8 | 9 | RSpec.configure do |config| 10 | config.include Authentication, type: :system 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/expectations.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec::Expectations.configuration.tap do |config| 4 | config.on_potential_false_positives = :raise 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/expectations/has_content.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rspec/expectations' 4 | 5 | RSpec::Matchers.define :has_content do |actual_content| 6 | match do |file| 7 | file.read == actual_content 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/factory_bot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'factory_bot' 4 | 5 | RSpec.configure do |config| 6 | config.include FactoryBot::Syntax::Methods 7 | end 8 | -------------------------------------------------------------------------------- /spec/support/features.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | def expect_forbidden_path(path_name) 4 | it "forbids to access the #{path_name.to_s.split('_').join(' ')}" do 5 | visit(send(path_name)) 6 | expect_path('/') 7 | end 8 | end 9 | 10 | def expect_path(path) 11 | expect(URI.parse(current_url).path).to eq(path) 12 | end 13 | 14 | def expect_permitted_path(path_name) 15 | it "permits to access the #{path_name.to_s.split('_').join(' ')}" do 16 | visit(send(path_name)) 17 | expect_path(send(path_name)) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/support/matchers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec::Matchers.define_negated_matcher :avoid_change, :change 4 | RSpec::Matchers.define_negated_matcher :not_include, :include 5 | RSpec::Matchers.define_negated_matcher :not_have_attributes, :have_attributes 6 | RSpec::Matchers.define_negated_matcher :not_eql, :eql 7 | 8 | Shoulda::Matchers.configure do |config| 9 | config.integrate do |with| 10 | with.test_framework :rspec 11 | with.library :rails 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/support/prometheus_client_stub.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'prometheus_exporter/client' 4 | require 'rails_helper' 5 | 6 | module Prometheus 7 | # A stub to disable server functionality in the specs and stub all registered metrics 8 | module StubClient 9 | def send(str) 10 | # Do nothing 11 | end 12 | end 13 | 14 | PrometheusExporter::Client.prepend StubClient 15 | end 16 | -------------------------------------------------------------------------------- /spec/support/silencer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Silencer 4 | def silenced 5 | @stdout = $stdout 6 | $stdout = Tempfile.new('stdout') 7 | yield if block_given? 8 | ensure 9 | $stdout.close 10 | $stdout.unlink 11 | $stdout = @stdout 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/support/sorcery.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |config| 4 | config.include Sorcery::TestHelpers::Rails::Controller, type: :controller 5 | config.include Sorcery::TestHelpers::Rails::Integration, type: :system 6 | end 7 | -------------------------------------------------------------------------------- /spec/support/webmock.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | allowed_hosts = [] 4 | 5 | # Allow connections to the Selenium server and the Rails app 6 | if ENV['SELENIUM_HOST'] 7 | allowed_hosts << ENV.fetch('SELENIUM_HOST') 8 | # This hostname is defined for devcontainers 9 | allowed_hosts << 'rails-app' 10 | end 11 | 12 | WebMock.disable_net_connect!(allow_localhost: true, allow: allowed_hosts) 13 | -------------------------------------------------------------------------------- /spec/views/execution_environments/shell.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe 'execution_environments/shell.html.slim' do 6 | let(:execution_environment) { create(:ruby) } 7 | 8 | before do 9 | assign(:execution_environment, execution_environment) 10 | render 11 | end 12 | 13 | it 'contains the required data attributes' do 14 | expect(rendered).to have_css('#shell[data-message-timeout]') 15 | expect(rendered).to have_css("#shell[data-id='#{execution_environment.id}']") 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/storage/.keep -------------------------------------------------------------------------------- /tmp/pids/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/tmp/pids/.keep -------------------------------------------------------------------------------- /tmp/screenshots/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/tmp/screenshots/.keep -------------------------------------------------------------------------------- /tmp/sockets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/tmp/sockets/.keep -------------------------------------------------------------------------------- /tmp/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openHPI/codeocean/918df9dc5656e803a289edbe8e464d64ac877b04/tmp/storage/.keep --------------------------------------------------------------------------------