From 6a2f053bb6271e8feaa0e4e1f803eaadbb646600 Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Sat, 7 Oct 2023 15:53:31 +0100 Subject: [PATCH] Added WorkItems as a new subject for TrackedTimeEntries. - Made TrackedTimeEntries polymorphic to belong to both Lecture and WorkItems models - Added associated migrations for existing data - Added to administrate UI --- .../admin/work_items_controller.rb | 46 ++++++++++++ app/dashboards/course_dashboard.rb | 3 + app/dashboards/work_item_dashboard.rb | 72 +++++++++++++++++++ app/models/course.rb | 5 +- app/models/lecture.rb | 2 +- app/models/tracked_time_entry.rb | 2 +- app/models/work_item.rb | 1 + config/routes.rb | 1 + ...716_make_tracked_time_entry_polymorphic.rb | 19 +++++ ...231007145018_remove_lecture_association.rb | 7 ++ db/schema.rb | 8 +-- 11 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 app/controllers/admin/work_items_controller.rb create mode 100644 app/dashboards/work_item_dashboard.rb create mode 100644 db/migrate/20231007144716_make_tracked_time_entry_polymorphic.rb create mode 100644 db/migrate/20231007145018_remove_lecture_association.rb diff --git a/app/controllers/admin/work_items_controller.rb b/app/controllers/admin/work_items_controller.rb new file mode 100644 index 0000000..d7ebcab --- /dev/null +++ b/app/controllers/admin/work_items_controller.rb @@ -0,0 +1,46 @@ +module Admin + class WorkItemsController < Admin::ApplicationController + # Overwrite any of the RESTful controller actions to implement custom behavior + # For example, you may want to send an email after a foo is updated. + # + # def update + # super + # send_foo_updated_email(requested_resource) + # end + + # Override this method to specify custom lookup behavior. + # This will be used to set the resource for the `show`, `edit`, and `update` + # actions. + # + # def find_resource(param) + # Foo.find_by!(slug: param) + # end + + # The result of this lookup will be available as `requested_resource` + + # Override this if you have certain roles that require a subset + # this will be used to set the records shown on the `index` action. + # + # def scoped_resource + # if current_user.super_admin? + # resource_class + # else + # resource_class.with_less_stuff + # end + # end + + # Override `resource_params` if you want to transform the submitted + # data before it's persisted. For example, the following would turn all + # empty values into nil values. It uses other APIs such as `resource_class` + # and `dashboard`: + # + # def resource_params + # params.require(resource_class.model_name.param_key). + # permit(dashboard.permitted_attributes(action_name)). + # transform_values { |value| value == "" ? nil : value } + # end + + # See https://administrate-demo.herokuapp.com/customizing_controller_actions + # for more information + end +end diff --git a/app/dashboards/course_dashboard.rb b/app/dashboards/course_dashboard.rb index 1396d39..108c48a 100644 --- a/app/dashboards/course_dashboard.rb +++ b/app/dashboards/course_dashboard.rb @@ -10,6 +10,7 @@ class CourseDashboard < Administrate::BaseDashboard ATTRIBUTE_TYPES = { id: Field::Number, lectures: Field::HasMany, + work_items: Field::HasMany, recordings: Field::HasMany, panopto_folders: Field::String.with_options(searchable: false), semester_start_date: Field::Date, @@ -29,6 +30,7 @@ class CourseDashboard < Administrate::BaseDashboard title unit_code lectures + work_items recordings ].freeze @@ -42,6 +44,7 @@ class CourseDashboard < Administrate::BaseDashboard semester_start_date toggl_project lectures + work_items recordings created_at updated_at diff --git a/app/dashboards/work_item_dashboard.rb b/app/dashboards/work_item_dashboard.rb new file mode 100644 index 0000000..263dc16 --- /dev/null +++ b/app/dashboards/work_item_dashboard.rb @@ -0,0 +1,72 @@ +require "administrate/base_dashboard" + +class WorkItemDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + id: Field::Number, + course: Field::BelongsTo, + due_date: Field::DateTime, + title: Field::String, + tracked_time_entries: Field::HasMany, + created_at: Field::DateTime, + updated_at: Field::DateTime, + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = %i[ + id + course + due_date + title + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = %i[ + id + course + due_date + title + tracked_time_entries + created_at + updated_at + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = %i[ + course + due_date + title + tracked_time_entries + ].freeze + + # COLLECTION_FILTERS + # a hash that defines filters that can be used while searching via the search + # field of the dashboard. + # + # For example to add an option to search for open resources by typing "open:" + # in the search field: + # + # COLLECTION_FILTERS = { + # open: ->(resources) { resources.where(open: true) } + # }.freeze + COLLECTION_FILTERS = {}.freeze + + # Overwrite this method to customize how work items are displayed + # across all pages of the admin dashboard. + # + # def display_resource(work_item) + # "WorkItem ##{work_item.id}" + # end +end diff --git a/app/models/course.rb b/app/models/course.rb index 0faf14d..569ee66 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -1,8 +1,9 @@ class Course < ApplicationRecord has_many :lectures, dependent: :destroy + has_many :work_items, dependent: :destroy - # A course has a standalone connection to its recordings. To be shown they must be associated with a lecture but we - # track those not associated with a lecture to avoid duplication. + # A course has a standalone connection to its recordings. To be displayed they must be associated with a lecture but + # we them independently to avoid re-importing lectures. has_many :recordings, dependent: :destroy def import_from_calendar! diff --git a/app/models/lecture.rb b/app/models/lecture.rb index 92e6a9a..b025126 100644 --- a/app/models/lecture.rb +++ b/app/models/lecture.rb @@ -2,7 +2,7 @@ class Lecture < ApplicationRecord belongs_to :course has_one :recording, dependent: :nullify - has_many :tracked_time_entries, dependent: :destroy + has_many :tracked_time_entries, dependent: :destroy, as: :subject enum :kind, [ :lecture, diff --git a/app/models/tracked_time_entry.rb b/app/models/tracked_time_entry.rb index 28d5dc6..da53706 100644 --- a/app/models/tracked_time_entry.rb +++ b/app/models/tracked_time_entry.rb @@ -1,5 +1,5 @@ class TrackedTimeEntry < ApplicationRecord - belongs_to :lecture + belongs_to :subject, polymorphic: true enum :kind, [ :concurrent, diff --git a/app/models/work_item.rb b/app/models/work_item.rb index 4a444ea..f9a26d3 100644 --- a/app/models/work_item.rb +++ b/app/models/work_item.rb @@ -1,3 +1,4 @@ class WorkItem < ApplicationRecord belongs_to :course + has_many :tracked_time_entries, dependent: :destroy, as: :subject end diff --git a/config/routes.rb b/config/routes.rb index 772ea2b..8df9001 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,7 @@ Rails.application.routes.draw do namespace :admin do resources :courses resources :lectures + resources :work_items resources :tracked_time_entries resources :recordings diff --git a/db/migrate/20231007144716_make_tracked_time_entry_polymorphic.rb b/db/migrate/20231007144716_make_tracked_time_entry_polymorphic.rb new file mode 100644 index 0000000..f9e6e85 --- /dev/null +++ b/db/migrate/20231007144716_make_tracked_time_entry_polymorphic.rb @@ -0,0 +1,19 @@ +class MakeTrackedTimeEntryPolymorphic < ActiveRecord::Migration[7.1] + def change + add_reference :tracked_time_entries, :subject, polymorphic: true + + reversible do |dir| + dir.up do + TrackedTimeEntry.all.each do |entry| + entry.update!(subject: Lecture.find(entry.lecture_id)) + end + end + + dir.down do + TrackedTimeEntry.all.each do |entry| + entry.update!(lecture_id: entry.subject_id) + end + end + end + end +end diff --git a/db/migrate/20231007145018_remove_lecture_association.rb b/db/migrate/20231007145018_remove_lecture_association.rb new file mode 100644 index 0000000..ec92eb2 --- /dev/null +++ b/db/migrate/20231007145018_remove_lecture_association.rb @@ -0,0 +1,7 @@ +class RemoveLectureAssociation < ActiveRecord::Migration[7.1] + def change + remove_reference :tracked_time_entries, :lecture, null: false, foreign_key: true + change_column_null :tracked_time_entries, :subject_id, false + change_column_null :tracked_time_entries, :subject_type, false + end +end diff --git a/db/schema.rb b/db/schema.rb index 17846e7..b099bbc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_10_07_144031) do +ActiveRecord::Schema[7.1].define(version: 2023_10_07_145018) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -50,14 +50,15 @@ ActiveRecord::Schema[7.1].define(version: 2023_10_07_144031) do end create_table "tracked_time_entries", force: :cascade do |t| - t.bigint "lecture_id", null: false t.integer "kind" t.jsonb "toggl_data" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.bigint "associated_toggl_entry_id", null: false + t.string "subject_type", null: false + t.bigint "subject_id", null: false t.index ["associated_toggl_entry_id"], name: "index_tracked_time_entries_on_associated_toggl_entry_id", unique: true - t.index ["lecture_id"], name: "index_tracked_time_entries_on_lecture_id" + t.index ["subject_type", "subject_id"], name: "index_tracked_time_entries_on_subject" end create_table "work_items", force: :cascade do |t| @@ -70,6 +71,5 @@ ActiveRecord::Schema[7.1].define(version: 2023_10_07_144031) do end add_foreign_key "recordings", "courses" - add_foreign_key "tracked_time_entries", "lectures" add_foreign_key "work_items", "courses" end