refs CNVS-5856, CNVS-6906, CNVS-6475
Test plan:
This commit lets you mark columns as teacher_notes columns. The UI
only supports one teacher_notes column, but this isn't enforced by
the API. Create a teacher_notes column using the API.
Change-Id: I1c15082e95ac08b092148f32f3c6906ec2dcef11
Reviewed-on: https://gerrit.instructure.com/28097
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Simon Williams <simon@instructure.com>
QA-Review: Caleb Guanzon <cguanzon@instructure.com>
Product-Review: Cameron Matheson <cameron@instructure.com>
fixes CNVS-10147
test plan
- set sis id, section name to longer than 255 chars
- should throw rails error
- should not throw database error
Change-Id: I05ebdf3ae89ace4f737ae6c124f015efceafec1d
Reviewed-on: https://gerrit.instructure.com/27835
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Rob Orton <rob@instructure.com>
Change-Id: Id2205c4c375c569e88857bb3f24a7f11a9d184af
Reviewed-on: https://gerrit.instructure.com/27960
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: James Williams <jamesw@instructure.com>
Product-Review: James Williams <jamesw@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
An integration_id can be used in a way similar to sis_source_id in
that it documents a 3rd party identifier for a particular object. The
reason we use an integration_id instead of a sis_source_id for some
SIS integrations is that there is BOTH a sis_source_id and another
id that is used (as in the case of SIF) to ferry information between
systems.
Models that have an integration_id now include:
- pseudonyms
- course_sections
- courses
- enrollment_terms
- accounts
Test Plan:
- make sure the above tables have an integration_id column after "rake db:migrate"
Fixes SIS-107
Change-Id: I80a03d7384fc6ff243436bdf18798ece5059acb7
Reviewed-on: https://gerrit.instructure.com/27593
Reviewed-by: Cody Cutrer <cody@instructure.com>
Reviewed-by: Ken Romney <kromney@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Duane Johnson <duane@instructure.com>
QA-Review: Duane Johnson <duane@instructure.com>
closes CNVS-6906, CNVS-6475
Test plan:
Use the new custom gradebook column apis to create/edit/delete custom
gradebook columns, and set data for users in a course on those
columns.
only teachers/TAs should have permission to use these apis.
Change-Id: I658b8dc02d6104559c98a6b7e1be5c72e775d664
Reviewed-on: https://gerrit.instructure.com/27615
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Simon Williams <simon@instructure.com>
QA-Review: Simon Williams <simon@instructure.com>
Product-Review: Cameron Matheson <cameron@instructure.com>
closes CNVS-5797
test plan:
* GET /api/v1/users/self/communication_channels/:id/notification_preferences
should return your preferences
* GET .../notification_preferences/<one of the named notifications returned above>
should return a single preference
* PUT .../notification_preferences/<notification>?notification_preferences[frequency]=never
should update it (will return it, and confirm by getting it again
* PUT .../notification_preferences?notification_preferences[<notification>][frequency]=never&
notification_preferences[<another notification>][frequency]=never
should update two preferences at once
* other allowed frequencies are immediately, daily, and weekly
* repeat replacing the communication channel's id by email/<email address>
* repeat by using an actual user id instead of self. users should
not be able to view or update each other's preferences. admins
should only be able to view, not update (the update routes only exist for "self",
so you'll get a 404 instead of a 401 for them)
* regression test notification preferences UI
Change-Id: I107f68a44cb68ee1675ad50ff7123e26d7765450
Reviewed-on: https://gerrit.instructure.com/26311
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
Change-Id: Ib2147e2a5c388ba56c1e558b414da9b7ec4c9cd2
Reviewed-on: https://gerrit.instructure.com/27614
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: James Williams <jamesw@instructure.com>
Product-Review: James Williams <jamesw@instructure.com>
fixes CNVS-9879
This is tricky to test, since ZachP already fixed the bug.
See https://gerrit.instructure.com/#/c/26059/ .
Consider manually breaking your own data:
UPDATE conversation_participants SET last_message_at = NOW() WHERE message_count = 0;
Change-Id: Id8eb4c23ff2968f7ab4ec6856629f76b82cb9515
Reviewed-on: https://gerrit.instructure.com/27121
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Steven Shepherd <sshepherd@instructure.com>
Product-Review: Braden Anderson <banderson@instructure.com>
Change-Id: I5d156b42300130d063cb7492b178b2be11cd32e3
Reviewed-on: https://gerrit.instructure.com/27133
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Brian Palmer <brianp@instructure.com>
QA-Review: Brian Palmer <brianp@instructure.com>
Product-Review: Brian Palmer <brianp@instructure.com>
refs CNVS-5180
test plan:
migrations should work on an install that had the old index, as well as on
new installs
Change-Id: Ia8e59a14104ba841eb9142293a9ea5162d2b279d
Reviewed-on: https://gerrit.instructure.com/26811
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Jon Jensen <jon@instructure.com>
Product-Review: Jon Jensen <jon@instructure.com>
fixes CNVS-9603
also, migration to move scribd_docs up to root attachments
test plan:
* BEFORE checking this out:
* configure and enable scribd
* upload the same (scribdable) file to two courses in the same
root account
* inspect the database, and confirm that both files have a
scribd_doc for them
* confirm both files render in the UI (you'll need to have
jobs running)
* upload another (scribdable) file to two courses
* directly set scribd_doc=NULL on the root_attachment of this
second pair; do *not* view it in the UI
* check out this change
* run migrations
* inspect the database, and confirm that only the root attachment
of for both pairs of previous files has a scribd_doc now
* in the UI, confirm that all 4 render correctly
* double check the DB, and ensure that only the two root attachments
have scribd_docs
* stop jobs
* upload *another* (scribdable) file to two courses
* start jobs; confirm that both copies render with scribd, and only
the root has a scribd_doc. also confirm that the last_inline_view
for the non-root one is still NULL (and that the last_inline_view
on the root is updated when you view the non-root one in the UI)
* repeat the last two stops, with jobs running the whole time this
time (i.e. make sure that the first copy of the new file renders
in scribd before uploading the second copy)
Change-Id: I3053e23a592e3a0c0713880f20fc543eb2c726d4
Reviewed-on: https://gerrit.instructure.com/26503
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
closes CNVS-9674
test plan
- migrations should not fail
Change-Id: I9acb8cb20b33bcdb2318fcaab894ac8f7c4c2c8f
Reviewed-on: https://gerrit.instructure.com/26658
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
Product-Review: Rob Orton <rob@instructure.com>
QA-Review: Rob Orton <rob@instructure.com>
fixes CNVS-5794
links to an access token to get the proper ARN
test plan:
* set up an SNS app in AWS
* configure your credentials in sns.yml
* set sns_arn on a developer key to be the ARN of the app in SNS
* using an access token created from that developer key,
you should be able to create a push channel
* you should see that channel in your profile (named after your developer
key)
Change-Id: I183241d02715252bf558c495d72d4995cea4232d
Reviewed-on: https://gerrit.instructure.com/25281
Reviewed-by: Cody Cutrer <cody@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
fixes: CNVS-348
This adds grade change auditing functionality. It uses cassandra and is built
after the authenication auditing. A new API endpoint was created to query these
logs. Permissions for this is a domain account. The logs can be quiried by
assignment, course, student, and grader.
Refer to: https://gollum.instructure.com/grade-auditor-implementation
Test Case:
Setup:
- Create a course with a student and an assignment.
1. Grade an assignment for a student.
2. The auditor should create a record in cassandra.
3. Query the endpoint should return the audit event.
- Query by Assignment
- Query by Course
- Query by Student
- Query by Grader
4. Ensure permissions are valid by querying with a non root account admin.
5. Permissions should be changable by site_admin under account permissions.
Change-Id: I0a1cf867d5d1b5bfbdeacc7eac81747f8732025a
Reviewed-on: https://gerrit.instructure.com/25961
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Nick Cloward <ncloward@instructure.com>
test plan:
- As a teacher, create a graded survey with an essay question.
- As a student, take the graded survey.
- As the teacher:
- You should not receive a notification that the submission needs
grading
- You should not see the survey in your todos list on the course
home page.
- When you view the quiz submission in speedgrader, you should see
the full points possible for that question in the input on
the question header box, instead of '--'.
fixes CNVS-1786
Change-Id: I658c0bc94d54be8449830412fd2da28884e98b4c
Reviewed-on: https://gerrit.instructure.com/25593
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Ahmad Amireh <ahmad@instructure.com>
QA-Review: Myller de Araujo <myller@instructure.com>
Reviewed-by: Derek DeVries <ddevries@instructure.com>
Product-Review: Stanley Stuart <stanley@instructure.com>
Teachers can now control when, and for how long, students get to see the
correct answers to their quiz submissions.
The patchset introduces two new columns to Quiz and a CSS rework of the
quiz options form. See linked references for more info.
Quiz#show_correct_answers should no longer be directly accessed, use
Quiz#show_correct_answers? instead.
== Test plan
CAs stands for Correct Answers.
- Create a quiz with 3 questions
- Take the quiz as a student, and:
- get 2/3 of the questions answered correctly
- submit it
Case A - Showing CAs the moment the submission goes in:
- Edit the quiz, and:
- Tick the 'Let Students See Their Score Points' checkbox
- Leave both date fields empty
- Save quiz
- Refresh student view
- You should see the CAs
Case B - Showing CAs after some date:
- Edit the quiz, and:
- Tick the 'Let Students See Their Score Points' checkbox
- Set the "Show Correct Answers At" to 3-days from now
- Refresh student view:
- You should not see the CAs
- Edit the quiz, and:
- Set the date to 3-days back
- Refresh student view:
- You should see the CAs
Case C - Hiding CAs after some date:
- Edit the quiz, and:
- Tick the 'Let Students See Their Score Points' checkbox
- Set the "Hide Correct Answers At" to 3-days from now
- Refresh student view:
- You should see the CAs
- You should see an alert that tells you the CAs will be hidden at
the date you chose earlier
- Edit the quiz, and:
- Set the date to 3-days-back
- Refresh student view:
- You should no longer see the CAs
- Alert should read that the answers stopped being visible as of the
date you chose earlier
Case D - Creating a time-frame for showing CAs:
- Edit the quiz, and:
- Tick the 'Let Students See Their Score Points' checkbox
- Set the "Show Correct Answers At" to yesterday
- Set the "Hide Correct Answers At" to 3-days from now
- Refresh student view:
- You should see the CAs
- You should see an alert that tells you the CAs will be visible
between yesterday and 3 days from now
- Edit the quiz, and:
- Set the "Show At" date to tomorrow
- Refresh student view:
- You should no longer see the CAs
- Alert should still tell you that the CAs will be visible starting
tomorrow until 3 days from now
Case E - Choosing a bad range
- Edit the quiz and:
- Tick the 'Let Students See Their Score Points' checkbox
- Set the "Show at" to tomorrow
- Set the "Hide at" to today, or tomorrow
- You should see an error-box
== Notes and really wild things
- http://docs.kodoware.com/canvas/cnvs-8103-take2
- http://docs.kodoware.com/canvas/cnvs-8103 (legacy changes)
refs CNVS-8103, CNVS-9386
Change-Id: Ib241ee5f143b87164105b7541aadac00f38f79ad
Reviewed-on: https://gerrit.instructure.com/25505
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Myller de Araujo <myller@instructure.com>
Reviewed-by: Derek DeVries <ddevries@instructure.com>
Product-Review: Derek DeVries <ddevries@instructure.com>
test plan:
- install the test_features plugin (since no real features exist yet)
- render and consult the feature flags documentation
- have a test environment with a root account,
sub-account, course in sub-account, and user
- Use the "list features" endpoint as a root account admin
(with no site admin privileges), on the root account context, and
confirm that hidden features do not show up
- Use the "list features" endpoint as a site admin user,
on the root account context, and confirm that hidden features
show up
- Use the "list features" endpoint on the site admin account
and confirm the hidden features show up
- Use the "set feature flag" endpoint on a hidden feature on site
admin and ensure the feature becomes visible in all root accounts
- Use the "set feature flag endpoint" on a hidden feature on a
single root account, and ensure the feature becomes visible to
that root account and not others
- Confirm that root_opt_in features appear "Off" by default
in root accounts, after being "Allowed" in code or site admin
- Confirm a feature flag that is set to "on" or "off" (vs. "allowed")
cannot be overridden in a lower context (and the API returns
locked=true for them)
- Confirm that setting locking_account_id requires admin rights
in the locking account
- Confirm that a feature flag with locking_account_id cannot be
changed without admin rights in the locking account (e.g.,
set a feature flag on a course, locked with the root account's id,
and make sure a teacher who is not an account admin can't change it)
- Confirm feature flags can be deleted with the "remove feature flag"
endpoint (and they are only deleted where they are defined, not
when called on an object that inherits a flag)
Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52
Reviewed-on: https://gerrit.instructure.com/25502
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Matt Fairbourn <mfairbourn@instructure.com>
Product-Review: Matt Goodwin <mattg@instructure.com>
Reviewed-by: Zach Pendleton <zachp@instructure.com>
fixes: CNVS-1601
Since submissions were not created for students who did not submit an
assignment the analytics were showing them as missing even if they were not due
yet. Regardless what the score was. The fix changed the DueDateCacher to create
submissions for students with overridden due dates. This will cache the due date
so analyitics can correctly calculate the graph data. The analytics will search
for a submission, if it finds one it will use the cached due date for
calculations, if not it uses the assignments date due assuming there are not any
dates that are overridden.
Also reference g/23800.
Test Case:
Setup: Create a Course with an assignment and an enrollment.
- Without the student submitting the assignment. Grade the assignment for the
student.
- Open analytics for the course and the Assignments graph should not show any
submissions for that assignment.
- Create a due date override.
- A submission should be created to cache the due date and the graph should
not show any submissions for that assignment.
Change-Id: Icdae246d9c9913c8a163505d14b86f1300c809de
Reviewed-on: https://gerrit.instructure.com/25352
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Nick Cloward <ncloward@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Nick Cloward <ncloward@instructure.com>
fixes CNVS-2330
Test plan:
* make a course with students named "Ball Wall" and
"Shmallart Wallart"
* In gradebook2, "Ball Wall" should be listed *above* "Smallart
Wallart"
* only in chrome though... other browsers don't support the locale
options we need
* In gradebook.csv, "Wall, Ball" should be listed above "Wallart,
Shmallart"
Change-Id: I7f20e81cc55b4ee962b2cca32cc48e6c49c48472
Reviewed-on: https://gerrit.instructure.com/26236
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: Caleb Guanzon <cguanzon@instructure.com>
Product-Review: Cameron Matheson <cameron@instructure.com>
refs CNVS-5180
the original migration had a regression since it was originally run;
fix the regression, and any dbs that have been migrated since that
regressions was introduced
Change-Id: I773c53a371364b238c9330481f1c1a7fdf472aa1
Reviewed-on: https://gerrit.instructure.com/26010
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
refs CNVS-5180
the original migration changed since it was originally run;
fix it if the original version ran
Change-Id: I809dbdf29979b7cb4de2edc5ac46b917e0469cd6
Reviewed-on: https://gerrit.instructure.com/26012
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
if the same user answers the same aligned question (through a question
bank) in multiple quizzes, let each quiz's question instance get its own
learning outcome result.
fixes CNVS-1194
test-plan:
- create an account-level outcome
- create an account-level question bank
- align the outcome with the question bank
- create a question in the question bank
- create two quizzes in course(s) under the account using that question
from the bank
- have one student take both quizzes
- look at the student's generated outcome results for that outcome;
there should be two results, one per quiz.
- retake one or both quizzes; there should still only be one result per
quiz, updated with the new score.
Change-Id: I1368270a06cec7dcd2c757ff60196b254c61d3d9
Reviewed-on: https://gerrit.instructure.com/25991
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
Product-Review: Rob Orton <rob@instructure.com>
QA-Review: Rob Orton <rob@instructure.com>
when the rubric data was an array of HashWithIndifferentAccess instead of
just Hash (which happens when the rubric is copied to another course), it
didn't have the comma in front of learning_outcome_id that was expected in the
FixOutOfSyncOutcomeAlignments data fixup.
fixes CNVS-9021
test plan:
*** before checking out this ***
- create a new learning outcome
- create rubric with the learning outcome
- import the rubric into another course using "Import Content" in course
settings
- add the rubric to an assignment
- note the id of the outcome you added to the rubric
- in the console, run the following command:
`ContentTag.where(:learning_outcome_id => <LO_ID_HERE>).
update_all(:workflow_state => 'deleted')'
- go to the outcome page and it will not list any alignments
- set up some other outcome alignments that are active, and others that are
deleted, that you would not expect to change
*** checkout the commit ***
- make sure delayed jobs ar running, and the UndeleteSomeOutcomeAlignments job
is not in the failed jobs list
- go to the first outcome page again, it should correctly list the alignments
(meaning they were restored) that you manually deleted from the second
course (the one you imported into) but not the original. This is okay, and
it's because we deleted all the outcome's alignments in the console. In
real data, only the alignments from the copied course would have been deleted.
- other alignments should not be touched
Change-Id: I524cc6a86483ea8beb6809fcc14653ef3ca711df
Reviewed-on: https://gerrit.instructure.com/25648
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Cameron Matheson <cameron@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
Product-Review: Simon Williams <simon@instructure.com>
fixes CNVS-6873
test plan:
* upload a file that's scribdable (i.e. a pdf)
* verify you can preview it
* Setting.set('scribd.stale_threshold', 0) (this means scribd docs
will be deleted immediately)
* run Attachment.delete_stale_scribd_docs
* refresh your preview; it should say it's still processing
* refresh again, and it should show up
Change-Id: I129f216eafb2f43e9ea94ae451cd041f1d5914d5
Reviewed-on: https://gerrit.instructure.com/25563
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
refs CNVS-8282
test plan
- have scribd enabled
- upload a scribdable document to a course
- document should be rendered with scribd
- previously created documents should still render
Change-Id: Id8d7ea962c7bbe16b0f124e23447c66a48dd4100
Reviewed-on: https://gerrit.instructure.com/25566
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Rob Orton <rob@instructure.com>
refs CNVS-7877
* counter updates have to be in their own batch in 1.2+
* add the use_cql3? method to cassandra gem, even
though we're not updating it yet
* slight change in syntax for table creation
* 1.2 doesn't return schema info in the schema cql command;
use a query to get tables
Change-Id: I22642b0fb99e744080f9a7efd0b3d0372de020b9
Reviewed-on: https://gerrit.instructure.com/25361
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
use it to trigger a singular grade publish for a user
Change-Id: If28044b9bef6c71d2061adb2ac423b836f4c8634
Reviewed-on: https://gerrit.instructure.com/24977
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
fixes CNVS-8241
test plan:
- is possible, have a submission version with invalid yaml
- make sure the PopulateSubmissionVersions job runs successfully
- make sure the GradingHistory api endpoint returns all submission
versions
Change-Id: I00039df95cd3725d32c5478b27f10b9557cb9172
Reviewed-on: https://gerrit.instructure.com/24646
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Product-Review: Simon Williams <simon@instructure.com>
rather than CANVAS_RAILS3 or Rails.version
this is to be consistent, and to reinforce that any "special" branches
are for rails 2.3 backwards compatibility while trying to target rails
3, rather than rails 3 "forwards compatibility".
Change-Id: I4494b65e3f71108a43d09032c1569c478646a828
Reviewed-on: https://gerrit.instructure.com/24998
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Product-Review: Jacob Fugal <jacob@instructure.com>
QA-Review: Jacob Fugal <jacob@instructure.com>
refs CNVS-8392
also update the page view API documentation
test plan:
* with this commit applied, page views will now log the remote
ip of requests, and return that ip in the api and csv downloads
* regenerate api docs with rake doc:api, and verify that the user
section now has expanded information on the api response
Change-Id: If463e211515881db6ce1f75c9bbca8c7fbcf7589
Reviewed-on: https://gerrit.instructure.com/24880
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Cody Cutrer <cody@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Brian Palmer <brianp@instructure.com>