this is already true, just make sure it stays that way
test plan: n/a
Change-Id: Ia7340e8de57b18da509d51580b5827c7069af80a
Reviewed-on: https://gerrit.instructure.com/7166
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: JT Olds <jt@instructure.com>
Test plan:
- send a message to multiple people you have not previously had a
conversation with
- observe that the message was successfully sent (but nothing is added
to the conversation list)
Change-Id: I3b3b57a58faa10bfeb3067112810226434ffd532
Reviewed-on: https://gerrit.instructure.com/8001
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Ryan Florence <ryanf@instructure.com>
as a student, when you go to /courses/x/assignments
it was showing the course name under each assignment,
which was unneeded since it is inferred since you
are "in" that course.
fixes: #6792
test plan:
go to /courses/x/assignments as a student
verify that it looks like this:
http://cl.ly/2m0j450E2C1i3G0A271J
not this:
http://cl.ly/11011P2O1R1z433a2F3F
Change-Id: I5c5944b2d8abd948fbbf05bb38ff8428f26c195e
Reviewed-on: https://gerrit.instructure.com/7888
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Cameron Matheson <cameron@instructure.com>
It turns out that the defaults for daily/weekly policies actually do work -
the issue before was that they won't work for a user whose first communication
channel is retired. This fixes that problem by using the first active email
channel.
Another problem was that we would only build placeholder policies if the user
had NO notification policies at all. However, that rarely happens - when a
user receives a notification and they don't have a policy for it, that policy
gets built. In this case, when the user went to their preferences page, they
would see all the notification categories they didn't have policies for as
"never". This creates placeholder policies for all the notification categories
the user doesn't have one for.
It also makes sure the correct defaults are displayed on the preferences
screen.
test plan:
* Create a new user A, and enroll them in a course.
* As another user B, create a calendar event in that course. A calendar event
is by default a "never" item.
* As user A, go to your communication prefs and notice that all the default
preferences are still appearing. In the console you can verify that the
policy was created for you too:
> User.find(<A.id>).notification_policies
* Now, delete that policy from the database.
* As user A, add a new comm channel and delete the old one.
* As user B, create another calendar event
* Verify in the console that user A got a notification policy created for the
second communication channel.
* As user B, create a discussion topic.
* As user A, add an entry to that topic.
* As user B, comment on that topic as well.
Discussion entries are by default 'daily', so user A should have a
DelayedMessage. Verify in console:
> DelayedMessage.last
Change-Id: I3f7827d2aa83d5b72ab5f8f96aa92ef96652f115
Reviewed-on: https://gerrit.instructure.com/8062
Reviewed-by: JT Olds <jt@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
affects: pseudonyms_controller, api
test plan:
* as an authorized user, make request and verify that
requested user's pseudonyms for given account are
returned;
* make same request for a user with multiple pseudonyms
in a single account and verify that all are returned;
* make request as an unauthorized user and verify that
401 is returned.
Change-Id: I0633e79108c0c6e626cf52f5d39d91a9e67edbb6
Reviewed-on: https://gerrit.instructure.com/8025
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
When a user had not configured any notification policies, on the communication
preferences page, they would see everything as "immediate". That would lead
people to believe that those are the defaults.
Note that for now, only "immediate" notifications actually will be sent by
default. All others are assumed to be never, so that should be reflected in
the UI.
test plan:
* Create a new user
* Go to the Profile -> Communication Preferences page
* Notice that the pre-selected preferences are immediate for immediate
notifications, and never for everything else.
Change-Id: Ibbd908a5b6f38d144fd4f752bc57258e96c4dc78
Reviewed-on: https://gerrit.instructure.com/8050
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
we are seeing an issue with some requests where the account association
info in a course loaded with these enrollments is getting a proc stored
on it, so that it can't be Marshal'd and the caching throws an error.
We're still investigating the cause, but this fixes up the errors.
fixes#6867
Change-Id: Ibc24e7583d7f3a4f1f4362680f6a2c080a53ba53
Reviewed-on: https://gerrit.instructure.com/8051
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Wily <zach@instructure.com>
the functionality where, if you chose a different
section to show, it would show only users from that
section in the gradebook2 broke. this fixes it.
refs: #6844, fixes: #6849
test plan:
* go to /courses/x/gradebook2 for something with 2
sections
* choose a different section to show in the top
left
* verify that it filtered the students it is
showing to just those in that section
Change-Id: I8051c6778e6959c9f2767edaa9e89ae453727bdb
Reviewed-on: https://gerrit.instructure.com/7990
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Ryan Florence <ryanf@instructure.com>
test plan:
* in gradebook1, have the total grade for a row
have a decimal (like 33.3%)
* load gradebook2 and verify that it is a decimal
rounded to 1 place too (so 33.3% and not 33% or
33.33%)
Change-Id: I5f5f2de5b3fe953690b678aa956279c471c84d9d
Reviewed-on: https://gerrit.instructure.com/8036
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jake Sorce <jake@instructure.com>
Tested-by: Jake Sorce <jake@instructure.com>
affects: course creation on /accounts/:id
test plan:
* navigate to courses page for account;
* click 'Add a New Course' button;
* fill out new course form and click 'Add Course';
* verify that (1) modal closes, and (2) flash message
appears.
Change-Id: Idce434d288dd8b81a29edfd1b5144c0dcedfc7ea
Reviewed-on: https://gerrit.instructure.com/8032
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Ryan Florence <ryanf@instructure.com>
affects: pseudonyms_controller/api
test plan:
* as authorized user, post request and verify
that new pseudonym is created;
* as authorized user, post duplicate pseudonym
and verify that 400 is returned.
* as unauthorized user, post request and verify
that 401 is returned.
Change-Id: I4b2ad73dd68f43a935e37d3fe9f02f4d0269b72a
Reviewed-on: https://gerrit.instructure.com/8024
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Pendleton <zachp@instructure.com>
for a user with :read_as_admin but not :read permissions to a course
(odd, but currently happens for designer enrollments in an unpublished
course) the user is redirected from the course "Home" to the course
settings. however, the settings page turns around and makes an xhr
request to /courses/X again for some data. don't redirect that call or
you get an infinite loop.
also, this change cuts out the unnecessary remainder of
CoursesController#show for xhr requests; before we still did all that
work and then just ignored it.
Change-Id: I4b6d39c8bf4e12173a4aa168903d2148f89c7a3d
test-plan:
- create an unpublished course
- enroll a designer in that course (currently only possible via sis or
console)
- while logged in/masquerading as the designed, visit the course's
settings page
- confirm there is *not* a runaway xhr recursion
Reviewed-on: https://gerrit.instructure.com/8039
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Ryan Florence <ryanf@instructure.com>
fixes#6636
there seems to be a race condition where this redirect will sometimes
happen before the LDB notices the params telling it to go into
fullscreen lockdown mode. so we just avoid the redirect, which isn't
necessary since we didn't make a post request anyway.
test plan: in the LDB, go to a quiz that requires the LDB, ensure that
it goes fullscreen.
Change-Id: Idf94ae56ce5e695f51fe75da9d98611f60164666
Reviewed-on: https://gerrit.instructure.com/7564
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Pendleton <zachp@instructure.com>
We were just finding the first CommunicationChannel, which might even be
retired. This will make sure we get an active one and it's an email one.
test plan:
* (perform all these steps on a new account, and don't go into the
notification preferences screen)
* Create a new account with an email address X
* Add a new, secondary email address Y to your account
* Delete the email address X
* As another user, start a conversation with the user created above.
* Verify that you received the email notification at email address Y and not
X.
Change-Id: I7b16001918c5f39b5929e0f520069838a10bcf66
Reviewed-on: https://gerrit.instructure.com/8035
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Zach Wily <zach@instructure.com>
test plan:
* create a course, assignment, and submissions
* add a ta limited to a section
* download the submissions zip for an assignment
* it should only include submissions for students
in the section the ta is a part of
Change-Id: I68e580301ad284186ec25742bc5869ae031baa69
Reviewed-on: https://gerrit.instructure.com/8015
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
find_by_* does a data type check, so doesn't work with non-integer ids
test plan:
* log in as site admin
* access an account on a different shard
* masquerade as someone
* unmasquerade
Change-Id: I672d96560d1598801a51f3e5252b32bcbd365fc7
Reviewed-on: https://gerrit.instructure.com/7817
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
Somehow the after_attachment_saved callback in Attachment was getting called
on non-scribdable attachments with a workflow_state of 'processing'. We were
previously only skipping non-scribdable attachments if the workflow_state was
'pending_upload'. Now we will skip scribd processing for any non-scribdable
attachment, no matter it's state.
Also changed UnzipAttachment to only create a scribd job if there are any
scribdable attachments.
test plan:
* Since we're not sure how the attachments originally got in the state
described above, it's hard to describe repro steps. However, if you upload
some images, they should not get scribd jobs created for them.
Change-Id: I7381af3f0928c2decf4f224834780cc90fbbc103
Reviewed-on: https://gerrit.instructure.com/8028
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
if the site admin account has a global stylesheet or
javascript include, include those files in all other
accounts.
affects: application layout
test plan:
* run specs
Change-Id: I87031fef39eac7ec77e318257c26b5378819a669
Reviewed-on: https://gerrit.instructure.com/7963
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Pendleton <zachp@instructure.com>
When a user didn't have any notification policies, default values are used to
decide when to send them notifications to their communication channel. Since
Conversation Message didn't have a default set, it used 'daily'.
It looks like there's another issue where anything except for 'immediately'
would not get sent at all. (It wouldn't get batched up for the digest email).
See communication_channel.rb:216. That should probably be fixed separately.
This fix will just address the common use case where people expect to get
emails about Conversations without having to do anything extra.
test plan:
* create a new user, verify the email address, etc, but do not save any
notification preferences.
* as another user, start a conversation with the new user.
* verify that the new user got a Message or email about the conversation
message.
Change-Id: Ib198ba528a80a8b1576d236bfbd91b3cc72980db
Reviewed-on: https://gerrit.instructure.com/7991
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
test plan:
* run the migration
* redo the migration
* do a batch mode sis import
Change-Id: I0204256f3825ffe0b4d252bbb83a0604d7a58942
Reviewed-on: https://gerrit.instructure.com/7904
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Reviewed-by: Ben Chobot <bench@instructure.com>
semanticDateRange returns html, so the handlebars template needs to use {{{}}}
so the html isn't escaped.
test plan:
* Create an appointment group as a teacher
* Reserve one of the slots as a student
* Verify that the green box in the appointment list shows the time chosen
correctly without any of the html.
Change-Id: If4f4732b5dea9e169c7c88701b3c7c10faf69720
Reviewed-on: https://gerrit.instructure.com/7977
Reviewed-by: Ryan Shaw <ryan@instructure.com>
Tested-by: Zach Wily <zach@instructure.com>
when a user is enrolled in one or more courses, we now give the query
planner a more efficient way of finding rows in the course subselect in
User#messageable_users. the new condition is redundant (and less
restrictive than the course_sql ones), but it ensures the planner will
use the index on enrollments.course_id and then filter on the other
fields.
the performance gains are most relevant in mysql when there are multiple
conditions in course_sql (from ~4s down to <0.01s)
test plan:
ensure the various course_sql paths work (e.g. section visibility).
existing specs should already cover these different flows
Change-Id: I11d41daa1134146abd2b099be24e873d47ef567b
Reviewed-on: https://gerrit.instructure.com/7450
Reviewed-by: Jon Jensen <jon@instructure.com>
Tested-by: Jacob Fugal <jacob@instructure.com>
display stream items for new and updated appointment groups, as well as
when someone signs up another user (e.g. group signup)
removed unused message templates, fixed date_string range to just show a
single date if date parts are the same
test plan:
1. publish an appointment group and ensure all pertinent students get a
dashboard notification
2. add times to an appointment group and ensure all pertinent students
get a dashboard notification
3. sign up a group for a timeslot and ensure all other group members
get a dashboard notification
Change-Id: Id0dec52c0376fb6e14b0f26bb60e4695b25f7591
Reviewed-on: https://gerrit.instructure.com/7938
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Wily <zach@instructure.com>
I kind of think the real bug is being able to delete the last blank row,
but maybe we want people to be able to delete that
test plan:
- fill out a time range
- fill out a second time range
- delete the 3rd (blank) row
- click split
Change-Id: I8339bca9f84bf913b41a65446ef738d86b366cf6
Reviewed-on: https://gerrit.instructure.com/7945
Reviewed-by: Zach Wily <zach@instructure.com>
Tested-by: Zach Wily <zach@instructure.com>
Test Plan
* Import any ol' non-canvas zip file so the import will fail
* Follow the now-friendlier link in the email that was sent to you
* Expand the errors/warnings and see if there is a link to download your file and (if you are site admin) there is a link to the error report.
refs #6607
Change-Id: Ia49070d94ccb26c9c20833a36f3ac7caa742806b
Reviewed-on: https://gerrit.instructure.com/7870
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Cody Cutrer <cody@instructure.com>
AccountAuthorizationConfigs now require the entity_id to
be set for SAML configs. It will be set to the domain of
the account. For existing SAML configs, the entity_id will
be set to what is in the SAML config file if there is one.
This commit also allows SAML meta data to show up for all
domains even if they're not configured for SAML. This helps
admins set up initial SAML configurations.
Test Plan:
* Create a saml configuration for an account
* Look at the metadata, the entity_id should be set to the domain/saml2 and not what is in the saml config file
* Try loading the meta data for an account with no SAML config. It should load and have the proper entity_id
closes#6713
Change-Id: Ia98543c996285d9b1febd788c3f3ec072b672b12
Reviewed-on: https://gerrit.instructure.com/7967
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
when updating a quiz, give user an option to notify or not
notify users of the change.
affects: quizzes_controller, quiz model
test plan:
* create quiz;
* modify quiz with notify checkbox checked, verify
that message is created;
* modify quiz with notify checkbox unchecked, verify
that message is not created;
Change-Id: I847741e36b601523eb8e46c36f4e9b70a7f119ec
Reviewed-on: https://gerrit.instructure.com/7939
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
test plan: run the migration
Change-Id: I75184edd64ddee384de485c443d4c7eee45cc26f
Reviewed-on: https://gerrit.instructure.com/7895
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
We've decided to approach this another way. See redmine #2635.
This reverts commit d9d5715b2b.
Change-Id: Ib497319994294a4fc0fe0da47acbde692e00fd91
Reviewed-on: https://gerrit.instructure.com/7961
Tested-by: Zach Wily <zach@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
This was caching the TA view for teachers, and vice-versa, causing confusion.
test plan:
* With caching enabled and a clean cache:
* Visit an unpublished course as a TA. Notice that the wizard does not
include the "publish" option, as that default is not normally granted to
TAs.
* Visit that same course as a teacher. Notice that the publish option is
there.
Change-Id: I5859c940e1d8fe7be9c4aa1b4f75bcc11c6b3d22
Reviewed-on: https://gerrit.instructure.com/7947
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Zach Wily <zach@instructure.com>
test plan:
* Go to the Scheduler
* Create an appt group
* Verify that the dash between the from and to times isn't all squished up
and to the right.
Change-Id: I441c4fe0aca48e0b6dbfa7e22c64e6038706bbe6
Reviewed-on: https://gerrit.instructure.com/7936
Reviewed-by: Cameron Matheson <cameron@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
* allow linking to the scheduler/appt groups
* limit select boxes' length in an appt group dialog
* don't let user delete all time block rows
* fix calendar popovers to not pop-up outside of body
* preserve duration after splitting time blocks
* change verbiage to "you can sign up"
* reword "limit each slot to [x] users"
* better 'blank screen' experience
* fix blue counter badges when empty
Change-Id: I1a4bc3b87a9b1ccccea5a846b28fea521e245214
Reviewed-on: https://gerrit.instructure.com/7922
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Wily <zach@instructure.com>
api available at /courses/:course_id/members, and returns
a paginated array ordered by enrollment type and user
sortable_name.
affected areas: enrollments api
test plan:
* make GET request as authenticated, authorized user and
verify that proper array of all enrollment types is
returned;
* make GET requests as unauthenticated and as unauthorized
users and verify that 401 Unauthorized is returned.
* pass page and per_page params and ensure that results are
properly paginated.
Change-Id: I2339e9939c9dca6f4081a092737935aadac0ecd8
Reviewed-on: https://gerrit.instructure.com/7827
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
The api uses absolute uris, not relative paths, for all urls and other
links.
Change-Id: Id36c10a49ff606c57b3fd5405166fe9bcabf33dd
Reviewed-on: https://gerrit.instructure.com/7917
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
allow points in rubric criteria and ratings to have decimal values. in working
with brian, we're operating under the following assumptions:
- round to 2 decimal places
- splitting always gives you a integer by default (you can change it yourself after)
- if there's not room to split with an integer, repeat the low value
test plan
- create a new rubric
- change a criterial value to something with a decimal point
- try setting specific ratings with decimals
- try to split between a large space (ie 10.5 and 0), should be 5
- try to split between a small space (ie 0.5 and 0), should be 0
closes#5355
Change-Id: I17e26fe18dda0847fa59dd40976e4d6f38851287
Reviewed-on: https://gerrit.instructure.com/7882
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Brian Palmer <brianp@instructure.com>
Reviewed-by: Ryan Florence <ryanf@instructure.com>
test plan: run the migration, then the specs
Change-Id: Idec29c0a9cf43a581e0ca9eae00248599270745c
Reviewed-on: https://gerrit.instructure.com/7896
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
fixes#4578
test plan:
* disable editing username on the account
* add multiple e-mails in /profile
* confirm them
* you should be able to click the stars without error
Change-Id: I38974282309f3e762529351db1f3c56e5eba02cc
Reviewed-on: https://gerrit.instructure.com/7926
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
fixes#6786, #6789
the uniqueness check was failing if there was a matching retired cc,
even though this cc is the only active/unconfirmed one. so
instead write a custom validator that only searches for
active/unconfirmed ccs.
test plan:
* manually add the same email address to a user multiple times,
in a retired state (in script/console, or directly in the db)
* try to add that email address to the user in the UI
* it should work
Change-Id: I41bdff34ffcd273d82d1d251e45c1ce48b61d51c
Reviewed-on: https://gerrit.instructure.com/7889
Tested-by: Cody Cutrer <cody@instructure.com>
Reviewed-by: Bracken Mosbacker <bracken@instructure.com>
test-plan:
- create a course A
- create a graded quiz in course A
- create a course B
- go to import content from course A into course B
- make sure "Copy Everything from A", "Quizzes for A", and the
specific quiz from A are all unchecked.
- check the assignment for the specific quiz from A.
- click "Import Course Content"
- the quiz should be imported from A to B without error
Change-Id: I88511511f6c8494ec04d551af3f15a2b32e374f1
Reviewed-on: https://gerrit.instructure.com/7914
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
added a domain-account-level setting controlling whether or not the
scheduler is enabled. when it is turned on,
1. /calendar requests redirect to /calendar2 by default
2. both the new and old calendar pages include a link to the other
calendar (sets a user preference so that it redirects correctly in
the future)
Change-Id: I1817c7f8e9075282ab1988088f5c0ef8d63325f6
Reviewed-on: https://gerrit.instructure.com/7840
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Wily <zach@instructure.com>
fixes#6048
somehow the submission's submitted_at.usec was
less than the quiz submissions finished_at.usec
this caused the speed grader to display the wrong
quiz version for affected quizzes
changed the logic around to find the latest
version using the version number, instead of dates
Change-Id: I78d6045f07ee76fa5e2b5abeeb42eed539f5da7c
Reviewed-on: https://gerrit.instructure.com/7898
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jon Jensen <jon@instructure.com>
put styling for active tab in <head> because
setting an .active class in the partial wont work
since it is cached.
And it can't be done in css with all combinations of:
body.whatever #section-tabs .whatever,
body.otherthing #section-tabs .otherthing {…}
because by adding a BLTI tab, you would not know
the class until runtime.
test plan:
in an environment with caching turned on,
verify that it looks like this:
http://cl.ly/2T0N0f0h1B0S1K070U0D
not this:
http://cl.ly/0e0T430J1Y12211C2r29fixes: #6791
Change-Id: I10d405f7fdf8d8edce8cec3e74ad62ec977a4676
Reviewed-on: https://gerrit.instructure.com/7887
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Zach Wily <zach@instructure.com>
When a course name shows up in in the new message form of a conversation, make
it link to the course page. Closes#6468.
Test plan:
- Go to the inbox
- Click on a conversation with course context
- Check that the course name next to the recipient, above the new message form
is a link.
- Check that the course names in the left panel conversation list are not
links.
Change-Id: Ib075e1339ef0f99f856c8b7fe09cc111b55dff2f
Reviewed-on: https://gerrit.instructure.com/7822
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jon Jensen <jon@instructure.com>
affected areas: conversations, identity header view.
test plan:
* create two users, A and B;
* enable caching in your test environment;
* send message to user A from user B;
* as user A, read message;
* refresh conversations page and verify that
identity header no longer has "1" next to
"Inbox."
Change-Id: I7a2c8845619d122b10b6d27f9585ce036de25113
Reviewed-on: https://gerrit.instructure.com/7865
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
this hasn't been released yet, and doesn't actually mean anything
test plan: run the specs
Change-Id: I391623e63fa7710717c26f33dac9c5ae220577e3
Reviewed-on: https://gerrit.instructure.com/7902
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Cody Cutrer <cody@instructure.com>