Add archived_at to LearningOutcome and LearningOutcomeGroup

closes OUT-6014
flag=none

Test Plan:
- Open a rails console
- Run the migration:
  - docker-compose run --rm web bundle exec rake db:migrate
- Run pp LearningOutcome and observe there is a column named
  archived_at with type datetime
- Run pp LearningOutcome.first and observe that archived_at is
  nil by default
- Run pp LearningOutcomeGroup and observe there is a column
  named archived_at with type datetime
- Run pp LearningOutcomeGroup.first and observe that archived_at
  is nil by default

Change-Id: Ib8f2bcd0231b5ce6634b22eb2a6ba73000404d0d
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/334062
Reviewed-by: Dave Wenzlick <david.wenzlick@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
QA-Review: Dave Wenzlick <david.wenzlick@instructure.com>
Migration-Review: Cody Cutrer <cody@instructure.com>
Product-Review: Kyle Rosenbaum <krosenbaum@instructure.com>
This commit is contained in:
Angela Gomba 2023-12-06 14:15:19 -05:00 committed by Kyle Rosenbaum
parent d5e6c6f2fb
commit 7713b76ac6
5 changed files with 191 additions and 0 deletions

View File

@ -281,6 +281,7 @@ class LearningOutcome < ActiveRecord::Base
workflow do
state :active
state :archived
state :retired
state :deleted
end
@ -375,6 +376,28 @@ class LearningOutcome < ActiveRecord::Base
save!
end
def archive!
# Only active outcomes can be archived
if workflow_state == "active"
self.workflow_state = "archived"
self.archived_at = Time.now.utc
save!
elsif workflow_state == "deleted"
raise ActiveRecord::RecordNotSaved, "Cannot archive a deleted LearningOutcome"
end
end
def unarchive!
# Only archived outcomes can be unarchived
if workflow_state == "archived"
self.workflow_state = "active"
self.archived_at = nil
save!
elsif workflow_state == "deleted"
raise ActiveRecord::RecordNotSaved, "Cannot unarchive a deleted LearningOutcome"
end
end
def assessed?(course = nil)
if course
learning_outcome_results.active.where(context_id: course, context_type: "Course").exists?

View File

@ -50,6 +50,7 @@ class LearningOutcomeGroup < ActiveRecord::Base
workflow do
state :active
state :archived
state :deleted
end
@ -256,6 +257,28 @@ class LearningOutcomeGroup < ActiveRecord::Base
end
end
def archive!
# Only active groups can be archived
if workflow_state == "active"
self.workflow_state = "archived"
self.archived_at = Time.now.utc
save!
elsif workflow_state == "deleted"
raise ActiveRecord::RecordNotSaved, "Cannot archive a deleted LearningOutcomeGroup"
end
end
def unarchive!
# Only archived groups can be unarchived
if workflow_state == "archived"
self.workflow_state = "active"
self.archived_at = nil
save!
elsif workflow_state == "deleted"
raise ActiveRecord::RecordNotSaved, "Cannot unarchive a deleted LearningOutcomeGroup"
end
end
scope :active, -> { where("learning_outcome_groups.workflow_state<>'deleted'") }
scope :active_first, -> { order(Arel.sql("CASE WHEN workflow_state = 'active' THEN 0 ELSE 1 END")) }

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
#
# Copyright (C) 2023 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddArchivedAtToLearningOutcome < ActiveRecord::Migration[7.0]
tag :predeploy
def change
add_column :learning_outcomes, :archived_at, :datetime, default: nil, null: true
add_column :learning_outcome_groups, :archived_at, :datetime, default: nil, null: true
end
end

View File

