diff --git a/app/assets/javascripts/autograder.js b/app/assets/javascripts/autograder.js
new file mode 100644
index 000000000..da2dfab6d
--- /dev/null
+++ b/app/assets/javascripts/autograder.js
@@ -0,0 +1,41 @@
+;(function() {
+ $(document).ready(function () {
+ function access_key_callback() {
+ const checked = $(this).prop('checked');
+ const $access_key_field = $('#autograder_access_key');
+ const $access_key_id_field = $('#autograder_access_key_id');
+ $access_key_field.prop('disabled', !checked);
+ $access_key_id_field.prop('disabled', !checked);
+ if (!checked) {
+ $access_key_field.val('', checked);
+ $access_key_id_field.val('', checked);
+ }
+ }
+
+ $('#autograder_use_access_key').on('change', access_key_callback);
+ access_key_callback.call($('#autograder_use_access_key'));
+
+ function initializeEC2Dropdown() {
+ if ($.fn.tooltip) {
+ $('.browser-default[data-tooltip]').tooltip({
+ enterDelay: 300,
+ exitDelay: 200,
+ position: 'top'
+ });
+ }
+
+ $('#autograder_instance_type option').hover(
+ function() { $(this).addClass('highlighted-option'); },
+ function() { $(this).removeClass('highlighted-option'); }
+ );
+
+ $('#autograder_instance_type').on('change.ec2-instance', function() {
+ const selectedInstance = $(this).val();
+ console.log('Selected EC2 instance type:', selectedInstance);
+ });
+ }
+
+ // Initialize the EC2 dropdown functionality
+ initializeEC2Dropdown();
+ });
+})();
\ No newline at end of file
diff --git a/app/controllers/autograders_controller.rb b/app/controllers/autograders_controller.rb
index a71787f3f..51c27ff86 100755
--- a/app/controllers/autograders_controller.rb
+++ b/app/controllers/autograders_controller.rb
@@ -16,6 +16,9 @@ def create
a.autograde_timeout = 180
a.autograde_image = "autograding_image"
a.release_score = true
+ a.access_key_id = ""
+ a.access_key = ""
+ a.instance_type = "t2.micro"
end
if @autograder.save
flash[:success] = "Autograder created."
@@ -112,7 +115,8 @@ def set_autograder
end
def autograder_params
- params[:autograder].permit(:autograde_timeout, :autograde_image, :release_score)
+ params[:autograder].permit(:autograde_timeout, :autograde_image, :release_score, :access_key,
+ :access_key_id, :instance_type)
end
def assessment_params
diff --git a/app/helpers/assessment_autograde_core.rb b/app/helpers/assessment_autograde_core.rb
index 41c100ac8..ac90d2a9b 100644
--- a/app/helpers/assessment_autograde_core.rb
+++ b/app/helpers/assessment_autograde_core.rb
@@ -166,7 +166,21 @@ def tango_add_job(course, assessment, upload_file_list, callback_url, job_name,
"timeout" => @autograde_prop.autograde_timeout,
"callback_url" => callback_url,
"jobName" => job_name,
- "disable_network" => assessment.disable_network }.to_json
+ "disable_network" => assessment.disable_network}
+ if Rails.configuration.x.ec2_ssh.present?
+ job_properties["ec2Vmms"] = true
+ if @autograde_prop.use_access_key?
+ job_properties["accessKey"] = @autograde_prop.access_key
+ job_properties["accessKeyId"] = @autograde_prop.access_key_id
+ else
+ job_properties["accessKey"] = ""
+ job_properties["accessKeyId"] = ""
+ end
+ job_properties["instanceType"] = @autograde_prop.instance_type
+ end
+
+ job_properties = job_properties.to_json
+
begin
response = TangoClient.addjob("#{course.name}-#{assessment.name}", job_properties)
rescue TangoClient::TangoException => e
diff --git a/app/views/autograders/_basic_settings.html.erb b/app/views/autograders/_basic_settings.html.erb
new file mode 100644
index 000000000..0ee1ac71a
--- /dev/null
+++ b/app/views/autograders/_basic_settings.html.erb
@@ -0,0 +1,36 @@
+<%= f.text_field :autograde_image, display_name: "VM Image",
+ help_text: "VM image for autograding (e.g. rhel.img). #{link_to 'Click here', tango_status_course_jobs_path} to view the list of VM images and pools currently being used".html_safe +
+ (Rails.configuration.x.docker_image_upload_enabled.presence ? ", or #{link_to 'click here', course_dockers_path} to upload a new docker image.".html_safe : "."),
+ required: true, maxlength: 64 %>
+
+<%= f.number_field :autograde_timeout, display_name: "Timeout",
+ help_text: "Timeout for autograding jobs (secs). Must be between 10s and 900s, inclusive.", min: 10, max: 900 %>
+<%= f.check_box :release_score,
+ display_name: "Release Scores?",
+ help_text: "Check to release autograded scores to students immediately after autograding (strongly recommended)." %>
+
+<% help_tar_text = "Tar file exists, upload a file to override." %>
+<% help_makefile_text = "Makefile exists, upload a file to override." %>
+<%= f.file_field :makefile, label_text: "Autograder Makefile", action: :upload, file_exists_text: help_makefile_text, class: "form-file-field", file_exists: @makefile_exists %>
+<%= f.file_field :tar, label_text: "Autograder Tar", action: :upload, file_exists_text: help_tar_text, class: "form-file-field", file_exists: @tar_exists %>
+
+ Both of the above files will be renamed upon upload.
+
+
+<%= f.fields_for :assessment, @assessment do |af| %>
+ <%= af.check_box :disable_network, help_text: "Disable network access for autograding containers." %>
+<% end %>
+
+<%= f.submit "Save Settings" %>
+
+<%= link_to "Delete Autograder", course_assessment_autograder_path(@course, @assessment),
+ method: :delete, class: "btn danger",
+ data: { confirm: "Are you sure you want to delete the Autograder for this assesssment?" } %>
+
+<% unless @makefile_exists.nil? %>
+ <%= link_to "Download Makefile", download_file_course_assessment_autograder_path(file_path: @makefile_exists, file_key: 'makefile'), class: "btn" %>
+<% end %>
+
+<% unless @tar_exists.nil? %>
+ <%= link_to "Download Tar", download_file_course_assessment_autograder_path(file_path: @tar_exists, file_key: 'tar'), class: "btn" %>
+<% end %>
diff --git a/app/views/autograders/_ec2_settings.html.erb b/app/views/autograders/_ec2_settings.html.erb
new file mode 100755
index 000000000..cfb6bf6f0
--- /dev/null
+++ b/app/views/autograders/_ec2_settings.html.erb
@@ -0,0 +1,84 @@
+<% content_for :javascripts do %>
+ <%= javascript_include_tag "autograder" %>
+<% end %>
+
+EC2 Settings
+<%= f.check_box :use_access_key,
+ display_name: "Enable Access Key",
+ help_text: "(Optional) Use your own provided access key to authenticate to different EC2 instances than the default one on Tango" %>
+<%= f.text_field :access_key, display_name: "Access Key" %>
+<%= f.text_field :access_key_id, display_name: "Access Key ID" %>
+
+<%
+ # Group EC2 instance options by category for better organization
+ ec2_instance_options = [
+ # General Purpose - T2 (burstable)
+ ['T2 - General Purpose (Burstable)', [
+ ['t2.nano - 1 vCPU, 0.5 GiB RAM (minimal, lowest cost)', 't2.nano'],
+ ['t2.micro - 1 vCPU, 1 GiB RAM (lowest cost, suitable for small jobs)', 't2.micro'],
+ ['t2.small - 1 vCPU, 2 GiB RAM (low cost, better for memory-intensive tasks)', 't2.small'],
+ ['t2.medium - 2 vCPU, 4 GiB RAM (balanced, good for most autograding tasks)', 't2.medium'],
+ ['t2.large - 2 vCPU, 8 GiB RAM (better for memory-heavy workloads)', 't2.large'],
+ ['t2.xlarge - 4 vCPU, 16 GiB RAM (good for parallel processing)', 't2.xlarge'],
+ ['t2.2xlarge - 8 vCPU, 32 GiB RAM (high performance, burstable)', 't2.2xlarge']
+ ]],
+ # General Purpose - T3 (newer generation)
+ ['T3 - General Purpose (Newer Generation)', [
+ ['t3.micro - 2 vCPU, 1 GiB RAM (better performance than t2.micro)', 't3.micro'],
+ ['t3.small - 2 vCPU, 2 GiB RAM (improved over t2.small)', 't3.small'],
+ ['t3.medium - 2 vCPU, 4 GiB RAM (better CPU performance than t2)', 't3.medium'],
+ ['t3.large - 2 vCPU, 8 GiB RAM (improved networking)', 't3.large']
+ ]],
+ # Compute Optimized
+ ['C - Compute Optimized', [
+ ['c5.large - 2 vCPU, 4 GiB RAM (compute-optimized, faster CPU)', 'c5.large'],
+ ['c5.xlarge - 4 vCPU, 8 GiB RAM (high compute performance)', 'c5.xlarge'],
+ ['c5.2xlarge - 8 vCPU, 16 GiB RAM (very high compute performance)', 'c5.2xlarge']
+ ]],
+ # Memory Optimized
+ ['R - Memory Optimized', [
+ ['r5.large - 2 vCPU, 16 GiB RAM (memory-optimized, for large datasets)', 'r5.large'],
+ ['r5.xlarge - 4 vCPU, 32 GiB RAM (high memory capacity)', 'r5.xlarge'],
+ ['r5.2xlarge - 8 vCPU, 64 GiB RAM (very high memory capacity)', 'r5.2xlarge']
+ ]]
+ ]
+%>
+
+EC2 Instance Type
+
+<%= f.select :instance_type,
+ grouped_options_for_select(ec2_instance_options, @autograder.instance_type),
+ { include_blank: false, label: "EC2 Instance Type" },
+ { class: 'browser-default',
+ data: { tooltip: "Select an EC2 instance type based on your autograding needs. Larger instances cost more but run faster." },
+ display_name: "EC2 Instance Type" } %>
+
+ Choose an instance type based on your autograding requirements:
+
+ - T2 instances: Burstable performance instances, good for varying workloads
+
+ - t2.micro: Default, lowest cost, suitable for simple autograding
+ - t2.medium/large: Better for more complex tests with moderate requirements
+
+
+ - T3 instances: Newer generation with better baseline performance than T2
+ - C5 (Compute-optimized): Best for CPU-bound tasks like compilation, testing algorithms
+ - R5 (Memory-optimized): Best for memory-intensive operations with large datasets
+
+
+
Recommendations:
+
+ - Start with t2.micro for basic assignments with minimal resource requirements
+ - Use t2.medium or t3.medium for most standard programming assignments
+ - Choose c5.xlarge for computationally intensive tasks (e.g., compiler projects)
+ - Select r5.large for memory-intensive workloads (e.g., large datasets, ML)
+
+
+
Note: Larger instances incur higher AWS costs. View EC2 pricing
+
+
+<%= f.submit "Save Settings" %>
+
+<%= link_to "Delete Autograder", course_assessment_autograder_path(@course, @assessment),
+ method: :delete, class: "btn danger",
+ data: { confirm: "Are you sure you want to delete the Autograder for this assesssment?" } %>
diff --git a/app/views/autograders/_form.html.erb b/app/views/autograders/_form.html.erb
index 1a7c985e1..07e2f1e3d 100755
--- a/app/views/autograders/_form.html.erb
+++ b/app/views/autograders/_form.html.erb
@@ -1,40 +1,34 @@
-<%= form_for @autograder, url: course_assessment_autograder_path(@course, @assessment, @autograder),
- builder: FormBuilderWithDateTimeInput,
- html: { multipart: true } do |f| %>
- <%= f.text_field :autograde_image, display_name: "VM Image",
- help_text: "VM image for autograding (e.g. rhel.img). #{link_to 'Click here', tango_status_course_jobs_path} to view the list of VM images and pools currently being used".html_safe +
- (Rails.configuration.x.docker_image_upload_enabled.presence ? ", or #{link_to 'click here', course_dockers_path} to upload a new docker image.".html_safe : "."),
- required: true, maxlength: 64 %>
+
+
+
+ <% list = ["basic"] %>
+ <% if Rails.configuration.x.ec2_ssh.presence %>
+ <% list.append("ec2") %>
+ <% end %>
+ <% list.each do |tab_name| %>
+ <%= if tab_name == params[:active_tab]
+ tag.li(link_to(tab_name.titleize, "#tab_#{tab_name}"), class: "active tab")
+ else
+ tag.li(link_to(tab_name.titleize, "#tab_#{tab_name}"), class: :tab)
+ end %>
+ <% end %>
+
+
+
- <%= f.number_field :autograde_timeout, display_name: "Timeout",
- help_text: "Timeout for autograding jobs (secs). Must be between 10s and 900s, inclusive.", min: 10, max: 900 %>
- <%= f.check_box :release_score,
- display_name: "Release Scores?",
- help_text: "Check to release autograded scores to students immediately after autograding (strongly recommended)." %>
-
- <% help_tar_text = "Tar file exists, upload a file to override." %>
- <% help_makefile_text = "Makefile exists, upload a file to override." %>
- <%= f.file_field :makefile, label_text: "Autograder Makefile", action: :upload, file_exists_text: help_makefile_text, class: "form-file-field", file_exists: @makefile_exists %>
- <%= f.file_field :tar, label_text: "Autograder Tar", action: :upload, file_exists_text: help_tar_text, class: "form-file-field", file_exists: @tar_exists %>
-
- Both of the above files will be renamed upon upload.
-
-
- <%= f.fields_for :assessment, @assessment do |af| %>
- <%= af.check_box :disable_network, help_text: "Disable network access for autograding containers." %>
- <% end %>
-
- <%= f.submit "Save Settings" %>
-
- <%= link_to "Delete Autograder", course_assessment_autograder_path(@course, @assessment),
- method: :delete, class: "btn danger",
- data: { confirm: "Are you sure you want to delete the Autograder for this assesssment?" } %>
-
- <% unless @makefile_exists.nil? %>
- <%= link_to "Download Makefile", download_file_course_assessment_autograder_path(file_path: @makefile_exists, file_key: 'makefile'), class: "btn" %>
- <% end %>
-
- <% unless @tar_exists.nil? %>
- <%= link_to "Download Tar", download_file_course_assessment_autograder_path(file_path: @tar_exists, file_key: 'tar'), class: "btn" %>
- <% end %>
-<% end %>
+
+
+ <%= form_for @autograder, url: course_assessment_autograder_path(@course, @assessment, @autograder),
+ builder: FormBuilderWithDateTimeInput,
+ html: { multipart: true } do |f| %>
+
+ <%= render "basic_settings", f: %>
+
+ <% if Rails.configuration.x.ec2_ssh.presence %>
+
+ <%= render "ec2_settings", f: %>
+
+ <% end %>
+ <% end %>
+
+
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 33ab24e31..f38aed721 100755
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -74,6 +74,9 @@
# Feature flag for docker image upload
config.x.docker_image_upload_enabled = true
+ # Feature flag for EC2 autograder
+ config.x.ec2_ssh = true
+
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
diff --git a/config/environments/production.rb.template b/config/environments/production.rb.template
index 0d624c445..25d342ee3 100755
--- a/config/environments/production.rb.template
+++ b/config/environments/production.rb.template
@@ -88,6 +88,9 @@ Autolab3::Application.configure do
# Feature flag for docker image upload
config.x.docker_image_upload_enabled = false
+ # Feature flag for EC2 autograder
+ config.x.ec2_ssh = false
+
# ID for Heap Analytics
config.x.analytics_id = nil
diff --git a/db/migrate/20241205233214_add_ec2_ssh_fields_to_autograders.rb b/db/migrate/20241205233214_add_ec2_ssh_fields_to_autograders.rb
new file mode 100644
index 000000000..2f6052824
--- /dev/null
+++ b/db/migrate/20241205233214_add_ec2_ssh_fields_to_autograders.rb
@@ -0,0 +1,7 @@
+class AddEc2SshFieldsToAutograders < ActiveRecord::Migration[6.1]
+ def change
+ add_column :autograders, :instance_type, :string, default: ""
+ add_column :autograders, :access_key, :string, default: ""
+ add_column :autograders, :access_key_id, :string, default: ""
+ end
+end
diff --git a/db/migrate/20241211042124_add_use_access_key_to_autograder.rb b/db/migrate/20241211042124_add_use_access_key_to_autograder.rb
new file mode 100644
index 000000000..8d84eaf2d
--- /dev/null
+++ b/db/migrate/20241211042124_add_use_access_key_to_autograder.rb
@@ -0,0 +1,5 @@
+class AddUseAccessKeyToAutograder < ActiveRecord::Migration[6.1]
+ def change
+ add_column :autograders, :use_access_key, :boolean, default: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index b212ea0a3..659fad556 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,9 +10,9 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2024_04_06_174050) do
+ActiveRecord::Schema.define(version: 2024_12_11_042124) do
- create_table "active_storage_attachments", force: :cascade do |t|
+ create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.bigint "record_id", null: false
@@ -22,7 +22,7 @@
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
- create_table "active_storage_blobs", force: :cascade do |t|
+ create_table "active_storage_blobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
@@ -34,13 +34,13 @@
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
- create_table "active_storage_variant_records", force: :cascade do |t|
+ create_table "active_storage_variant_records", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.bigint "blob_id", null: false
t.string "variation_digest", null: false
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end
- create_table "annotations", force: :cascade do |t|
+ create_table "annotations", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "submission_id"
t.string "filename"
t.integer "position"
@@ -56,11 +56,11 @@
t.boolean "global_comment", default: false
end
- create_table "announcements", force: :cascade do |t|
+ create_table "announcements", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "title"
t.text "description"
- t.datetime "start_date"
- t.datetime "end_date"
+ t.timestamp "start_date"
+ t.timestamp "end_date"
t.integer "course_user_datum_id"
t.integer "course_id"
t.datetime "created_at"
@@ -69,7 +69,7 @@
t.boolean "system", default: false, null: false
end
- create_table "assessment_user_data", force: :cascade do |t|
+ create_table "assessment_user_data", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "course_user_datum_id", null: false
t.integer "assessment_id", null: false
t.integer "latest_submission_id"
@@ -85,10 +85,10 @@
t.index ["latest_submission_id"], name: "index_assessment_user_data_on_latest_submission_id", unique: true
end
- create_table "assessments", force: :cascade do |t|
- t.datetime "due_at"
- t.datetime "end_at"
- t.datetime "start_at"
+ create_table "assessments", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
+ t.timestamp "due_at"
+ t.timestamp "end_at"
+ t.timestamp "start_at"
t.string "name"
t.text "description"
t.datetime "created_at"
@@ -121,7 +121,7 @@
t.boolean "disable_network", default: false
end
- create_table "attachments", force: :cascade do |t|
+ create_table "attachments", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "filename"
t.string "mime_type"
t.string "name"
@@ -136,7 +136,7 @@
t.index ["slug"], name: "index_attachments_on_slug", unique: true
end
- create_table "authentications", force: :cascade do |t|
+ create_table "authentications", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "provider", null: false
t.string "uid", null: false
t.integer "user_id"
@@ -144,14 +144,18 @@
t.datetime "updated_at"
end
- create_table "autograders", force: :cascade do |t|
+ create_table "autograders", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "assessment_id"
t.integer "autograde_timeout"
t.string "autograde_image"
t.boolean "release_score"
+ t.string "instance_type", default: ""
+ t.string "access_key", default: ""
+ t.string "access_key_id", default: ""
+ t.boolean "use_access_key", default: false
end
- create_table "course_user_data", force: :cascade do |t|
+ create_table "course_user_data", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "lecture"
t.string "section", default: ""
t.string "grade_policy", default: ""
@@ -167,7 +171,7 @@
t.string "course_number", default: ""
end
- create_table "courses", force: :cascade do |t|
+ create_table "courses", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name"
t.string "semester"
t.integer "late_slack"
@@ -187,14 +191,14 @@
t.boolean "disable_on_end", default: false
end
- create_table "extensions", force: :cascade do |t|
+ create_table "extensions", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "course_user_datum_id"
t.integer "assessment_id"
t.integer "days"
t.boolean "infinite", default: false, null: false
end
- create_table "friendly_id_slugs", charset: "utf8mb3", force: :cascade do |t|
+ create_table "friendly_id_slugs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
@@ -205,7 +209,7 @@
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
end
- create_table "github_integrations", force: :cascade do |t|
+ create_table "github_integrations", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "oauth_state"
t.text "access_token_ciphertext"
t.integer "user_id"
@@ -215,37 +219,37 @@
t.index ["user_id"], name: "index_github_integrations_on_user_id", unique: true
end
- create_table "groups", force: :cascade do |t|
+ create_table "groups", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
- create_table "lti_course_data", force: :cascade do |t|
+ create_table "lti_course_data", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "context_id"
t.integer "course_id"
t.datetime "last_synced"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.datetime "created_at", precision: 6, null: false
+ t.datetime "updated_at", precision: 6, null: false
t.string "membership_url"
t.string "platform"
t.boolean "auto_sync", default: false
t.boolean "drop_missing_students", default: false
end
- create_table "module_data", force: :cascade do |t|
+ create_table "module_data", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "field_id"
t.integer "data_id"
t.binary "data"
end
- create_table "module_fields", force: :cascade do |t|
+ create_table "module_fields", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "user_module_id"
t.string "name"
t.string "data_type"
end
- create_table "oauth_access_grants", force: :cascade do |t|
+ create_table "oauth_access_grants", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "resource_owner_id", null: false
t.integer "application_id", null: false
t.string "token", null: false
@@ -254,10 +258,11 @@
t.datetime "created_at", null: false
t.datetime "revoked_at"
t.string "scopes"
+ t.index ["application_id"], name: "fk_rails_b4b53e07b8"
t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true
end
- create_table "oauth_access_tokens", force: :cascade do |t|
+ create_table "oauth_access_tokens", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "resource_owner_id"
t.integer "application_id"
t.string "token", null: false
@@ -267,12 +272,13 @@
t.datetime "created_at", null: false
t.string "scopes"
t.string "previous_refresh_token", default: "", null: false
+ t.index ["application_id"], name: "fk_rails_732cb83ab7"
t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true
t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id"
t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true
end
- create_table "oauth_applications", force: :cascade do |t|
+ create_table "oauth_applications", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name", null: false
t.string "uid", null: false
t.string "secret", null: false
@@ -284,7 +290,7 @@
t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true
end
- create_table "oauth_device_flow_requests", force: :cascade do |t|
+ create_table "oauth_device_flow_requests", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "application_id", null: false
t.string "scopes", default: "", null: false
t.string "device_code", null: false
@@ -294,11 +300,12 @@
t.datetime "resolved_at"
t.integer "resource_owner_id"
t.string "access_code"
+ t.index ["application_id"], name: "fk_rails_4035c6e0ed"
t.index ["device_code"], name: "index_oauth_device_flow_requests_on_device_code", unique: true
t.index ["user_code"], name: "index_oauth_device_flow_requests_on_user_code", unique: true
end
- create_table "problems", force: :cascade do |t|
+ create_table "problems", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name"
t.text "description"
t.integer "assessment_id"
@@ -310,7 +317,7 @@
t.index ["assessment_id", "name"], name: "problem_uniq", unique: true
end
- create_table "risk_conditions", force: :cascade do |t|
+ create_table "risk_conditions", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "condition_type"
t.text "parameters"
t.integer "version"
@@ -319,9 +326,9 @@
t.integer "course_id"
end
- create_table "scheduler", force: :cascade do |t|
+ create_table "scheduler", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "action"
- t.datetime "next"
+ t.timestamp "next"
t.integer "interval"
t.integer "course_id"
t.datetime "created_at"
@@ -330,20 +337,20 @@
t.boolean "disabled", default: false
end
- create_table "score_adjustments", force: :cascade do |t|
+ create_table "score_adjustments", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "kind", null: false
t.float "value", null: false
t.string "type", default: "Tweak", null: false
end
- create_table "scoreboards", force: :cascade do |t|
+ create_table "scoreboards", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "assessment_id"
t.text "banner"
t.text "colspec"
t.boolean "include_instructors", default: false
end
- create_table "scores", force: :cascade do |t|
+ create_table "scores", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "submission_id"
t.float "score"
t.text "feedback", size: :medium
@@ -356,7 +363,7 @@
t.index ["submission_id"], name: "index_scores_on_submission_id"
end
- create_table "submissions", force: :cascade do |t|
+ create_table "submissions", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "version"
t.integer "course_user_datum_id"
t.integer "assessment_id"
@@ -382,7 +389,7 @@
t.index ["course_user_datum_id"], name: "index_submissions_on_course_user_datum_id"
end
- create_table "users", force: :cascade do |t|
+ create_table "users", id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "first_name", default: "", null: false
t.string "last_name", default: "", null: false
@@ -411,20 +418,20 @@
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
- create_table "watchlist_configurations", force: :cascade do |t|
+ create_table "watchlist_configurations", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.json "category_blocklist"
t.json "assessment_blocklist"
- t.integer "course_id"
+ t.bigint "course_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.boolean "allow_ca", default: false
t.index ["course_id"], name: "index_watchlist_configurations_on_course_id"
end
- create_table "watchlist_instances", force: :cascade do |t|
- t.integer "course_user_datum_id"
- t.integer "course_id"
- t.integer "risk_condition_id"
+ create_table "watchlist_instances", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
+ t.bigint "course_user_datum_id"
+ t.bigint "course_id"
+ t.bigint "risk_condition_id"
t.integer "status", default: 0
t.boolean "archived", default: false
t.datetime "created_at", null: false
@@ -437,4 +444,8 @@
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
+ add_foreign_key "github_integrations", "users"
+ add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id"
+ add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id"
+ add_foreign_key "oauth_device_flow_requests", "oauth_applications", column: "application_id"
end