@ -341,6 +341,71 @@ describe LearningOutcomeGroup do
end
end
describe "#archive" do
it "sets the workflow_state to archived and sets archived_at" do
group = @course.learning_outcome_groups.create!(title: "group")
group.archive!
expect(group.workflow_state).to eq("archived")
expect(group.archived_at).not_to be_nil
end
it "won't update an already archived group" do
group = @course.learning_outcome_groups.create!(title: "group")
group.archive!
archived_at = group.archived_at
expect(group.workflow_state).to eq("archived")
expect(group.archived_at).not_to be_nil
group.archive!
expect(group.workflow_state).to eq("archived")
expect(group.archived_at).to eq(archived_at)
end
it "raises an ActiveRecord::RecordNotSaved error if we try to archive a deleted group" do
group = @course.learning_outcome_groups.create!(title: "group")
group.destroy!
expect(group.workflow_state).to eq("deleted")
expect { group.archive! }.to raise_error(
ActiveRecord::RecordNotSaved,
"Cannot archive a deleted LearningOutcomeGroup"
)
expect(group.workflow_state).to eq("deleted")
expect(group.archived_at).to be_nil
end
end
describe "#unarchive" do
it "sets the workflow_state to active and sets archived_at to nil" do
group = @course.learning_outcome_groups.create!(title: "group")
group.archive!
expect(group.workflow_state).to eq("archived")
expect(group.archived_at).not_to be_nil
group.unarchive!
expect(group.workflow_state).to eq("active")
expect(group.archived_at).to be_nil
end
it "won't update an active group" do
group = @course.learning_outcome_groups.create!(title: "group")
expect(group.workflow_state).to eq("active")
expect(group.archived_at).to be_nil
group.unarchive!
expect(group.workflow_state).to eq("active")
expect(group.archived_at).to be_nil
end
it "raises an ActiveRecord::RecordNotSaved error if we try to unarchive a deleted group" do
group = @course.learning_outcome_groups.create!(title: "group")
group.destroy!
expect(group.workflow_state).to eq("deleted")
expect { group.unarchive! }.to raise_error(
ActiveRecord::RecordNotSaved,
"Cannot unarchive a deleted LearningOutcomeGroup"
)
expect(group.workflow_state).to eq("deleted")
expect(group.archived_at).to be_nil
end
end
context "root account resolution" do
it "sets root_account_id using Account context" do
group = LearningOutcomeGroup.create!(title: "group", context: Account.default)

View File

@ -736,6 +736,59 @@ describe LearningOutcome do
"Does Not Meet Expectations"
])
end
it "archive! updates the workflow_state to archived and sets archived_at" do
@outcome.archive!
expect(@outcome.workflow_state).to eq("archived")
expect(@outcome.archived_at).not_to be_nil
end
it "archive! raises an ActiveRecord::RecordNotSaved error when we try to archive a deleted outcome" do
@outcome.destroy!
expect(@outcome.workflow_state).to eq("deleted")
expect { @outcome.archive! }.to raise_error(
ActiveRecord::RecordNotSaved,
"Cannot archive a deleted LearningOutcome"
)
expect(@outcome.workflow_state).to eq("deleted")
expect(@outcome.archived_at).to be_nil
end
it "archive! will not update an already archived outcome" do
@outcome.archive!
archived_at = @outcome.archived_at
expect(@outcome.workflow_state).to eq("archived")
expect(@outcome.archived_at).not_to be_nil
@outcome.archive!
expect(@outcome.workflow_state).to eq("archived")
expect(@outcome.archived_at).to eq(archived_at)
end
it "unarchive! updates the workflow_state to active and sets archived_at to nil" do
@outcome.archive!
expect(@outcome.workflow_state).to eq("archived")
expect(@outcome.archived_at).not_to be_nil
@outcome.unarchive!
expect(@outcome.workflow_state).to eq("active")
expect(@outcome.archived_at).to be_nil
end
it "unarchive! raises an ActiveRecord::RecordNotSaved error when we try to unarchive a deleted outcome" do
@outcome.destroy!
expect(@outcome.workflow_state).to eq("deleted")
expect { @outcome.unarchive! }.to raise_error(
ActiveRecord::RecordNotSaved,
"Cannot unarchive a deleted LearningOutcome"
)
expect(@outcome.workflow_state).to eq("deleted")
expect(@outcome.archived_at).to be_nil
end
it "unarchive! will not update an active outcome" do
@outcome.unarchive!
expect(@outcome.workflow_state).to eq("active")
expect(@outcome.archived_at).to be_nil
end
end
context "Don't create outcomes with illegal values" do