canvas-lms/config/routes.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2908 lines
159 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
#
# Copyright (C) 2011 - 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/>.
full_path_glob = "(/*full_path)"
# allow plugins to prepend routes
Dir[Rails.root.join("{gems,vendor}/plugins/*/config/pre_routes.rb")].each do |pre_routes|
load pre_routes
end
CanvasRails::Application.routes.draw do
post "/api/graphql", to: "graphql#execute"
post "/api/graphql/subgraph", to: "graphql#subgraph_execute"
# The subgraph endpoint is for use only with the federated API Gateway. See
# `app/graphql/README.md` for details.
get "graphiql", to: "graphql#graphiql"
resources :submissions, only: [] do
resources :submission_comments, path: :comments, only: :index, defaults: { format: :pdf }
add new endpoint for docviewer audit events refs GRADE-1331 Test Plan - Create/edit dynamic_settings.yml and add in an entry under "config" that is: canvadoc: app-host: "http://api.canvadoc.docker" secret: "c2Vrcml0" * app-host url doesn't matter, and the secret is "sekrit" base64 encoded if you're curious. - Open a rails console and enter: `Canvas::Security.create_jwt({}, nil, 'sekrit', :HS512)` The resulting token is your auth token for the duration of testing. - Create an assignment that accepts file uploads. - As a student, submit to that with a document. - As a teacher, launch speedgrader once for that assignment and view the document. - Open a rails console and find the submission, the attachment for that submission, and the canvadoc id related to that attachment. - use Postman or similar to do a post request to the new endpoint (submissions/:submission_id/docviewer_audit_events) with params as: canvas_user_id: (some teacher's id) document_id: (the canvadoc id) event_type: (anything you want, but 'highlight_created' is good) related_annotation_id: (pick a number) submission_id: (the id of the submission) token: (your auth_token from the first few steps) annotation_body: { color: (pick a color) content: (some text) created_at: (pick a date) modified_at: (pick a date) page: (pick a number) type: (pick some text) } - Open a rails console and verify that an AnonymousOrModerationEvent with the attributes you set above was created. Change-Id: Ia41dba4814799a0c7b297b7b8f87d37e26fc6a2a Reviewed-on: https://gerrit.instructure.com/161049 Reviewed-by: Spencer Olson <solson@instructure.com> Tested-by: Jenkins Reviewed-by: Keith T. Garner <kgarner@instructure.com> QA-Review: Adrian Packel <apackel@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2018-08-15 02:33:56 +08:00
resources :docviewer_audit_events, only: [:create], constraints: { format: :json }
end
autosave comments on navigating to different user in speedgrader closes CNVS-28529 While in SpeedGrader, if you have something entered in the comments field and, without submitting those comments, you navigate to a different user or otherwise navigate away from SpeedGrader, your comments will now automatically be saved as "draft" comments for that user's submission. Draft comments * don't show up anywhere other than while grading * are invisible to users whether or not the assignment is muted * are only "submittable" by the author of the draft comment test plan: 1. Create a course, with at least two students 2. Add a quiz with at least one essay type question 3. As each student, take the quiz 4. As the teacher, grade the quiz and start up SpeedGrader 5. Enter comments for the first student's submission but do *not* submit them 6. Navigate to the next student 7. You should see a message telling you your comment was auto-saved 8. Go back to the previous student 9. You should see your comment styled differently with a red asterisk before it, indicating a draft comment (also using aria-label for a11y goodness) 10.Enter another comment and this time submit it 11.You should see your comment styled normally without a red asterisk before it, indicating a normal (non-draft) comment 12.Try steps 5 through 11 with different ways of leaving that student in step #6 e.g. using the drop down, or quitting SpeedGrader altogether and you should see the same results for draft comments 13.Go back to a submission with a draft comment. 14.Click on the button labelled "Publish" next to your draft comment. 15.Watch your comment change in appearance from a draft comment to a regular comment 16.Delete any comment and watch it disappear from the comment list. 17.Go to the next student 18.Go back to the previous student for whose submission you deleted the comment 19.Notice the deleted comment remains missing from the comment list. 20.Verify that, if logged in as a student, you never see draft comments Change-Id: If32294a7bed6f847709b54d4c8e4fc21fb2a6eca Reviewed-on: https://gerrit.instructure.com/77133 Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Neil Gupta <ngupta@instructure.com> Tested-by: Jenkins QA-Review: Amber Taniuchi <amber@instructure.com> Product-Review: Christi Wruck
2016-04-14 05:02:28 +08:00
resources :submission_comments, only: [:update, :destroy]
resources :epub_exports, only: [:index]
get "inbox" => "context#inbox"
get "oauth/redirect_proxy" => "oauth_proxy#redirect_proxy"
get "conversations/unread" => "conversations#index", :as => :conversations_unread, :redirect_scope => "unread"
get "conversations/starred" => "conversations#index", :as => :conversations_starred, :redirect_scope => "starred"
get "conversations/sent" => "conversations#index", :as => :conversations_sent, :redirect_scope => "sent"
get "conversations/archived" => "conversations#index", :as => :conversations_archived, :redirect_scope => "archived"
get "conversations/find_recipients" => "search#recipients"
get "search/recipients" => "search#recipients"
post "conversations/mark_all_as_read" => "conversations#mark_all_as_read"
get "conversations/batches" => "conversations#batches", :as => :conversation_batches
resources :conversations, only: %i[index show update create destroy] do
post :add_recipients
post :add_message
post :remove_messages
end
2015-06-26 03:35:25 +08:00
post "/external_auth_observers/redirect_login" => "login/external_auth_observers#redirect_login", :as => :external_auth_validation
Register Parents and Add Observees when configured for SAML authentication Fixes PFS-1084 Parent Registration: When a Saml config is designated for Parent Registration the parent signing up will be redirected to a Saml login page where they will log in with their child's credentials. After login the child user's Saml session will be ended and the parent registration process will complete. Parent Adding Student: When a Saml config is designated for Parent Registration the parent adding another observee will be redirected to a Saml login page where they will log in with their child's credentials. After login the child user's Saml session will be ended and the observee creation process will complete. --------------------------------------- TEST PLAN: SETUP: 1) In your account settings check the box for 'Self Registration' (and either of the sub-options) 2) Add the following users to your account (these will be the students): billyjoel eltonjohn 3) In Authentication Settings add a SAML authentication service and enter the following fields (I've set up a remote SAML Idp): IdP Entity ID: http://107.170.212.143/saml2/idp/metadata.php Log On URL: http://107.170.212.143/simplesaml/saml2/idp/SSOService.php Log Out URL: http://107.170.212.143/simplesaml/saml2/idp/SingleLogoutService.php Certificate Fingerprint: 9C:11:68:93:95:CD:18:01:EC:52:2B:9E:22:7F:73:55:ED:6D:82:D4 Parent Registration: check TEST: Parent Registration: * Go to '/login/canvas' * Click on the signup banner * sign up as a parent for billyjoel or eltonjohn (on SAML login page the password for either user is: tantrum) Add Student: * Log in as a parent user w/ a Canvas Auth login * Go to '/profile/observees' * Add Student 'billyjoel' or 'eltonjohn' Authentication Settings (new parent reg checkbox): * Go to Authentication Settings * Add a second SAML config * check the parent registration checkbox - it should warn that selection will deselect the other and in fact do so upon save. - the selected config is the one used for parent reg/add student --------------------------------------- Change-Id: Ief83b604fc252c88dbb912c56de65d8620fe802f Reviewed-on: https://gerrit.instructure.com/49691 Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Reviewed-by: Jacob Fugal <jacob@instructure.com> Product-Review: Ethan Vizitei <evizitei@instructure.com>
2015-03-03 01:41:17 +08:00
2011-02-01 09:57:29 +08:00
# So, this will look like:
refactor user creation/invitations closes #5833 fixes #5573, #5572, #5753 * communication channels are now only unique within a single user * UserList changes * Always resolve pseudonym#unique_ids * Support looking up by SMS CCs * Option to either require e-mails match an existing CC, or e-mails that don't match a Pseudonym will always be returned unattached (relying on better merging behavior to not have a gazillion accounts created) * Method to return users, creating new ones (*without* a Pseudonym) if necessary. (can't create with a pseudonym, since Pseudonym#unique_id is still unique, I can't have multiple outstanding users with the same unique_id) * EnrollmentsFromUserList is mostly gutted, now using UserList's functionality directy. * Use UserList for adding account admins, removing the now unused Account#add_admin => User#find_by_email/User#assert_by_email codepath * Update UsersController#create to not worry about duplicate communication channels * Remove AccountsController#add_user, and just use UsersController#create * Change SIS::UserImporter to send out a merge opportunity e-mail if a conflicting CC is found (but still create the CC) * In /profile, don't worry about conflicting CCs (the CC confirmation process will now allow merging) * Remove CommunicationChannelsController#try_merge and #merge * For the non-simple case of CoursesController#enrollment_invitation redirect to /register (CommunicationsChannelController#confirm) * Remove CoursesController#transfer_enrollment * Move PseudonymsController#registration_confirmation to CommunicationChannelsController#confirm (have to be able to register an account without a Pseudonym yet) * Fold the old direct confirm functionality in, if there are no available merge opportunities * Allow merging the new account with the currently logged in user * Allow changing the Pseudonym#unique_id when registering a new account (since there might be conflicts) * Display a list of merge opportunities based on conflicting communication channels * Provide link(s) to log in as the other user, redirecting back to the registration page after login is complete (to complete the merge as the current user) * Remove several assert_* methods that are no longer needed * Update PseudonymSessionsController a bit to deal with the new way of dealing with conflicting CCs (especially CCs from LDAP), and to redirect back to the registration/confirmation page when attempting to do a merge * Expose the open_registration setting; use it to control if inviting users to a course is able to create new users Change-Id: If2f38818a71af656854d3bf8431ddbf5dcb84691 Reviewed-on: https://gerrit.instructure.com/6149 Tested-by: Hudson <hudson@instructure.com> Reviewed-by: Jacob Fugal <jacob@instructure.com>
2011-10-13 04:30:48 +08:00
# http://instructure.com/register/5R32s9iqwLK75Jbbj0
match "register/:nonce" => "communication_channels#confirm", :as => :registration_confirmation, :via => [:get, :post]
refactor user creation/invitations closes #5833 fixes #5573, #5572, #5753 * communication channels are now only unique within a single user * UserList changes * Always resolve pseudonym#unique_ids * Support looking up by SMS CCs * Option to either require e-mails match an existing CC, or e-mails that don't match a Pseudonym will always be returned unattached (relying on better merging behavior to not have a gazillion accounts created) * Method to return users, creating new ones (*without* a Pseudonym) if necessary. (can't create with a pseudonym, since Pseudonym#unique_id is still unique, I can't have multiple outstanding users with the same unique_id) * EnrollmentsFromUserList is mostly gutted, now using UserList's functionality directy. * Use UserList for adding account admins, removing the now unused Account#add_admin => User#find_by_email/User#assert_by_email codepath * Update UsersController#create to not worry about duplicate communication channels * Remove AccountsController#add_user, and just use UsersController#create * Change SIS::UserImporter to send out a merge opportunity e-mail if a conflicting CC is found (but still create the CC) * In /profile, don't worry about conflicting CCs (the CC confirmation process will now allow merging) * Remove CommunicationChannelsController#try_merge and #merge * For the non-simple case of CoursesController#enrollment_invitation redirect to /register (CommunicationsChannelController#confirm) * Remove CoursesController#transfer_enrollment * Move PseudonymsController#registration_confirmation to CommunicationChannelsController#confirm (have to be able to register an account without a Pseudonym yet) * Fold the old direct confirm functionality in, if there are no available merge opportunities * Allow merging the new account with the currently logged in user * Allow changing the Pseudonym#unique_id when registering a new account (since there might be conflicts) * Display a list of merge opportunities based on conflicting communication channels * Provide link(s) to log in as the other user, redirecting back to the registration page after login is complete (to complete the merge as the current user) * Remove several assert_* methods that are no longer needed * Update PseudonymSessionsController a bit to deal with the new way of dealing with conflicting CCs (especially CCs from LDAP), and to redirect back to the registration/confirmation page when attempting to do a merge * Expose the open_registration setting; use it to control if inviting users to a course is able to create new users Change-Id: If2f38818a71af656854d3bf8431ddbf5dcb84691 Reviewed-on: https://gerrit.instructure.com/6149 Tested-by: Hudson <hudson@instructure.com> Reviewed-by: Jacob Fugal <jacob@instructure.com>
2011-10-13 04:30:48 +08:00
# deprecated
get "pseudonyms/:id/register/:nonce" => "communication_channels#confirm", :as => :registration_confirmation_deprecated
post "confirmations/:user_id/re_send(/:id)" => "communication_channels#re_send_confirmation", :as => :re_send_confirmation, :id => nil
get "confirmations/:user_id/limit_reached(/:id)" => "communication_channels#confirmation_limit_reached", :as => :confirmation_limit_reached, :id => nil
match "forgot_password" => "pseudonyms#forgot_password", :as => :forgot_password, :via => [:get, :post]
get "pseudonyms/:pseudonym_id/change_password/:nonce" => "pseudonyms#confirm_change_password", :as => :confirm_change_password
post "pseudonyms/:pseudonym_id/change_password/:nonce" => "pseudonyms#change_password", :as => :change_password
2011-02-01 09:57:29 +08:00
# callback urls for oauth authorization processes
get "oauth" => "users#oauth"
get "oauth_success" => "users#oauth_success"
get "mr/:id" => "info#message_redirect", :as => :message_redirect
get "help_links" => "info#help_links"
redesign and simplify error pages fixes ADMIN-2336 test plan: - create a page in a course that links to the following: * a file that has been deleted * a file with an invalid id * a resource (file, assignment, etc.) that is unpublished * a resource that is in a different course (most easily done by changing the course id in the link in the html) - as a student, click these links and ensure the pages you see look like the mockups in ADMIN-2331. - in all of these cases, * there is a centered image - this image is not read by screen readers, since it is purely decorative * there is not a red box * there is not a link to contact support - for the deleted file, you should see "Page Not Found" and a note that the file has been deleted - for other links to nonexistent items, you should just see "Page Not Found" - for unpublished items, you should see "Not Yet Available" and a locked document picture - for items in a different course (that the student is not enrolled in), you should see "Access Denied" and a lock picture - also test the new 400 and 500 error pages. the easiest way to do this is with the /test_error endpoint: - /test_error?status=400 - /test_error?status=500 - these show the broken rocket picture and still include a support link Change-Id: I9f20e742e690482887cf375c79e4060aff6d7146 Reviewed-on: https://gerrit.instructure.com/178581 Tested-by: Jenkins Reviewed-by: Ed Schiebel <eschiebel@instructure.com> Reviewed-by: Carl Kibler <ckibler@instructure.com> QA-Review: Carl Kibler <ckibler@instructure.com> Product-Review: Kyle Follett <kfollett@instructure.com>
2019-01-19 05:37:35 +08:00
# This is a debug route that makes working on error pages easier
get "test_error" => "info#test_error" unless Rails.env.production?
get "live_events/heartbeat" => "info#live_events_heartbeat" unless Rails.env.production?
concern :question_banks do
resources :question_banks do
post :bookmark
post :reorder
get :questions
post :move_questions
resources :assessment_questions
end
end
2011-02-01 09:57:29 +08:00
concern :groups do
resources :groups, except: :edit
resources :group_categories, only: %i[create update destroy]
get "group_unassigned_members" => "groups#unassigned_members"
end
Allows teacher to clone a group set. Option 'Clone Group Set' added in the group set cog wheel. When modifying group membership on a group that has submitted an assignment, teacher is alerted and given option of cloning group set or changing groups. fixes CNVS-19746 test plan: - as a teacher - navigate to a course - select 'People' and go to 'Groups' - create a new group set with groups and memberships - create a group assignment for that group set - as a student who is a member of a group of that group set - submit the assignment for their group - as a teacher - modify the memberships for that group set - for groups that have submissions - drag and drop a student - out of group into another group - out of group into 'Unassigned Students' - into group from another group - into group from 'Unassigned Students' - remove student using 'Remove' option in cog wheel - move student using 'Move To...' option in cog wheel - add student from 'Unassigned Students' using '+' option - when 'Clone Group Set' modal is displayed - select 'New Group Set' - memberships in original group set should not change - within cloned group set - should contain all groups, group leader, memberships, and membership limits from original group set - group membership modification should function as normal - selecting 'Change Groups' - group membership changes - delete assignment created for group set - group membership modification should function as normal - select 'Clone Group Set' option from group set cog wheel - should follow same expectations when 'New Group Set' is selected from alert - significant UI changes were made and should be tested - accessibility has been considered and should be tested - regression test on group Change-Id: I59276eca93f86d370f8658f5bdd0e9464f3fa061 Reviewed-on: https://gerrit.instructure.com/58753 Tested-by: Jenkins Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> QA-Review: Steven Shepherd <sshepherd@instructure.com> Product-Review: Andraia Allsop <aallsop@instructure.com>
2015-07-18 04:07:01 +08:00
resources :group_categories do
member do
post "clone_with_name"
end
end
concern :files do
resources :files, except: [:new] do
get "inline" => "files#text_show", :as => :text_inline
get "download" => "files#show", :download => "1"
get "download.:type" => "files#show", :as => :typed_download, :download => "1"
get "preview" => "files#show", :preview => "1"
post "inline_view" => "files#show", :inline => "1"
get "contents" => "files#attachment_content", :as => :attachment_content
file preview endpoint test plan: 0. upload the following types of files into a course, and note their IDs: a) document of some type (such as Word, PDF) b) image (such as JPEG, PNG, GIF) c) media (such as MP3, MP4, MOV) 1. enable canvadocs and google docs previews in account settings. 2. test the document preview by hitting the following in a new browser tab: /courses/X/files/Y/file_preview (where X is the course ID and Y is the file ID of the document file) - You should see a Canvadocs preview of the document. - There should be no Canvas chrome in the window, just the document preview. 3. disable canvadocs but leave google doc previews enabled. 4. hit the URL from step 2. - you should see a Google preview of the document 5. disable Google docs previews. 6. hit the URL from step 2. - you should see a message indicating that no preview is available, with a link to download the file. 7. hit the URL from step 2, but substitute the file ID with the ID of an image instead of a document. - you should see the image (and nothing else). 8. hit the URL from step 2, but substitute the file ID with the ID of a media file. - You should see a functioning media player (or a message indicating the media has not been converted yet) 9. add a document to a module, and set a "must view" completion requirement 10. use this endpoint to preview the document, and confirm that the module completion requirement is fulfilled fixes CNVS-15827 Change-Id: Id0ecaa7f003248cb3d8f163e48c3b16631ee59cf Reviewed-on: https://gerrit.instructure.com/42438 Reviewed-by: Ryan Shaw <ryan@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com> Product-Review: Cosme Salazar <cosme@instructure.com>
2014-10-09 05:27:45 +08:00
get "file_preview" => "file_previews#show"
collection do
get "folder#{full_path_glob}" => "files#react_files", :format => false, :defaults => { format: "html" }
get "search" => "files#react_files", :format => false, :defaults => { format: "html" }
get :quota
post :reorder
end
get "*file_path" => "files#show_relative", :as => :relative_path, :file_path => /.+/ # needs to stay below react_files route
end
end
concern :file_images do
get "images" => "files#images"
end
concern :relative_files do
get "file_contents/*file_path" => "files#show_relative", :as => :relative_file_path, :file_path => /.+/
end
concern :folders do
resources :folders
end
concern :media do
get "media_download" => "users#media_download"
end
concern :users do
get "users" => "context#roster"
get "user_services" => "context#roster_user_services"
get "users/:user_id/usage" => "context#roster_user_usage", :as => :user_usage
get "users/:id" => "context#roster_user", :as => :user
end
concern :announcements do
resources :announcements
post "announcements/external_feeds" => "announcements#create_external_feed"
delete "announcements/external_feeds/:id" => "announcements#destroy_external_feed", :as => :announcements_external_feed
end
concern :discussions do
resources :discussion_topics, only: %i[index new show edit destroy]
get "discussion_topics/:id/*extras" => "discussion_topics#show", :as => :map, :extras => /.+/
resources :discussion_entries
end
concern :pages do
resources :wiki_pages, path: :pages, except: %i[update destroy new], constraints: { id: %r{[^/]+} } do
get "revisions" => "wiki_pages#revisions", :as => :revisions
end
get "wiki" => "wiki_pages#front_page", :as => :wiki
get "wiki/:id" => "wiki_pages#show_redirect", :id => %r{[^/]+}
get "wiki/:id/revisions" => "wiki_pages#revisions_redirect", :id => %r{[^/]+}
get "wiki/:id/revisions/:revision_id" => "wiki_pages#revisions_redirect", :id => %r{[^/]+}
end
concern :conferences do
resources :conferences do
match :join, via: [:get, :post]
match :close, via: [:get, :post]
get :recording
delete :recording, to: "conferences#delete_recording", as: :delete_recording
get :settings
end
end
get "/courses/:course_id/gradebook2", to: redirect("/courses/%{course_id}/gradebook")
2011-02-01 09:57:29 +08:00
# There are a lot of resources that are all scoped to the course level
# (assignments, files, wiki pages, user lists, forums, etc.). Many of
# these resources also apply to groups and individual users. We call
# courses, users, groups, or even accounts in this setting, "contexts".
# There are some helper methods like the before_filter :get_context in application_controller
# and the application_helper method :context_url to make retrieving
# these contexts, and also generating context-specific urls, easier.
resources :courses do
# DEPRECATED
get "self_enrollment/:self_enrollment" => "courses#self_enrollment", :as => :self_enrollment
post "self_unenrollment/:self_unenrollment" => "courses#self_unenrollment", :as => :self_unenrollment
post :unconclude
get :students
get "observer_pairing_codes.csv", action: :observer_pairing_codes_csv, as: "observer_pairing_codes"
post :enrollment_invitation
# this needs to come before the users concern, or users/:id will preempt it
get "users/prior" => "context#prior_users", :as => :prior_users
concerns :users
get :statistics
delete "unenroll/:id" => "courses#unenroll_user", :as => :unenroll
post "move_enrollment/:id" => "courses#move_enrollment", :as => :move_enrollment
delete "unenroll/:id.:format" => "courses#unenroll_user", :as => :formatted_unenroll
post "limit_user_grading/:id" => "courses#limit_user", :as => :limit_user_grading
delete "conclude_user/:id" => "courses#conclude_user", :as => :conclude_user_enrollment
post "unconclude_user/:id" => "courses#unconclude_user", :as => :unconclude_user_enrollment
resources :sections, except: %i[index edit new] do
get "crosslist/confirm/:new_course_id" => "sections#crosslist_check", :as => :confirm_crosslist
post :crosslist
delete "crosslist" => "sections#uncrosslist", :as => :uncrosslist
end
get "undelete" => "context#undelete_index", :as => :undelete_items
post "undelete/:asset_string" => "context#undelete_item", :as => :undelete_item
get "settings#{full_path_glob}", action: :settings
get :settings
get "details" => "courses#settings"
post :re_send_invitations
post :enroll_users
post :link_enrollment
post :update_nav
resource :gradebook do
get "submissions_upload/:assignment_id" => "gradebooks#show_submissions_upload", :as => :show_submissions_upload
post "submissions_upload/:assignment_id" => "gradebooks#submissions_zip_upload", :as => :submissions_upload
collection do
get :change_gradebook_version
get :blank_submission
create endpoint for final grade overrides closes GRADE-1876 test plan: Notes: * To test the endpoint, send use the path: GET /courses/:course_id/gradebook/final_grade_overrides * To set overrides, perform the following in the Rails console: enrollment = course.enrollments.find_by(user_id: <student.id>) # to update a course score score = enrollment.scores.find_by!(course_score: true) score.update!(override_score: 89.2) # some score value # to update a grading period score period = <some grading period> score = enrollment.scores.find_by!(grading_period: period) score.update!(override_score: 89.2) # some score value A. Setup 1. Select or create a course 2. Ensure the course has at least one assignment 3. Enable the "Final Grade Override" feature flag 4. Use an enrollment term with some grading periods 5. Override a student's course score 6. Override a student's grading period score B. Verify 1. As a teacher in the course, send a request to the endpoint 2. Verify the response is structured as follows: { final_grade_overrides: { <student_id>: { course_grade: { percentage: 12.34 }, grading_period_grades: { <grading_period_id>: { percentage: 56.78 }, <grading_period_id>: { percentage: 90.12 } } }, <student_id>: {…} } } 3. Verify the response includes ids of only students with overrides 4. Verify each student represented includes scores for only the specific overrides assigned * not all grading period ids will be included if they do not all have overrides * the course grade override will not be included if not assigned 5. Verify the override percentage values are accurate Change-Id: I0e7df11139518b94460883d3dbd4700cba9aaeda Reviewed-on: https://gerrit.instructure.com/174017 Tested-by: Jenkins Reviewed-by: Gary Mei <gmei@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> QA-Review: Adrian Packel <apackel@instructure.com> Product-Review: Keith Garner <kgarner@instructure.com>
2018-12-04 01:15:02 +08:00
get :final_grade_overrides
get :speed_grader
post :speed_grader_settings
get :history
post :update_submission
post :change_gradebook_column_size
post :save_gradebook_column_order
add user_ids endpoint to gradebooks_controller Add endpoint to gradebooks controller which returns user ids sorted according to the user's gradebook sort preferences. closes CNVS-37608 Test Plan: 1. Create a course that has some active students, inactive students, and concluded students. Enable New Gradebook and go to the gradebook. 2. Click on the student header and select 'Inactive enrollments' and 'Concluded enrollments'. Then select 'Sort by -> A-Z'. 2. As a student in the course, hit the new endpoint to get user IDs (GET /courses/:course_id/gradebook/user_ids). Verify you get a 401 unauthorized response. 3. As a teacher in the course, hit the user_ids endpoint and verify you get a list of user IDs back. The user IDs should be ordered such that their corresponding users' names are in alpha ascending order. The list of user IDs should also include inactive and concluded students' IDs. 4. Go to the gradebook and click on the student header. Select 'Sort by -> Z-A'. 5. Hit the user_ids endpoint and verify the returned user IDs are now ordered such that their corresponding users' names are in alpha descending order. The list of user IDs should also include inactive and concluded students' IDs. 6. Go to the gradebook and click on the student column header. Deselect the 'Inactive enrollments' and 'Concluded enrollments' options. 7. Hit the user_ids endpoint and verify the returned user IDs no longer include IDs for inactive or concluded students. The IDs should still be ordered such that their corresponding users' names are in alpha descending order. 8. Go to the gradebook and click on the total grade header. Select 'Sort by Grade -> Low to High' 9. Hit the user_ids endpoint and verify the returned user IDs are ordered such that their corresponding users' current total grades are in ascending order. 10. Go to the gradebook and click on the total grade header. Select 'Sort by Grade -> High to Low' 11. Hit the user_ids endpoint and verify the returned user IDs are ordered such that their corresponding users' current total grades are in descending order. 12. In the same manner as the steps above, make sure changing the following settings in the gradebook causes the user_ids endpoint to return an array of IDs ordered according to the gradebook sort preferences: a) Assignment column header -> Sort by Grade -> Low to High b) Assignment column header -> Sort by Grade -> High to Low c) Assignment column header -> Sort by -> Missing (the user_ids endpoint should return all users with a missing submission for that assignment first) d) Assignment column header -> Sort by -> Late (the user_ids endpoint shoudl return all users with a late submission for that assignment first) e) Select a grading period and sort by total grade. The user_ids endpoint should return user IDs that are ordered such that their corresponding users' grades are in ascending or descending order for the selected grading period. * Note: Sorting by assignment group totals is not currently supported. Change-Id: I4a36aa5b82d87f49d2396bbc16e1cc56e89eba0f Reviewed-on: https://gerrit.instructure.com/116491 Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com> Tested-by: Jenkins Reviewed-by: Keith T. Garner <kgarner@instructure.com> QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-06-17 06:37:46 +08:00
get :user_ids
get :grading_period_assignments
end
end
resource :gradebook_csv, only: [:create]
# DEPRECATED old migration emails pointed the user to this url, leave so the controller can redirect
get "imports/list" => "content_imports#index", :as => :import_list
# DEPRECATED
get "imports" => "content_imports#intro"
resource :gradebook_upload do
get "data" => "gradebook_uploads#data"
end
get "grades" => "gradebooks#grade_summary", :id => nil
get "grading_rubrics" => "gradebooks#grading_rubrics"
get "grades/:id" => "gradebooks#grade_summary", :as => :student_grades
sort assignments on course grades page allow sorting by assignment group, due date, module, and title on the course grades page. also, store the user's sort preferences and remember that preference on subsequent page loads. closes CNVS-21660 test plan: - as a student, go to the /courses/:course_id/grades page. - verify there is a dropdown to sort assignments by due date and title. the first time you visit this page, the dropdown option should default to ordering by due date. verify each option correctly sorts the assignments. - if the course has any Modules, there should be an option to sort by Module. if the course does not have any Modules, there should not be a Module sort option. - if the course has assignments that belong to different Assignment Groups, there should be an option to sort by Assignment Group. if the course does not have any assignments, or if all of the course's assignments belong to the same Assignment Group, there should not be an Assignment Group sort option. - select any option besides 'Due Date'. next, leave the page and return back to the page. verify the selected dropdown option matches the option you selected before leaving the page. - repeat the steps above while logged in as a teacher, TA, student view student, and admin. when logged in as a teacher, TA, or admin, the url will be /courses/:course_id/grades/ :student_id - verify the dropdown is accessible - note: if a student is enrolled in multiple courses, the dropdown for the sort order should be on the right-hand side of the /courses/:course_id/grades page (and the dropdown for the course selection should be on the left-hand side). if a student is only enrolled in one course, the dropdown for sort order should be on the left-hand side of the page. Change-Id: Idbcbea2d25051cb5d933bfb395daebeedc630855 Reviewed-on: https://gerrit.instructure.com/69419 Reviewed-by: Derek Bender <djbender@instructure.com> Tested-by: Jenkins QA-Review: KC Naegle <knaegle@instructure.com> Product-Review: Spencer Olson <solson@instructure.com>
2015-12-22 12:35:21 +08:00
post "save_assignment_order" => "gradebooks#save_assignment_order", :as => :save_assignment_order
concerns :announcements
get "calendar" => "calendars#show"
get :locks
concerns :discussions
resources :assignments do
get "moderate" => "assignments#show_moderate"
get "anonymous_submissions/:anonymous_id",
to: "submissions/anonymous_previews#show",
constraints: lambda { |request|
request.query_parameters.key?(:preview) && request.format == :html
}
get "anonymous_submissions/:anonymous_id",
to: "submissions/anonymous_downloads#show",
constraints: lambda { |request|
request.query_parameters.key?(:download)
}
get "anonymous_submissions/:anonymous_id", to: "anonymous_submissions#show", as: :anonymous_submission
cleanup SubmissionsController#show fixes CNVS-25767 - Simplifies SubmissionsController#show & adds test coverage. - Adds Submissions::DownloadsController#show to handle submission download functionality. - Adds Submissions::PreviewsController#show to handle submission preview functionality. test plan: - As a teacher, add assignments for each online submission type: Text Entry, Website URL & File Uploads. - As a student, provide a submission for each of these assignments. Provide two submissions for at least one of the assignments. - As the student, view each of these submissions via the submission details page. URL path looks like: /courses/1/assignments/1/submissions/2, and can be accessed from assignment page. - Observe that the body of the submission shows up in the Submission Detail page. - Observe that for file uploads, the files can be downloaded. - As the teacher, access the speed grader for each submission. - Observe that the submission body appears in the speed grader. - Observe that, for file uploads, the files are displayed inline (this doesn't work for every media type and it will tell you as much if it's not supported). - Observe that if there are multiple files provided, the list of files appears in the left hand column, and the teacher can tolggle between them. - Observe that if the submission has multiple versions, in the left hand column there is a dropdown labeled 'Submission to view:', and toggling the selected datetime will change the submission that is displayed. - As the teacher viewing a submission in the speed grader, leave a comment in the right hand column, and attach a file. - As the student, view the submission details page. - Observe that there is a link to the fiel in the right hand column, and that the file can be downloaded. Change-Id: Ib3fff3909f47873b37c373e53ab26cb8176b94e1 Reviewed-on: https://gerrit.instructure.com/68559 Tested-by: Jenkins Reviewed-by: Mike Nomitch <mnomitch@instructure.com> QA-Review: Michael Hargiss <mhargiss@instructure.com> Product-Review: Jason Sparks <jsparks@instructure.com>
2015-12-04 00:15:27 +08:00
get "submissions/:id",
to: "submissions/previews#show",
constraints: lambda { |request|
request.query_parameters.key?(:preview) && request.format == :html
}
cleanup SubmissionsController#show fixes CNVS-25767 - Simplifies SubmissionsController#show & adds test coverage. - Adds Submissions::DownloadsController#show to handle submission download functionality. - Adds Submissions::PreviewsController#show to handle submission preview functionality. test plan: - As a teacher, add assignments for each online submission type: Text Entry, Website URL & File Uploads. - As a student, provide a submission for each of these assignments. Provide two submissions for at least one of the assignments. - As the student, view each of these submissions via the submission details page. URL path looks like: /courses/1/assignments/1/submissions/2, and can be accessed from assignment page. - Observe that the body of the submission shows up in the Submission Detail page. - Observe that for file uploads, the files can be downloaded. - As the teacher, access the speed grader for each submission. - Observe that the submission body appears in the speed grader. - Observe that, for file uploads, the files are displayed inline (this doesn't work for every media type and it will tell you as much if it's not supported). - Observe that if there are multiple files provided, the list of files appears in the left hand column, and the teacher can tolggle between them. - Observe that if the submission has multiple versions, in the left hand column there is a dropdown labeled 'Submission to view:', and toggling the selected datetime will change the submission that is displayed. - As the teacher viewing a submission in the speed grader, leave a comment in the right hand column, and attach a file. - As the student, view the submission details page. - Observe that there is a link to the fiel in the right hand column, and that the file can be downloaded. Change-Id: Ib3fff3909f47873b37c373e53ab26cb8176b94e1 Reviewed-on: https://gerrit.instructure.com/68559 Tested-by: Jenkins Reviewed-by: Mike Nomitch <mnomitch@instructure.com> QA-Review: Michael Hargiss <mhargiss@instructure.com> Product-Review: Jason Sparks <jsparks@instructure.com>
2015-12-04 00:15:27 +08:00
get "submissions/:id",
to: "submissions/downloads#show",
constraints: lambda { |request|
request.query_parameters.key?(:download)
}
put "anonymous_submissions/:anonymous_id", to: "anonymous_submissions#update"
Allow reassignment from SpeedGrader closes OUT-4033 [fsc-timeout=50] flag=reassign_assignments This feature allows teachers to reassign an assignment to a student after they've submitted to the assignment and the teacher has provided feedback via comments. The reassignment will appear in their planner with a "Redo" tag visible next to the assignment. Only supports assignments of submission type "Online". test plan: - enable "Reassign Assignments" feature option - in a course, create a student account - as a teacher, create an assignment with a due date - as a student, confirm the assignment appears in their planner - as a student, submit to the assignment - as a teacher, open the submission in SpeedGrader - reassign the assignment to the student by: * adding a comment to the assignment * clicking the "Reassign Assignment" button - as a student, confirm the assignment appears with a "Redo" pill in the planner, along with the comment from the teacher - as a student, resubmit to the assignment and confirm the assignment shows as completed again in the planner without the "Redo" pill - repeat the above steps, except with an assignment that has "Anonymous Grading" enabled and it should behave in the same way - repeat the above steps but with more students and no due date on the assignment, but with various assignment overrides with due dates and some students assigned to those overrides (using course sections) and confirm the "Resassign Assignment" button only appears for those students with assignment overrides (and hence due dates), with the button being disabled until the student both submits to the assignment and the teacher has provided a comment. Change-Id: Id745b50f3810378804e0728e544ebf6bff8f756a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/251663 QA-Review: Kai Bjorkman <kbjorkman@instructure.com> Product-Review: Jody Sailor Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> Reviewed-by: Pat Renner <prenner@instructure.com>
2020-10-28 03:49:42 +08:00
put "anonymous_submissions/:anonymous_id/reassign", to: "anonymous_submissions#redo_submission"
resources :submissions do
get "originality_report/:asset_string" => "submissions#originality_report", :as => :originality_report
post "turnitin/resubmit" => "submissions#resubmit_to_turnitin", :as => :resubmit_to_turnitin
get "turnitin/:asset_string" => "submissions#turnitin_report", :as => :turnitin_report
post "vericite/resubmit" => "submissions#resubmit_to_vericite", :as => :resubmit_to_vericite
get "vericite/:asset_string" => "submissions#vericite_report", :as => :vericite_report
get "audit_events" => "submissions#audit_events", :as => :audit_events
Allow reassignment from SpeedGrader closes OUT-4033 [fsc-timeout=50] flag=reassign_assignments This feature allows teachers to reassign an assignment to a student after they've submitted to the assignment and the teacher has provided feedback via comments. The reassignment will appear in their planner with a "Redo" tag visible next to the assignment. Only supports assignments of submission type "Online". test plan: - enable "Reassign Assignments" feature option - in a course, create a student account - as a teacher, create an assignment with a due date - as a student, confirm the assignment appears in their planner - as a student, submit to the assignment - as a teacher, open the submission in SpeedGrader - reassign the assignment to the student by: * adding a comment to the assignment * clicking the "Reassign Assignment" button - as a student, confirm the assignment appears with a "Redo" pill in the planner, along with the comment from the teacher - as a student, resubmit to the assignment and confirm the assignment shows as completed again in the planner without the "Redo" pill - repeat the above steps, except with an assignment that has "Anonymous Grading" enabled and it should behave in the same way - repeat the above steps but with more students and no due date on the assignment, but with various assignment overrides with due dates and some students assigned to those overrides (using course sections) and confirm the "Resassign Assignment" button only appears for those students with assignment overrides (and hence due dates), with the button being disabled until the student both submits to the assignment and the teacher has provided a comment. Change-Id: Id745b50f3810378804e0728e544ebf6bff8f756a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/251663 QA-Review: Kai Bjorkman <kbjorkman@instructure.com> Product-Review: Jody Sailor Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> Reviewed-by: Pat Renner <prenner@instructure.com>
2020-10-28 03:49:42 +08:00
put "reassign" => "submissions#redo_submission", :as => :reassign
end
Reenable anon plagiarism in SG for Turnitin For assignments using Turnitin (but not Vericite), re-enable the SpeedGrader link to the similarity report and the resubmit button even for assignments that are currently anonymizing. closes GRADE-1883 Test plan: - Create an anonymous assignment (with or without file submissions; see creation steps below) - In a Rails console, create some OriginalityReport objects for multiple submissions (see below) - Give at least one a valid score and workflow_state of 'scored' - Maybe enter a value for originality_report_url for one of them - Give at least one a workflow_state of 'error' - (or use "pending", in which case leave the score blank) - If your assignment involves file submissions, ensure each report's attachment_id matches an existent attachment - Open these submissions in SpeedGrader and check the following: - For 'scored' reports, you should see a clickable similarity score that links to a URL of the form: - .../anonymous_submissions/3oPSs/originality_report/asset_id (asset_id will be, e.g., submission_34 or attachment_999) - Visiting that URL should take you to the report's custom URL if defined, or else return you to SpeedGrader saying that a report couldn't be found (which is expected since our data is made up) - For 'pending'/'error' reports, you should see an error icon that reveals a 'Resubmit' button when clicked - Clicking 'Resubmit' should make a request to a URL of the form (you can check this in your logs): .../anonymous_submissions/3oPSs/turnitin/resubmit - This should then redirect you to the submission in SpeedGrader - Unmute the assignment - The above URLs should now be in the familiar 'submissions/<submission ID>' form, but work identically - The one change should be that the above links redirect you to the submission details page instead of SpeedGrader APPENDIX: Creating Turnitin originality data: For a given submission: > submission.originality_reports.create!( workflow_state; 'scored', # or 'error' or 'pending' originality_score: 88.0, # 0 = bad, 100 = great originality_report_url: <a custom URL if desired> attachment_id: <specific attachment ID or nil> ) If your assignment involves submitting files, you will need to specify a valid attachment ID for attachment_id; otherwise, leave it blank. APPENDIX 2: A note on Turnitin It is also possible to set up an LTI-based assignment that uses Turnitin but this is not strictly required to view originality scores, and furthermore this author was not sure how to configure it (beyond the directions given in Confluence) to result in anything other than an error when opening it, apparently because we were trying to pass a context_id that was already in use. Change-Id: Ibf14e6c83e77516ae34d2dde409b623e693d5677 Reviewed-on: https://gerrit.instructure.com/175816 Reviewed-by: Gary Mei <gmei@instructure.com> Reviewed-by: Keith Garner <kgarner@instructure.com> Tested-by: Jenkins QA-Review: Gary Mei <gmei@instructure.com> Product-Review: Sidharth Oberoi <soberoi@instructure.com>
2018-12-15 00:46:42 +08:00
get "anonymous_submissions/:anonymous_id/originality_report/:asset_string",
to: "anonymous_submissions#originality_report",
as: :anonymous_submission_originality_report
post "anonymous_submissions/:anonymous_id/turnitin/resubmit",
to: "anonymous_submissions#resubmit_to_turnitin",
as: :anonymous_submission_resubmit_to_turnitin
get "anonymous_submissions/:anonymous_id/turnitin/:asset_string",
to: "anonymous_submissions#turnitin_report",
as: :anonymous_submission_turnitin_report
post "anonymous_submissions/:anonymous_id/vericite/resubmit",
to: "anonymous_submissions#resubmit_to_vericite",
as: :anonymous_submission_resubmit_to_vericite
get "anonymous_submissions/:anonymous_id/vericite/:asset_string",
to: "anonymous_submissions#vericite_report",
as: :anonymous_submission_vericite_report
get :rubric
resource :rubric_association, path: :rubric do
resources :rubric_assessments, path: :assessments
2011-02-01 09:57:29 +08:00
end
get :peer_reviews
post :assign_peer_reviews
delete "peer_reviews/:id" => "assignments#delete_peer_review", :as => :delete_peer_review
post "peer_reviews/:id" => "assignments#remind_peer_review", :as => :remind_peer_review
post "peer_reviews/users/:reviewer_id" => "assignments#assign_peer_review", :as => :assign_peer_review
put "mute" => "assignments#toggle_mute"
collection do
get :syllabus
get :submissions
2011-02-01 09:57:29 +08:00
end
get "lti/resource/:resource_link_id",
controller: "lti/message",
action: "resource",
as: :resource_link_id
get :tool_launch
end
resources :grading_standards, only: %i[index create update destroy]
resources :assignment_groups do
post "reorder" => "assignment_groups#reorder_assignments", :as => :reorder_assignments
collection do
post :reorder
end
end
get "external_tools/sessionless_launch" => "external_tools#sessionless_launch"
resources :external_tools do
match :resource_selection, via: [:get, :post]
get :homework_submission
get :finished
collection do
get :retrieve
end
end
get "lti/resource/:resource_link_id",
controller: "lti/message",
action: "resource",
as: :resource_link_id
get "lti/basic_lti_launch_request/:message_handler_id",
controller: "lti/message",
action: "basic_lti_launch_request",
as: :basic_lti_launch_request
post "lti/tool_proxy_registration", controller: "lti/message", action: "registration", as: :tool_proxy_registration
get "lti/tool_proxy_reregistration/:tool_proxy_id",
controller: "lti/message",
action: "reregistration",
as: :tool_proxy_reregistration
get "lti/registration_return",
controller: "lti/message",
action: "registration_return",
as: :registration_return
resources :submissions
resources :calendar_events
concerns :files, :file_images, :relative_files, :folders
concerns :groups
concerns :pages
concerns :conferences
concerns :question_banks
post "quizzes/publish" => "quizzes/quizzes#publish"
post "quizzes/unpublish" => "quizzes/quizzes#unpublish"
post "assignments/publish/quiz" => "assignments#publish_quizzes"
post "assignments/unpublish/quiz" => "assignments#unpublish_quizzes"
post "quizzes/new" => "quizzes/quizzes#new" # use POST instead of GET (not idempotent)
resources :quizzes, controller: "quizzes/quizzes", except: :new do
get :managed_quiz_data
get :submission_versions
get :history
get :statistics
get :read_only
get :submission_html
resources :quiz_submissions, controller: "quizzes/quiz_submissions", path: :submissions do
collection do
put :backup
post :backup
end
member do
get :record_answer
post :record_answer
end
resources :events, controller: "quizzes/quiz_submission_events", path: "log#{full_path_glob}"
end
post "extensions/:user_id" => "quizzes/quiz_submissions#extensions", :as => :extensions
resources :quiz_questions, controller: "quizzes/quiz_questions", path: :questions, only: %i[create update destroy show]
resources :quiz_groups, controller: "quizzes/quiz_groups", path: :groups, only: %i[create update destroy] do
member do
post :reorder
end
end
match "take" => "quizzes/quizzes#show", :take => "1", :via => [:get, :post]
get "take/questions/:question_id" => "quizzes/quizzes#show", :as => :question, :take => "1"
get :moderate
get :lockdown_browser_required
end
resources :collaborations
get "lti_collaborations" => "collaborations#lti_index"
get "lti_collaborations/*all" => "collaborations#lti_index"
resources :gradebook_uploads
resources :rubrics
resources :rubric_associations do
post "remind/:assessment_request_id" => "rubric_assessments#remind", :as => :remind_assessee
resources :rubric_assessments, path: "assessments"
end
get "outcomes/users/:user_id" => "outcomes#user_outcome_results", :as => :user_outcomes_results
resources :outcomes do
get "alignments/:id" => "outcomes#alignment_redirect", :as => :alignment_redirect
post "alignments" => "outcomes#align", :as => :align
delete "alignments/:id" => "outcomes#remove_alignment", :as => :remove_alignment
get "results" => "outcomes#outcome_results"
get "results/:id" => "outcomes#outcome_result", :as => :result
get :details
collection do
get :list
post :add_outcome
end
end
resources :outcome_groups, only: %i[create update destroy] do
post :reorder
end
resources :context_modules, path: :modules do
post "items" => "context_modules#add_item", :as => :add_item
post "reorder" => "context_modules#reorder_items", :as => :reorder
post "collapse" => "context_modules#toggle_collapse", :as => :toggle_collapse
get "prerequisites/:code" => "context_modules#content_tag_prerequisites_needing_finishing", :as => :prerequisites_needing_finishing
get "items/last" => "context_modules#module_redirect", :as => :last_redirect, :last => 1
get "items/first" => "context_modules#module_redirect", :as => :first_redirect, :first => 1
collection do
post :reorder
get :progressions
end
end
2022-02-16 00:10:48 +08:00
get "blackout_dates" => "blackout_dates#index"
get "course_pacing" => "course_paces#index"
Initial pace plans import This change brings in the basic pace plans frontend with styled-components and several other smaller libraries replaced with InstUI 7 components. It also adds the 'reselect' library as a direct dependency (which we already had through @instructure/outcomes-ui) and 'tsc-files' for type-checking of staged TS files on commit. There were also some tweaks to typescript and eslint configs, mostly to get both up to speed with the typescript code. Finally, this also adds a `pace_plans` endpoint to `courses_controller` to bootstrap the frontend-- this will get moved to `pace_plans_controller` once it has been merged. It's also worth noting that no frontend tests are included with this change-- the existing tests were written with enzyme and are heavily snapshot-based, so we will be replacing those with @testing-library/react tests in later updates (in keeping with current testing best practices at Instructure). closes LS-2431, LS-2432, LS-2433, LS-2434, LS-2452 flag = pace_plans Test plan: - Set up a course with at least one module and several module items - Turn on the pace_plans feature flag in the account associated with that course - Turn on the "Enable pace plans" setting in course settings - Create a pace plan for the course via the Rails console: c = Course.find<id> pp = c.pace_plans.create! workflow_state: 'active' c.context_module_tags.each_with_index do |t, i| pp.pace_plan_module_items.create! module_item: t, duration: i*2 end - Go to the course as a teacher or admin - Expect to see a "Pace Plans" link in the course navigation - Click it, expect the pace plan you created earlier to load and render - Expect to be able to pick dates, change durations, and toggle checkboxes (although saves will fail, since there is no API yet). - Expect to not see the "Pace Plans" course nav link when the feature flag or course setting is off - Expect /courses/<id>/pace_plans to return a 404 when the feature flag or course setting is off - Expect to not see the "Pace Plans" course nav link as a student - Expect /courses/<id>/pace_plans to display an "Unauthorized" page as a student Change-Id: If4dc5d17f2c6a2109d4b4cb652c9e9ef00d7cc33 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/271650 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Ed Schiebel <eschiebel@instructure.com> QA-Review: Ed Schiebel <eschiebel@instructure.com> Product-Review: Jeff Largent <jeff.largent@instructure.com>
2021-08-18 05:14:24 +08:00
post "collapse_all_modules" => "context_modules#toggle_collapse_all"
resources :content_exports, only: %i[create index destroy show]
get "offline_web_exports" => "courses#offline_web_exports"
post "start_offline_web_export" => "courses#start_offline_web_export"
get "start_offline_web_export" => "courses#start_offline_web_export"
get "modules/items/assignment_info" => "context_modules#content_tag_assignment_data", :as => :context_modules_assignment_info
get "modules/items/master_course_info" => "context_modules#content_tag_master_course_data", :as => :context_modules_master_course_info
get "modules/items/:id" => "context_modules#item_redirect", :as => :context_modules_item_redirect
implement cyoe gear option for score-able objects refs CYOE-304 test plan: - there should be no changes in the student view - part 1: - create a new course with cyoe disabled - create two new assignments (one graded, one ungraded), four new quizzes (one graded, one practice, one survey, one graded survey), and two discussions (one graded, one ungraded), one page - create a new module and add the items from above as module items - check the cog menu on the created items and ensure that there is no "Mastery Paths" option in any of the following views: - assignments index page - quizzes index page - discussions index page - all items on the modules page - part 2: - enable cyoe in the course from part 1 - create a new page with "allow in mastery paths" checkbox checked - create a module item for the new page - check the same four index pages as before (assignments, quizzes, discussions, and modules) and make sure that: - the following items have a "Mastery Paths" cog menu option: - the graded assignment - the graded discussion - the graded quiz - clicking on the "Mastery Paths" menu option on any of the above menus navigates to the correct edit page with the mastery paths tab opened on page load - the following items do not have the "Mastery Paths" option: - the ungraded assignment - the ungraded discussion - the practice quiz - the survey - the graded survey - both pages Change-Id: I20c905d764fd3533ae8e68dbd99b7b73fcff81ed Reviewed-on: https://gerrit.instructure.com/91129 Tested-by: Jenkins Reviewed-by: Christian Prescott <cprescott@instructure.com> Reviewed-by: Michael Brewer-Davis <mbd@instructure.com> QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com> Product-Review: Felix Milea-Ciobanu <fmileaciobanu@instructure.com>
2016-09-22 23:23:50 +08:00
get "modules/items/:id/edit_mastery_paths" => "context_modules#item_redirect_mastery_paths"
get "modules/items/:id/choose" => "context_modules#choose_mastery_path"
get "modules/items/sequence/:id" => "context_modules#item_details", :as => :context_modules_item_details
delete "modules/items/:id" => "context_modules#remove_item", :as => :context_modules_remove_item
put "modules/items/:id" => "context_modules#update_item", :as => :context_modules_update_item
get "confirm_action" => "courses#confirm_action"
get :copy, as: :start_copy
post "copy" => "courses#copy_course", :as => :copy_course
concerns :media
get "user_notes" => "user_notes#user_notes"
get "details/sis_publish" => "courses#sis_publish_status", :as => :sis_publish_status
post "details/sis_publish" => "courses#publish_to_sis", :as => :publish_to_sis
resources :user_lists, only: :create
post "invite_users" => "users#invite_users", :as => :invite_users
post "reset" => "courses#reset_content"
resources :alerts
2020-11-07 03:34:38 +08:00
post "student_view(/:redirect_to_referer)" => "courses#student_view", :as => :student_view
delete "student_view" => "courses#leave_student_view"
delete "test_student" => "courses#reset_test_student"
get "content_migrations" => "content_migrations#index"
get "link_validator" => "courses#link_validator", :as => :link_validator
get "grading_schemes" => "grading_schemes_json#detail_list"
get "grading_scheme_summaries" => "grading_schemes_json#summary_list"
post "grading_schemes" => "grading_schemes_json#create"
post "grading_schemes/:id/archive" => "grading_schemes_json#archive"
post "grading_schemes/:id/unarchive" => "grading_schemes_json#unarchive"
delete "grading_schemes/:id" => "grading_schemes_json#destroy"
put "grading_schemes/:id" => "grading_schemes_json#update"
get "grading_schemes/default" => "grading_schemes_json#show_default_grading_scheme"
get "grading_schemes/:id" => "grading_schemes_json#show"
end
get "quiz_statistics/:quiz_statistics_id/files/:file_id/download" => "files#show", :as => :quiz_statistics_download, :download => "1"
resources :page_views, only: :update
post "media_objects" => "media_objects#create_media_object", :as => :create_media_object
get "media_objects/:id" => "media_objects#media_object_inline", :as => :media_object
get "media_objects/:media_object_id/redirect" => "media_objects#media_object_redirect", :as => :media_object_redirect
get "media_objects/:media_object_id/thumbnail" => "media_objects#media_object_thumbnail", :as => :media_object_thumbnail
get "media_objects/:media_object_id/info" => "media_objects#show", :as => :media_object_info
get "media_objects_iframe/:media_object_id" => "media_objects#iframe_media_player", :as => :media_object_iframe
get "media_objects_iframe" => "media_objects#iframe_media_player", :as => :media_object_iframe_href
get "media_objects/:media_object_id/media_tracks/:id" => "media_tracks#show", :as => :show_media_tracks
post "media_objects/:media_object_id/media_tracks" => "media_tracks#create", :as => :create_media_tracks
delete "media_objects/:media_object_id/media_tracks/:id" => "media_tracks#destroy", :as => :delete_media_tracks
post "media_attachments" => "media_objects#create_media_object", :as => :create_media_attachment
get "media_attachments/:attachment_id/thumbnail" => "media_objects#media_object_thumbnail", :as => :media_attachment_thumbnail
get "media_attachments/:attachment_id/info" => "media_objects#show", :as => :media_attachment_info
get "media_attachments_iframe/:attachment_id" => "media_objects#iframe_media_player", :as => :media_attachment_iframe
get "media_attachments/:attachment_id/redirect" => "media_objects#media_object_redirect", :as => :media_attachment_redirect
get "media_attachments/:attachment_id/media_tracks/:id" => "media_tracks#show", :as => :show_media_attachment_tracks
post "media_attachments/:attachment_id/media_tracks" => "media_tracks#create", :as => :create_media_attachment_tracks
delete "media_attachments/:attachment_id/media_tracks/:id" => "media_tracks#destroy", :as => :delete_media_attachment_tracks
get "external_content/success/:service" => "external_content#success", :as => :external_content_success
get "external_content/success/:service/:id" => "external_content#success", :as => :external_content_update
get "external_content/retrieve/oembed" => "external_content#oembed_retrieve", :as => :external_content_oembed_retrieve
get "external_content/cancel/:service" => "external_content#cancel", :as => :external_content_cancel
%w[account course group].each do |context|
prefix = "#{context}s/:#{context}_id"
post "#{prefix}/deep_linking_response", controller: "lti/ims/deep_linking", action: :deep_linking_response, as: "#{context}_deep_linking_response"
end
%w[account course group user].each do |context|
match "#{context.pluralize}/:#{context}_id/external_content/success/:service" => "external_content#success", :as => "#{context}_external_content_success", :via => [:get, :post]
match "#{context.pluralize}/:#{context}_id/external_content/success/:service/:id" => "external_content#success", :as => "#{context}_external_content_update", :via => [:get, :post]
end
2011-02-01 09:57:29 +08:00
# We offer a bunch of atom and ical feeds for the user to get
# data out of Instructure. The :feed_code attribute is keyed
# off of either a user, and enrollment, a course, etc. based on
# that item's uuid. In config/initializers/active_record.rb you'll
# find a feed_code method to generate the code, and in
2011-02-01 09:57:29 +08:00
# application_controller there's a get_feed_context to get it back out.
scope "/feeds" do
get "calendars/:feed_code" => "calendar_events_api#public_feed", :as => :feeds_calendar
get "calendars/:feed_code.:format" => "calendar_events_api#public_feed", :as => :feeds_calendar_format
get "forums/:feed_code" => "discussion_topics#public_feed", :as => :feeds_forum
get "forums/:feed_code.:format" => "discussion_topics#public_feed", :as => :feeds_forum_format
get "topics/:discussion_topic_id/:feed_code" => "discussion_entries#public_feed", :as => :feeds_topic
get "topics/:discussion_topic_id/:feed_code.:format" => "discussion_entries#public_feed", :as => :feeds_topic_format
get "announcements/:feed_code" => "announcements#public_feed", :as => :feeds_announcements
get "announcements/:feed_code.:format" => "announcements#public_feed", :as => :feeds_announcements_format
get "courses/:feed_code" => "courses#public_feed", :as => :feeds_course
get "courses/:feed_code.:format" => "courses#public_feed", :as => :feeds_course_format
get "groups/:feed_code" => "groups#public_feed", :as => :feeds_group
get "groups/:feed_code.:format" => "groups#public_feed", :as => :feeds_group_format
get "enrollments/:feed_code" => "courses#public_feed", :as => :feeds_enrollment
get "enrollments/:feed_code.:format" => "courses#public_feed", :as => :feeds_enrollment_format
get "users/:feed_code" => "users#public_feed", :as => :feeds_user
get "users/:feed_code.:format" => "users#public_feed", :as => :feeds_user_format
get "eportfolios/:eportfolio_id.:format" => "eportfolios#public_feed", :as => :feeds_eportfolio
get "conversations/:feed_code" => "conversations#public_feed", :as => :feeds_conversation
get "conversations/:feed_code.:format" => "conversations#public_feed", :as => :feeds_conversation_format
2011-02-01 09:57:29 +08:00
end
resources :assessment_questions do
get "files/:id/download" => "files#assessment_question_show", :as => :map, :download => "1"
get "files/:id/preview" => "files#assessment_question_show", :preview => "1"
get "files/:id/:verifier" => "files#assessment_question_show", :as => :verified_file, :download => "1"
2011-02-01 09:57:29 +08:00
end
resources :eportfolios, except: :index do
post :reorder_categories
post ":eportfolio_category_id/reorder_entries" => "eportfolios#reorder_entries", :as => :reorder_entries
resources :categories, controller: :eportfolio_categories
resources :entries, controller: :eportfolio_entries do
resources :page_comments, path: :comments, only: [:create, :destroy]
get "files/:attachment_id" => "eportfolio_entries#attachment", :as => :view_file
get "submissions/:submission_id" => "eportfolio_entries#submission", :as => :preview_submission
end
get :export, as: :export_portfolio
get ":category_name" => "eportfolio_categories#show", :as => :named_category
get ":category_name/:entry_name" => "eportfolio_entries#show", :as => :named_category_entry
end
resources :groups do
concerns :users
delete "remove_user/:user_id" => "groups#remove_user", :as => :remove_user
post :add_user
get "accept_invitation/:uuid" => "groups#accept_invitation", :as => :accept_invitation
get "members" => "groups#context_group_members"
get "undelete" => "context#undelete_index", :as => :undelete_items
post "undelete/:asset_string" => "context#undelete_item", :as => :undelete_item
concerns :announcements
concerns :discussions
resources :calendar_events
concerns :files, :file_images, :relative_files, :folders
resources :external_tools, only: :show do
collection do
get :retrieve
end
end
concerns :pages
concerns :conferences
concerns :media
resources :collaborations
get "lti_collaborations" => "collaborations#lti_index"
get "lti_collaborations/*all" => "collaborations#lti_index"
get "calendar" => "calendars#show"
resources :external_tools do
get :finished
match :resource_selection, via: [:get, :post]
collection do
get :retrieve
end
end
end
resources :accounts do
get "search(/:tab)", action: :course_user_search
get "settings#{full_path_glob}", action: :settings
get :reports_tab
get :settings
get :admin_tools
Add eportfolio moderation dashboard flag=eportfolio_moderation closes TALLY-380 Test plan: - Enable the "ePortfolio Moderation" root account release flag - Create a batch of ePortfolios - Have at least one public and one private ePortfolio - The created ePortfolios don't actually need to have any content - In the console, set their spam_status values to a mix of the following: - flagged_as_possible_spam - marked_as_spam - marked_as_safe - (leave a couple of them with no spam_status) - Ensure that you have at least one user with eportfolios that are all either marked_as_safe or have no spam_status - As an admin, log in to Canvas and open the Admin view for your account - With the feature flag on, the left-hand links should include an "ePortfolio Moderation" link - Clicking the link should bring you to a table showing all the ePortfolios for which you set a non-null status above - Check that: - Entries in the table are grouped by author - Entries per user appear in the following order - "Needs review: flagged as possible spam" - ...followed by "Marked as spam" - ...followed by "Marked as safe" - (entries with no spam_status should not be shown) - Clicking on a user brings you to that user's profile page - Clicking on an ePortfolio link brings you to that portfolio - The specific user you created above whose portfolios are all safe or unclassified does *not* have any results in the list Change-Id: I6f784f34eb47e479a560288ffac28efa967b826d Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/220676 Tested-by: Jenkins Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Adrian Packel <apackel@instructure.com> Reviewed-by: Nick Pitrak <npitrak@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Jonathan Fenton <jfenton@instructure.com>
2019-12-13 07:01:21 +08:00
get :eportfolio_moderation
get "search" => "accounts#course_user_search", :as => :course_user_search
post "account_users" => "accounts#add_account_user", :as => :add_account_user
delete "account_users/:id" => "accounts#remove_account_user", :as => :remove_account_user
resources :grading_standards, only: %i[index create update destroy]
get :statistics
get "statistics/over_time/:attribute" => "accounts#statistics_graph", :as => :statistics_graph
get "statistics/over_time/:attribute.:format" => "accounts#statistics_graph", :as => :formatted_statistics_graph
get :turnitin_confirmation
get :vericite_confirmation
resources :permissions, controller: :role_overrides, only: [:index, :create] do
collection do
post :add_role
delete :remove_role
end
end
get "calendar_settings", action: :account_calendar_settings, as: :calendar_settings
scope(controller: :analytics_hub) do
get "analytics_hub", action: :show, as: :analytics_hub
end
subaccount branding (creation and trickle down) fixes CNVS-21426 changes theme_editor routes to nest under accounts show correct brand_config for subaccount be able to theme subaccounts parent account changes trickle down to subs theme editor default values are that of parent account add not in preview text that subaccounts dont show test plan: simple creation - create a sub-account - brand it differently from parent - if you go to courses belonging to this subaccount, it gets their css - if you go to courses belonging to the parent you get the parent css - if you go to a user dashboard you get the parent branding (maybe we can add smarts to this later in case you only are in the subaccount?) trickle down - rebrand two values on the parent - one that the subaccount explicitly sets - and one that doesnt - apply this config on the parent - wait a little and go to the child account - its theme inherits values for the parent, but... if it explicitly sets those values itself then it doesnt inherit it - go to the editor for the subaccount - the placeholder values are those of the parent account (or the canvas default if the parent hasnt set it) - test trickle down with a sub-account and a sub-sub-account still to do on different patch sets: - account settings to allow subaccount branding - show the progress of all the child compilation Change-Id: Iaddba7036f564965427807c2fd8b0a6a5d524366 Reviewed-on: https://gerrit.instructure.com/61285 Reviewed-by: Rob Orton <rob@instructure.com> QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com> Product-Review: Colleen Palmer <colleen@instructure.com>
2015-08-15 02:42:55 +08:00
scope(controller: :brand_configs) do
get "theme_editor", action: :new, as: :theme_editor
All of the stuff from the save_a_theme dev branch this commit is the result of squashing a bunch of others together. this is everything that was already on the dev/save_a_theme branch as well as the "Add specs" commit. I left the test plans from some of the squashed commits in case they are helpful for QA Test plan: - Recompile assets, restart Canvas and clear browser cache - Go to Admin > [Your school name] - Click on Themes in the context menu - You should now see a collections page with a theme card for all the themes you have in Theme Editor: http://screencast.com/t/lb5vozF7 - Note: it might be my database, but on my end, I don't see a theme card for my Canvas default theme. There are also some brand colors missing for my theme cards. I'll be interested to see if you hit the same thing. These are issues that we can resolve with Ryan when he is back. - You should be able to click on the Apply and Delete buttons and see the confirm-overlays. We still need final copy for these. Test plan: - Go to your institution's Settings page and click Themes on the context menu. - You should now see a page listing all the default and user-created themes in your Canvas installation. - Clicking on each theme will open it inside theme editor. - The current/active theme will be correctly styled with a green outline change redirect targets and messages in theme editor test plan: exiting theme editor should redirect you back to the /accounts/x/themes page instead of /acounts/x make room for footer in theme editor test plan: in theme editor, scroll the preview to the bottom you should be able to scroll all the way, without having the bottom cut off by the footer remove "theme editor" button from account user/course search this is not needed since "Themes" now shows up in the left nav. test plan: turn on the 'Course and User Search' feature flag go to accounts/x you should not see a "theme editor" button on the right aka, not like this: http://cl.ly/2G2C3p3s3n0C fix "Exit" button in theme editor we were warning "you will lose unsaved changes" even when you hand not made any changes add specs to "Save A theme" stuff closes: CNVS-27961 test plan: do a whole regression test on the theme editor don't show both "k12 theme" and "canvas default" as options fixes: CNVS-25495 description (and test plan): if you are a k12 school, rather than seeing both "Canvas Default" and "K12 Theme" as options on the tiles of system themes to start from, you should now just see "Canvas Default". if you pick that, it should show the k12 theme. Change-Id: I5c2512e576dcb2aedaa899e17080d9c106e159ca Reviewed-on: https://gerrit.instructure.com/78163 Tested-by: Jenkins Reviewed-by: Rob Orton <rob@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com> QA-Review: Ryan Shaw <ryan@instructure.com>
2016-01-19 03:29:32 +08:00
get "brand_configs", action: :index
subaccount branding (creation and trickle down) fixes CNVS-21426 changes theme_editor routes to nest under accounts show correct brand_config for subaccount be able to theme subaccounts parent account changes trickle down to subs theme editor default values are that of parent account add not in preview text that subaccounts dont show test plan: simple creation - create a sub-account - brand it differently from parent - if you go to courses belonging to this subaccount, it gets their css - if you go to courses belonging to the parent you get the parent css - if you go to a user dashboard you get the parent branding (maybe we can add smarts to this later in case you only are in the subaccount?) trickle down - rebrand two values on the parent - one that the subaccount explicitly sets - and one that doesnt - apply this config on the parent - wait a little and go to the child account - its theme inherits values for the parent, but... if it explicitly sets those values itself then it doesnt inherit it - go to the editor for the subaccount - the placeholder values are those of the parent account (or the canvas default if the parent hasnt set it) - test trickle down with a sub-account and a sub-sub-account still to do on different patch sets: - account settings to allow subaccount branding - show the progress of all the child compilation Change-Id: Iaddba7036f564965427807c2fd8b0a6a5d524366 Reviewed-on: https://gerrit.instructure.com/61285 Reviewed-by: Rob Orton <rob@instructure.com> QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com> Product-Review: Colleen Palmer <colleen@instructure.com>
2015-08-15 02:42:55 +08:00
post "brand_configs", action: :create
delete "brand_configs", action: :destroy
post "brand_configs/save_to_account", action: :save_to_account
post "brand_configs/save_to_user_session", action: :save_to_user_session
end
resources :role_overrides, only: [:index, :create] do
collection do
post :add_role
delete :remove_role
end
end
add pagination to terms page Fixes support week bug ticket where libertyuniversity had 500-ish terms which was producing 504 gateway time-out error on beta. Adding paging to the terms page to fix this issue. Changes of note: - terms displayed per page: 20 - search terms input added at top of page - search terms query looks at name of term only (e.g. “term 22”) - “Add New Term” button moved to top of page - terms pagination shows at bottom of terms results list - term_name query string add to terms API controller refs FOO-3630 flag=none test plan: - log in as admin and visit admin > terms: 1. confirm that there are no pagination links at bottom of terms list 2. confirm that there is a single “Default Term” (can not be deleted) 3. confirm that “Add New Term” button is displayed at top-right 4. add a total 20 terms (including the default term) - refresh the page 1. confirm that there are no pagination links at bottom of terms list 2. add 1 more term - refresh page: 1. confirm that pagination links are displayed at bottom of terms list 2. confirm that the “previous” link is DISABLED 3. confirm that the current page number “1” is DISABLED 4. confirm that the next page number “2” is ENABLED 5. confirm that the “next” link is ENABLED - click “next” link to go to second page of terms: 1. confirm that the “next” link is DISABLED 2. confirm that the current page number “2” is DISABLED 3. confirm that the previous page number “1” is ENABLED 4. confirm that the “previous” link is ENABLED - search for an EXISTING term (yielding 1 result): 1. confirm that the search term is displayed in the terms list 2. confirm that the pagination links are NOT displayed 3. confirm that ”View all terms” is next to the search button 4. confirm that search input contains the search query terms 5. click the “View all terms” link 6. confirm that the page returns to the first page of terms - search for a NON-EXISTING term (yielding 0 results): 1. confirm that a no-results message appears - search for an EXISTING set of terms (yielding 21+ results): 1. confirm that the pagination links are displayed - see FOO-3630 for more details Change-Id: Ib36d4ed843dddb74a704678f80a59b732a9de361 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/322825 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Michael Hulse <michael.hulse@instructure.com> Reviewed-by: August Thornton <august@instructure.com> QA-Review: Michael Hulse <michael.hulse@instructure.com> Product-Review: Michael Hulse <michael.hulse@instructure.com>
2023-07-16 12:56:58 +08:00
resources :terms, except: %i[index new show edit]
# handle the index route using terms_api_controller
get "terms", controller: :terms_api, action: "index"
resources :sub_accounts
resources :calendar_events
get :avatars
get :sis_import
resources :sis_imports, only: %i[create show index], controller: :sis_imports_api
get "users" => "accounts#users", :as => "users"
post "users" => "users#create", :as => :add_user
get "users/:user_id/delete" => "accounts#confirm_delete_user", :as => :confirm_delete_user
delete "users/:user_id" => "accounts#remove_user", :as => :delete_user
clean up user "deletion" fixes CNVS-1552 any time the UI/API tries to "delete" a user, it should only be trying to remove it from some root account (the @domain_root_account if not otherwise specified). if that root account was the last root account the user was associated with, then the remnants of the user are fully deleted, but only then. leave User#destroy as a short-cut to delete the user from all their accounts at once, but should not be invoked directly from any UI/API actions. test-plan: PERMISSIONS being able to remove a user from an account entails being able to: - DELETE http://accounts-domain/users/:user - DELETE /accounts/:account/users/:user both should fail or succeed together * given - Sally who's an admin with the :manage_user_logins permission on one account (Account1) and a student on another account (Account2) - Bob who's a student on both accounts - Alice who's an admin on Account1 with greater permissions than Sally * Sally should: - see "Delete My Account" on her Account1 profile - not see "Delete My Account" on her Account2 profile - not see "Delete My Account" on Bob's Account1 profile - not see "Delete My Account" on Alice's Account1 profile - see "Delete from Account1" at /users/:sally - see "Delete from Account1" at /users/:bob - not see "Delete from Account2" at /users/:sally - not see "Delete from Account2" at /users/:bob - not see "Delete from Account1" at /users/:alice - be able to remove herself from Account1 - be able to remove Bob from Account1 - not be able to remove herself from Account2 - not be able to remove Bob from Account2 - not be able to remove Alice from Account1 * given Sally's Account1 pseudonym has a SIS ID but her Account2 pseudonym doesn't, Sally should: - no longer see "Delete My Account" on her Account1 profile - no longer see "Delete from Account1" at /users/:sally - still see "Delete from Account1" at /users/:bob - no longer be able to remove herself from Account1 - still be able to remove Bob from Account1 EFFECTS * as Sally, remove Bob from Account1 via DELETE http://account1-domain/users/:bob - Bob's pseudonyms, enrollments, etc. in Account1 should be removed - Bob's pseudonyms, enrollments, etc. in Account2 should be untouched * repeat using DELETE /accounts/:account1/users/:bob, with the same expectations Change-Id: Ib7612f95d1c7e4cca36d8486950565ec096b4ab1 Reviewed-on: https://gerrit.instructure.com/41591 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: August Thornton <august@instructure.com> Reviewed-by: Cody Cutrer <cody@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2014-09-23 07:04:03 +08:00
# create/delete are handled by specific routes just above
resources :users, only: %i[new edit show update]
resources :account_notifications, only: %i[create update destroy]
concerns :announcements
resources :submissions
put "sso_settings" => "authentication_providers#update_sso_settings",
refactor views for unified AAC administration closes CNVS-20076 First, pull a presenter out of the AAC index This thing needs more flexibility before introducing multiple OAuth connectors. This commit adds a couple characterization specs for the AAC controller, then drives out a presenter to pull as much logic and config out of the nested views as possible. Then, this commit refactors the previously-somewhat-bespoke-and-presumptive sac configuration into a workflow that shows each aac in turn according to it's type, creating forms for each type at the bottom, and showing the relevant form for a new one based on selection on the right. Have regression tested in the browser to the level of CRUD functionality, but also deserves solid QA for SSO functionality post-configuration. DONE: -successful CAS creation/editing/deletion -successful LDAP creation/editing/deletion -proper differentiation between LDAP primary and secondary -proper SAML creation/editing -move away from "update_all" deprecated endpoint -Selenium Spec fixes -ensure discovery URL and debugging workflows for saml -remove duplication from views -tear down old JS workflow -apply appropriate tests for new behavior -remove presenter methods that are no longer valuable -Moved change_password_url and login_handle_name -up to account settings, removed them from AACs, and built -migrations to manage the transition. -Found and fixed all references to change_password_url on AACs -Found and fixes all references to login_handle_name on AACs -add datafixup for migrating AAC data to account settings -unify repetative individual files into single form delcarations \o/ -remove old SAML editing js -Make sure SAML still works -Make LDAP partial flow just like SAML/CAS -Unify position information across all types -update "acts_as_list" to support STI classes -move discovery URL into account auth form -remove discover URL js management -Unify form generation between new/existing aacs -deprecate discovery url API endpoints -update docs for authorization settings to deprecate their usage in AAC api and redirect their values to current settings for now -make delete links non-js-y to stop this silly page refresh on api completion -make form submissions actually submit the form rather than do this silly page refresh on api completion -See if anything needs “Edit Details” button, remove if not -Wire up removing account settings by blanking out form -Removed "cancel" button from form because fields are always open -placate gergich -Test removing config info -Test population fixup on real data -write docs for authorization settings -fix existing specs -fix routing and docs to not break doc generation -fix stupid jenkins task that thinks it can’t see controls -re-fix selenium -fix saml debugging workflow -write tests for acts_as_list behavior -write tests for authorization settings -remove auth_info types of things -clean up and unify styles where possible TEST PLAN: Regression test creating/deleting/editing and logging in with SSO solutions for CAS, LDAP, and SAML. Should be no functional behavior modification, though workflow will be a little more unified between the 3 currently supported types (each one will require using the menu in the right sidebar to add a new AAC). Also test setting and deleting account settings through the form underneath the configs when there are AACs in existence. Finally, make sure that the SAML Debugging workflow still works. Change-Id: I448db10185512d1b9469c2a425be0a3bcf9e6ebf Reviewed-on: https://gerrit.instructure.com/53448 Tested-by: Jenkins Reviewed-by: Cody Cutrer <cody@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Ethan Vizitei <evizitei@instructure.com>
2015-04-28 05:23:04 +08:00
:as => :update_sso_settings
delete "authentication_providers" => "authentication_providers#destroy_all", :as => :remove_all_authentication_providers
resources :authentication_providers, only: %i[show] do
get :refresh_metadata, action: :refresh_saml_metadata
end
resources :authentication_providers, only: %i[index create update destroy] do
get :debugging, action: :debug_data
put :debugging, action: :start_debugging
delete :debugging, action: :stop_debugging
end
get "test_ldap_connections" => "authentication_providers#test_ldap_connection"
get "test_ldap_binds" => "authentication_providers#test_ldap_bind"
get "test_ldap_searches" => "authentication_providers#test_ldap_search"
match "test_ldap_logins" => "authentication_providers#test_ldap_login", :via => [:get, :post]
get "external_tools/sessionless_launch" => "external_tools#sessionless_launch"
resources :external_tools do
get :finished
match :resource_selection, via: [:get, :post]
collection do
get :retrieve
end
end
get "lti/resource/:resource_link_id",
controller: "lti/message",
action: "resource",
as: :resource_link_id
get "lti/basic_lti_launch_request/:message_handler_id",
controller: "lti/message",
action: "basic_lti_launch_request",
as: :basic_lti_launch_request
post "lti/tool_proxy_registration", controller: "lti/message", action: "registration", as: :tool_proxy_registration
get "lti/tool_proxy_reregistration/:tool_proxy_id",
controller: "lti/message",
action: "reregistration",
as: :tool_proxy_reregistration
get "lti/registration_return",
controller: "lti/message",
action: "registration_return",
as: :registration_return
get "outcomes/users/:user_id" => "outcomes#user_outcome_results", :as => :user_outcomes_results
resources :outcomes do
get "results" => "outcomes#outcome_results"
get "results/:id" => "outcomes#outcome_result", :as => :result
get "alignments/:id" => "outcomes#alignment_redirect", :as => :alignment_redirect
get :details
collection do
get :list
post :add_outcome
end
end
resources :outcome_groups, only: %i[create update destroy] do
post :reorder
end
resources :rubrics
resources :rubric_associations do
resources :rubric_assessments, path: "assessments"
end
concerns :files, :file_images, :relative_files, :folders
concerns :media
concerns :groups
resources :outcomes
get :courses
get "courses/:id" => "accounts#courses_redirect", :as => :courses_redirect
get "user_notes" => "user_notes#user_notes"
resources :alerts
resources :question_banks do
post :bookmark
post :reorder
get :questions
post :move_questions
resources :assessment_questions
end
resources :user_lists, only: :create
member do
get :statistics
end
resources :developer_keys, only: :index
get "/developer_keys/:key_id", controller: :developer_keys, action: :index, as: "account_developer_key_view"
get "extensions", controller: "lti/registrations", action: :index, as: "lti_registrations"
get "extensions/*path", controller: "lti/registrations", action: :index
get "extensions/manage", controller: "lti/registrations", action: :index, as: "lti_manage_registrations"
get "release_notes" => "release_notes#manage", :as => :release_notes_manage
2022-02-16 00:10:48 +08:00
get "blackout_dates" => "blackout_dates#index"
get "grading_schemes" => "grading_schemes_json#detail_list"
get "grading_scheme_summaries" => "grading_schemes_json#summary_list"
get "grading_scheme_grouped" => "grading_schemes_json#grouped_list"
post "grading_schemes/:id/archive" => "grading_schemes_json#archive"
post "grading_schemes/:id/unarchive" => "grading_schemes_json#unarchive"
post "grading_schemes" => "grading_schemes_json#create"
delete "grading_schemes/:id" => "grading_schemes_json#destroy"
put "grading_schemes/:id" => "grading_schemes_json#update"
get "grading_schemes/:id/used_locations" => "grading_schemes_json#used_locations", :as => :grading_schemes_used_locations
get "grading_schemes/default_used_locations" => "grading_schemes_json#default_used_locations", :as => :grading_schemes_default_used_locations
get "grading_schemes/default" => "grading_schemes_json#show_default_grading_scheme"
get "grading_schemes/:id" => "grading_schemes_json#show"
get "grading_settings" => "account_grading_settings#index"
get "grading_settings/*path" => "account_grading_settings#index"
2011-02-01 09:57:29 +08:00
end
get "images/users/:user_id" => "users#avatar_image", :as => :avatar_image
get "images/thumbnails/:id/:uuid" => "files#image_thumbnail", :as => :thumbnail_image
get "images/thumbnails/show/:id/:uuid" => "files#show_thumbnail", :as => :show_thumbnail_image
post "images/users/:user_id/report" => "users#report_avatar_image", :as => :report_avatar_image
put "images/users/:user_id" => "users#update_avatar_image", :as => :update_avatar_image
get "grades" => "users#grades"
feature flag for 'All Grading Periods' totals Add grading period dropdowns on the 'grades' page, and add a "Display Totals for 'All Grading Periods'" feature flag. By default, the feature will be turned 'off'. When the feature is 'off': - Totals will not display in the gradebook or the 'student grades' page when the 'All Grading Periods' option is selected. - The grading period dropdowns on the 'grades' page will not have an 'All Grading Periods' option. When the feature is 'on': - Totals will display in the gradebook and the 'student grades' page when the 'All Grading Periods' option is selected. - The grading period dropdowns on the 'grades' page will have an 'All Grading Periods' option. closes CNVS-23995 test plan: 1) as a teacher, enable the 'multiple grading periods' feature (do not enable the 'display totals for all grading periods' feature yet). a) verify the gradebook does not show totals when the 'All Grading Periods' option is selected. b) verify the 'student grades page' (courses/4/grades/9#tab-assignments) does not show totals, and the calculation of 'what-if' grades is disabled when the 'All Grading Periods' option is selected. c) turn on the 'display totals for all grading periods' feature. repeat steps a & b and verify that the totals now show up (and you can calculate what-if grades on the student grades page when 'All Grading Periods is selected') 2) sign in as a student that is enrolled in 3 courses: 1 course with MGP disabled, 1 course with MGP enabled and 'display all grading periods totals' (DAGPT) disabled, and 1 course with MGP enabled and DAGPT enabled. go the the 'grades' page (/grades). a) verify there is a grading period dropdown next to the totals for courses that have MGP enabled. verify there is not a grading period dropdown next to the total for the course with MGP disabled. b) verify that the current grading period is selected by default, if one exists. if a current grading period does not exist, then: - the dropdown next to the total for the course with DAGPT disabled should show 'Select a grading period' and the total grade should show as '--'. - the dropdown next to the total for the course with DAGPT enabled should show 'All Grading Periods' and the total grade should be displayed. c) verify clicking a grading period in the dropdown changes the total, and shows the correct total for that grading period. 3) repeat steps 2a-c, but sign in as an observer that is observing at least 3 students in 3 different courses(1 course with MGP disabled, 1 with MGP enabled and DAGPT disabled, and 1 course with MGP enabled + DAGPT enabled). 4) verify that the grading period dropdowns that were added are accessible. Note: The 'grades' page (/grades) will _always_ display the total for 'All Grading Periods' when signed in as a teacher. We are aware of this existing bug and we're working on a solution. Change-Id: If501b47aa57121d17d4e6629d1dcdbc8676971a2 Reviewed-on: https://gerrit.instructure.com/65847 Tested-by: Jenkins Reviewed-by: Strand McCutchen <smccutchen@instructure.com> Reviewed-by: Dylan Ross <dross@instructure.com> Reviewed-by: Derek Bender <djbender@instructure.com> QA-Review: Jason Carter <jcarter@instructure.com> Product-Review: Spencer Olson <solson@instructure.com>
2015-10-14 03:20:03 +08:00
get "grades_for_student" => "users#grades_for_student"
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login" => "login#new"
get "login/session_token" => "login#session_token", :as => :login_session_token
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
delete "logout" => "login#destroy"
get "logout" => "login#logout_landing"
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login/canvas" => "login/canvas#new", :as => :canvas_login
post "login/canvas" => "login/canvas#create"
get "login/email_verify" => "login/email_verify#show", :as => :login_email_verify_show
post "login/email_verify" => "login/email_verify#verify", :as => :login_email_verify
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login/ldap" => "login/ldap#new"
post "login/ldap" => "login/ldap#create"
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login/cas" => "login/cas#new"
get "login/cas/:id" => "login/cas#new", :as => :cas_login
post "login/cas" => "login/cas#destroy", :as => :cas_logout
post "login/cas/:id" => "login/cas#destroy"
get "login/saml" => "login/saml#new", :as => :saml_login_base
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login/saml/logout" => "login/saml#destroy"
post "login/saml/logout" => "login/saml#destroy"
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
# deprecated alias
get "saml_logout" => "login/saml#destroy"
get "login/saml/:id" => "login/saml#new", :as => :saml_login
Register Parents and Add Observees when configured for SAML authentication Fixes PFS-1084 Parent Registration: When a Saml config is designated for Parent Registration the parent signing up will be redirected to a Saml login page where they will log in with their child's credentials. After login the child user's Saml session will be ended and the parent registration process will complete. Parent Adding Student: When a Saml config is designated for Parent Registration the parent adding another observee will be redirected to a Saml login page where they will log in with their child's credentials. After login the child user's Saml session will be ended and the observee creation process will complete. --------------------------------------- TEST PLAN: SETUP: 1) In your account settings check the box for 'Self Registration' (and either of the sub-options) 2) Add the following users to your account (these will be the students): billyjoel eltonjohn 3) In Authentication Settings add a SAML authentication service and enter the following fields (I've set up a remote SAML Idp): IdP Entity ID: http://107.170.212.143/saml2/idp/metadata.php Log On URL: http://107.170.212.143/simplesaml/saml2/idp/SSOService.php Log Out URL: http://107.170.212.143/simplesaml/saml2/idp/SingleLogoutService.php Certificate Fingerprint: 9C:11:68:93:95:CD:18:01:EC:52:2B:9E:22:7F:73:55:ED:6D:82:D4 Parent Registration: check TEST: Parent Registration: * Go to '/login/canvas' * Click on the signup banner * sign up as a parent for billyjoel or eltonjohn (on SAML login page the password for either user is: tantrum) Add Student: * Log in as a parent user w/ a Canvas Auth login * Go to '/profile/observees' * Add Student 'billyjoel' or 'eltonjohn' Authentication Settings (new parent reg checkbox): * Go to Authentication Settings * Add a second SAML config * check the parent registration checkbox - it should warn that selection will deselect the other and in fact do so upon save. - the selected config is the one used for parent reg/add student --------------------------------------- Change-Id: Ief83b604fc252c88dbb912c56de65d8620fe802f Reviewed-on: https://gerrit.instructure.com/49691 Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Reviewed-by: Jacob Fugal <jacob@instructure.com> Product-Review: Ethan Vizitei <evizitei@instructure.com>
2015-03-03 01:41:17 +08:00
get "saml_observee" => "login/saml#observee_validation", :as => :saml_observee
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
post "login/saml" => "login/saml#create"
# deprecated alias; no longer advertised
post "saml_consume" => "login/saml#create"
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login/saml_idp_discovery" => "login/saml_idp_discovery#new"
get "login/saml_idp_discovery/:id" => "login/saml_idp_discovery#new", :as => :saml_idp_discovery_login
# the callback URL for all OAuth1.0a based SSO
get "login/oauth/callback" => "login/oauth#create", :as => :oauth_login_callback
# the callback URL for all OAuth2 based SSO
get "login/oauth2/callback" => "login/oauth2#create", :as => :oauth2_login_callback
# the callback URL for Sign in with Apple
post "login/oauth2/callback" => "login/oauth2#create"
# ActionController::TestCase can't deal with aliased controllers when finding
# routes, so we let this route exist only for tests
get "login/oauth2" => "login/oauth2#new" if Rails.env.test?
get "login/apple" => "login/apple#new", :as => :apple_login
get "login/clever" => "login/clever#new", :as => :clever_login
# Clever gets their own callback, cause we have to add additional processing
# for their Instant Login feature
get "login/clever/callback" => "login/clever#create", :as => :clever_callback
get "login/clever/:id" => "login/clever#new"
get "login/facebook" => "login/facebook#new", :as => :facebook_login
get "login/github" => "login/github#new", :as => :github_login
get "login/google" => "login/google#new", :as => :google_login
get "login/google/:id" => "login/google#new"
get "login/linkedin" => "login/linkedin#new", :as => :linkedin_login
Add Microsoft Login Commit from Siimpl Fixes OI-3, OI-4 test plan: * register an application with Microsoft * configure microsoft as an authentication source * login with microsoft * it should complain about a missing user for an ID * add that ID to your user * login again, it should work * delete microsoft authentication * reconfigure at /plugins/microsoft * add authentication again; this time it shouldn't let you configure the integration * login with microsoft again * change to email attribute * login and it should show your e-mail, instead of an opaque ID * change tenant to "organizations" * login with a regular Microsoft account * it should give an error about not being able to log in * login with an organization account (@instructure.com works) * it should show your email * change tenant to "consumers" * login with your regular Microsoft account; it should work * login with an organization account; it should give an error NOTE: Microsoft requires https. so if you're testing locally, and don't have https, you'll need to change oauth2_controller.rb and add (protocol: 'https') to both oauth2_login_callback_url calls; during the login flow it will redirect you back to the app over https; edit the url and connect to http and it will work Change-Id: I578df7c2865b8775752ead28a1153918cd24aaa6 Reviewed-on: https://gerrit.instructure.com/72971 Tested-by: Jenkins Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Andrew Butterfield <abutterfield@instructure.com>
2016-02-19 02:53:10 +08:00
get "login/microsoft" => "login/microsoft#new"
get "login/microsoft/:id" => "login/microsoft#new", :as => :microsoft_login
get "login/openid_connect" => "login/openid_connect#new"
get "login/openid_connect/:id" => "login/openid_connect#new", :as => :openid_connect_login
get "login/twitter" => "login/twitter#new", :as => :twitter_login
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
get "login/otp" => "login/otp#new", :as => :otp_login
post "login/otp/sms" => "login/otp#send_via_sms", :as => :send_otp_via_sms
post "login/otp" => "login/otp#create"
get "users/self/otps" => "one_time_passwords#index", :as => :one_time_passwords
delete "users/self/otps" => "one_time_passwords#destroy_all", :as => :destroy_all_one_time_passwords
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
# deprecated redirect
get "login/:id" => "login#new"
refactor PseudonymSessionsController fixes CNVS-20394 split it into appropriate concerns. main points are: * /login never renders a login form - it redirects forward to the default auth controller based on the first account authorization config (or discovery url on the account) * /login/canvas is the new home of the old login form. this form is never rendered in-situ anymore - other places that used to render it now redirect to /login (and then forward to here), reducing their knowledge of SSO * /login/ldap ends up at the same place (cause LDAP auth is handled transparently) * /login/cas and /login/saml redirect forward to the first SSO configuration of the appropriate type. /login/:auth_type/:id can be used to select a specific one * if an SSO fails, it redirects back to /login with flash[:error] set. this can forward to the discovery url appropriately, or render an error page appropriately (the old no_auto=1, but now it's not layered on top of the login partial that didn't show a login form) * ?canvas_login=1 is deprecated. just go directly to /login/canvas * /saml_consume, /saml_logout are deprecated. they are processed directly by /login/saml and /login/saml/logout * /login/:id is deprecated - it forwards to /login/:auth_type/:id as appropriate (presumably only saml, since that was the only one that previously should have been using these links) * OTP has been split into its own controller, and separated into multiple actions instead of one all-in-one action * /logout has been vastly simplified. the login controller should set session[:login_aac], and on logout it will check with that AAC for a url to redirect to after logout, instead of /login. SSO logout is handled by each controller if they support it test plan: * regression test the following functionality - * login with canvas auth * login with LDAP auth * login with SAML auth - and multiple SAMLs * login with CAS auth * MFA (configure, using, auto-setup) * Canvas as OAuth Provider flow * redirects to the login page when you're not logged in * failure of SAML/CAS (i.e. can't find user) show a decent error page and allows retry * "sticky" site admin auth (site admin is CAS/SAML, going directly to another domain logs you in with site admin) Change-Id: I1bb9d81a101939f812cbd5020e20749e883fdc0f Reviewed-on: https://gerrit.instructure.com/53220 QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
2015-05-01 03:58:57 +08:00
delete "users/:user_id/mfa" => "login/otp#destroy", :as => :disable_mfa
get "file_session/clear" => "login#clear_file_session", :as => :clear_file_session
get "register" => "users#new"
get "register_from_website" => "users#new"
get "enroll/:self_enrollment_code" => "self_enrollments#new", :as => :enroll
get "services" => "users#services"
get "search/bookmarks" => "users#bookmark_search", :as => :bookmark_search
get "search/rubrics" => "search#rubrics"
get "search/all_courses" => "search#all_courses"
resources :users, except: [:destroy, :index] do
match "masquerade", via: [:get, :post]
concerns :files, :file_images
resources :page_views, only: :index
resources :folders do
get :download
end
resources :calendar_events
get "external_tools/:id" => "users#external_tool", :as => :external_tool
resources :rubrics
resources :rubric_associations do
resources :rubric_assessments, path: :assessments
end
resources :pseudonyms, except: :index
resources :question_banks, only: :index
get :admin_merge
get :admin_split
post :merge
get :grades
resources :user_notes
get :manageable_courses
get "outcomes" => "outcomes#user_outcome_results"
get "teacher_activity/course/:course_id" => "users#teacher_activity", :as => :course_teacher_activity
get "teacher_activity/student/:student_id" => "users#teacher_activity", :as => :student_teacher_activity
get :media_download
resources :messages, only: %i[index create show] do
get :html_message
end
2011-02-01 09:57:29 +08:00
end
resources :users, only: [:passport] do
get "passport" => "learner_passport#index"
get "passport/data/achievements" => "learner_passport#achievements_index"
get "passport/data/portfolios" => "learner_passport#portfolios_index"
put "passport/data/portfolios/create" => "learner_passport#portfolio_create"
post "passport/data/portfolios/:portfolio_id" => "learner_passport#portfolio_update"
get "passport/data/portfolios/show/:portfolio_id" => "learner_passport#portfolio_show"
put "passport/data/portfolios/duplicate" => "learner_passport#portfolio_duplicate"
put "passport/data/portfolios/delete" => "learner_passport#portfolio_delete"
get "passport/data/projects" => "learner_passport#projects_index"
put "passport/data/projects/create" => "learner_passport#project_create"
post "passport/data/projects/:project_id" => "learner_passport#project_update"
get "passport/data/projects/show/:project_id" => "learner_passport#project_show"
put "passport/data/projects/duplicate" => "learner_passport#project_duplicate"
put "passport/data/projects/delete" => "learner_passport#project_delete"
get "passport/data/pathways" => "learner_passport#pathways_index"
get "passport/data/pathways/badges" => "learner_passport#pathway_badges_index"
get "passport/data/pathways/learner_groups" => "learner_passport#pathway_learner_groups_index"
get "passport/data/pathways/canvas_requirements" => "learner_passport#pathway_canvas_requirements_index"
put "passport/data/pathways/create" => "learner_passport#pathway_create"
post "passport/data/pathways/:pathway_id" => "learner_passport#pathway_update"
get "passport/data/pathways/show/:pathway_id" => "learner_passport#pathway_show"
get "passport/data/pathways/share_users" => "learner_passport#pathway_share_users"
get "passport/data/skills" => "learner_passport#skills_index"
get "passport/data/reset" => "learner_passport#reset"
get "passport/*path" => "learner_passport#index"
end
get "show_message_template" => "messages#show_message_template"
get "message_templates" => "messages#templates"
resource :profile, controller: :profile, only: [:show, :update] do
resources :pseudonyms, except: :index
resources :tokens, except: :index
member do
put :update_profile
get :communication
put :communication_update
get :settings
get :content_shares
get :observees
end
2011-02-01 09:57:29 +08:00
end
get "account_notifications" => "account_notifications#render_past_global_announcements"
scope "/profile" do
post "toggle_disable_inbox" => "profile#toggle_disable_inbox"
get "profile_pictures" => "profile#profile_pics", :as => :profile_pics
Add QR for Mobile Login link to /profile routes closes USERS-458 flag=mobile_qr_login This commit changes how we're adding the link to render the mobile QR code modal. We're going to be using the profile tab approach instead of adding it directly to the global profile tray. This will allow it to exist not only in the global profile tray, but the user profile, and even the global mobile nav. The QR for mobile link tab will show up for any active path under '/profile' Test Plan: - Ensure your version of canvas has an up to date instructure_misc_plugin - create a developer key - add https://sso.canvaslms.com/canvas/login as its only redirect URI - In a rails console - a = Account.default - a.settings[:ios_mobile_sso_developer_key_id] = <dev key global id> - a.save! - a.account_domains.create!(name: 'sso.canvaslms.com') With the :mobile_qr_login feature flag enabled: *Web View* - Navigate to '/' - Open the profile tray and click 'QR for Mobile Login' - Ensure the QR code image is generated with the title and expire tag - Navigate to '/profile' - Click on 'QR for Mobile Login' on the left hand side section tabs - Ensure the QR code image is generated with the title and expire tag *Mobile Web View* - Shrink browser horizontally until Canvas web view is rendered - Click on the down carrot menu at the top of the global nav - Click on 'QR for Mobile Login' option at the bottom - Ensure the QR code image is generated with the title and expire tag - Click on the hamburger menu in the top left - Select the Account drop-down - Click on 'QR for Mobile Login' - Ensure the QR code image is generated with the title and expire tag - 'QR for Mobile Login' link tab should only appear for paths under '/profile' With the :mobile_qr_login feature flag disabled: - Verify the 'QR for Mobile Login' link tab does not appear in any of the above locations previously tested - Hitting the '/profile/qr_for_Mobile' path directly renders a 404 Change-Id: If69d5f3a7526f7aa84cfae22d0747e5afd2d617b Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/232750 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Charley Kline <ckline@instructure.com> QA-Review: Charley Kline <ckline@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2020-04-03 07:07:04 +08:00
get "qr_mobile_login" => "profile#qr_mobile_login", :as => :qr_mobile_login
delete "user_services/:id" => "users#delete_user_service", :as => :profile_user_service
post "user_services" => "users#create_user_service", :as => :profile_create_user_service
2011-02-01 09:57:29 +08:00
end
get "about/:id" => "profile#show", :as => :user_profile
resources :communication_channels
2011-02-01 09:57:29 +08:00
get "" => "users#user_dashboard", :as => "dashboard"
get "dashboard-sidebar" => "users#dashboard_sidebar", :as => :dashboard_sidebar
post "users/toggle_hide_dashcard_color_overlays" => "users#toggle_hide_dashcard_color_overlays"
get "styleguide" => "info#styleguide"
get sub account branding and custom css/includes working fixes: CNVS-24787 fixes: CNVS-23964 fixes: CNVS-23957 - Handle parent account custom css/js for new_styles test plan: * set up a root account, child account, and grandchild account * use theme editor to set a custom css/js file for each (eg: for css `* {color:red}` and for js 'console.log("from grandchild")` * make a course & a group in the grandchild account * load a page in that course and group and make sure you see grandchild account's branding, and root's, child's, and then grandchild's css loaded on the page (grandchild should be loaded last so you see it's css effects override root or child's and you should see the console.log from root then child then grandchild) * view a page in "child". it should have root and child's css/js but not grandchild * as a user that only has enrollments (account associations) in "child", go to the dashboard. you should see css/js for both root and child but not grandchild fixes: CNVS-25051 Opening Theme Editor for sub-accounts shows incorrect theme preview test plan: * Go to a sub-account in theme editor and change settings so the Branding is different and save. * the preview on the right should reflect your changes both after you "apply" and "save" (and not just show the preview of the root account's branding) fixes: CNVS-23406 - global JS and CSS files are being included when Global CSS/JavaScript includes is false test plan: * go to /accounts/self/, and go to theme editor and upload a css_override * see that that css is loaded on pages * back in root account settings disable Global CSS/JavaScript includes * check that the css is no longer loaded. * do the same thing checking a subaccount's custom css fixes: CNVS-25558 - load whole chain of custom css/js in native app api requests test plan: * make api request for a wiki page in course in a subaccount that has custom css/js within a root account that also has custom css/js * you should see both the root account's css/js and the child account's returned in the response to test grandchild js issue jeremyp found: * go to theme editor for a grandchild account * choose a js override file (like: `console.log('first')`) * preview & apply * you should see "first" in console * go back to theme editor, pick a new file (like: `console.log('second')`) * preview & apply * you should only see "second" in console. not "first" Change-Id: I8d9047948f5da94be41e0205844629a170f980af Reviewed-on: https://gerrit.instructure.com/68249 Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Tested-by: Jenkins Product-Review: Ryan Shaw <ryan@instructure.com>
2015-12-05 00:57:07 +08:00
get "accounts/:account_id/theme-preview" => "brand_configs#show"
root to: "users#user_dashboard", as: "root", via: :get
# backwards compatibility with the old /dashboard url
get "dashboard" => "users#user_dashboard", :as => :dashboard_redirect
2011-02-01 09:57:29 +08:00
# Thought this idea of having dashboard-scoped urls was a good idea at the
# time... now I'm not as big a fan.
resource :dashboard, only: [] do
resources :content_exports, path: :data_exports
end
2011-02-01 09:57:29 +08:00
scope "/dashboard" do
get "stream_items" => "users#dashboard_stream_items", :as => :dashboard_stream_items
2018-08-21 23:41:56 +08:00
get "dashboard_cards" => "users#dashboard_cards", :as => :dashboard_dashboard_cards
put "view" => "users#dashboard_view"
delete "account_notifications/:id" => "users#close_notification", :as => :dashboard_close_notification
get "eportfolios" => "eportfolios#user_index", :as => :dashboard_eportfolios
post "comment_session" => "services_api#start_kaltura_session", :as => :dashboard_comment_session
delete "ignore_stream_item/:id" => "users#ignore_stream_item", :as => :dashboard_ignore_stream_item
end
2011-02-01 09:57:29 +08:00
resources :plugins, only: %i[index show update]
get "calendar" => "calendars#show"
get "calendar2" => "calendars#show"
get "course_sections/:course_section_id/calendar_events/:id" => "calendar_events#show", :as => :course_section_calendar_event
get "files" => "files#index"
get "files/folder#{full_path_glob}", controller: "files", action: "react_files", format: false, defaults: { format: "html" }
get "files/search", controller: "files", action: "react_files", format: false, defaults: { format: "html" }
get "files/:id/public_url" => "files#public_url", :as => :public_url
post "files/pending" => "files#create_pending", :as => :file_create_pending
resources :assignments, only: :index do
resources :files, only: [] do
post "inline_view" => "files#show", :inline => "1"
request scribd re-render when no preview available test plan: 1. work in an account with scribd enabled and google doc previews disabled (in console, add "-google_docs_previews" to the Accounts's allowed_services) 2. upload a scribd-previewable file type in the files tab (it needs to be a new file that is not already in the canvas instance) 3. make sure it previews properly (it may take a minute after uploading for the scribd rendering to complete) 4. delete the file 5. undelete the file (/courses/X/undelete) 6. reload the files tab, and click on the filename on the left side. - on the right, you should see a message like "the preview for this document is unavailable; please try again later". 7. reload the files tab again, then click on the filename. - if the scribd rendering has completed, you should see a scribd preview. if you don't, wait a few minutes and reload the files page again, to give scribd some time. 8. test other areas documents can be previewed. (it's permissible to simply delete the scribd_doc in the console via attachment.delete_scribd_doc, then try to preview, see that a "try again later" message appears, and the scribd preview appears in later page views.) a. documents embedded in rich text via the wiki sidebar b. student submissions, as viewed by the student ("submission details" button, "preview" icon) c. student submissions, as viewed by the teacher in SpeedGrader(TM) fixes CNVS-7019 Change-Id: I37be820a776637252e14b6a28a1be389b718ff9f Reviewed-on: https://gerrit.instructure.com/22438 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Bracken Mosbacker <bracken@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com>
2013-07-17 06:02:44 +08:00
end
end
2011-02-01 09:57:29 +08:00
resources :appointment_groups, only: %i[index show edit]
2011-02-01 09:57:29 +08:00
resources :errors, only: %i[show index create], path: :error_reports
2011-02-01 09:57:29 +08:00
get "health_check" => "info#health_check"
get "health_prognosis" => "info#health_prognosis"
# To be used for uptime reporting
get "readiness" => "info#readiness"
# To be used by ALB
get "internal/readiness" => "info#readiness"
get "deep" => "info#deep"
get "web-app-manifest/manifest.json" => "info#web_app_manifest"
2011-02-01 09:57:29 +08:00
get "browserconfig.xml", to: "info#browserconfig", defaults: { format: "xml" }
post "object_snippet" => "context#object_snippet"
get "saml2" => "login/saml#metadata"
Add asymmetric encryption for service tokens refs FOO-2410 test plan: - in dynamic_settings.yml, add the following block: ``` store: canvas: services-jwt: # these are all the same JWK but with different kid # to generate a new key, run the following in a Canvas console: # # key = OpenSSL::PKey::RSA.generate(2048) # key.public_key.to_jwk(kid: Time.now.utc.iso8601).to_json jwk-past.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-05-18T22:33:20Z_a\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" jwk-present.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-06-18T22:33:20Z_b\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" jwk-future.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-07-18T22:33:20Z_c\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" ``` - Ensure /internal/services/jwks loads correctly - In console, ensure `CanvasSecurity::ServicesJwt.decrypt(Base64.decode64(CanvasSecurity::ServicesJwt.for_user('localhost', User.first)))` and `CanvasSecurity::ServicesJwt.decrypt(Base64.decode64(CanvasSecurity::ServicesJwt.for_user('localhost', User.first, symmetric: true)))` both work and produce sensible looking output Change-Id: I13c6c35cc92ed12d03bf97e89e590614e11c6d47 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275160 QA-Review: August Thornton <august@instructure.com> Product-Review: August Thornton <august@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Reviewed-by: Evan Battaglia <ebattaglia@instructure.com>
2021-10-05 03:20:31 +08:00
get "internal/services/jwks" => "security#jwks"
2011-02-01 09:57:29 +08:00
# Routes for course exports
get "xsd/:version.xsd" => "content_exports#xml_schema"
get "/jobs", to: "jobs_v2#redirect", as: "jobs"
get "/job_stats", to: "jobs_v2#job_stats", as: "job_stats"
resources :jobs_v1, controller: :jobs, only: [:index, :show] do
collection do
post "batch_update"
end
end
2011-02-01 09:57:29 +08:00
resources :jobs_v2, only: [:index]
get "equation_images/*id" => "equation_images#show", :as => :equation_images, :id => /.+/
# assignments at the top level (without a context) -- we have some specs that
# assert these routes exist, but just 404 unless it is a download from local
# storage. I'm not sure we ever actually want top-level assignments available,
# maybe we should change the specs instead.
# Note, if local storage is used, a file is fetched from this top level
# (i.e. SpeedGrader document preview with Google Docs viewer)
resources :assignments, only: [:index, :show] do
get "files/:id/download" => "files#show", :download => "1"
end
resources :files, except: [:new] do
get "download" => "files#show", :download => "1"
end
resources :rubrics do
resources :rubric_assessments, path: :assessments
end
post "selection_test" => "external_content#selection_test"
scope "/quizzes/quiz_submissions/:quiz_submission_id", as: "quiz_submission" do
concerns :files
end
get "courses/:course_id/outcome_rollups" => "outcome_results#rollups", :as => "course_outcome_rollups"
get "terms_of_use" => "legal_information#terms_of_use", :as => "terms_of_use_redirect"
get "privacy_policy" => "legal_information#privacy_policy", :as => "privacy_policy_redirect"
scope(controller: :smart_search) do
get "courses/:course_id/search", action: :show, as: :course_search
# TODO: Add back global search once we have a good way to handle it
# get "search", action: :show
end
scope(controller: :translation) do
post "courses/:course_id/translate", action: :translate
post "courses/:course_id/translate/paragraph", action: :translate_paragraph
post "translate/message", action: :translate_message
end
### API routes ###
# TODO: api routes can't yet take advantage of concerns for DRYness, because of
# the way ApiRouteSet works. For now we get around it by defining methods
# inline in the routes file, but getting concerns working would rawk.
ApiRouteSet::V1.draw(self) do
scope(controller: :courses) do
get "courses", action: :index, as: "courses"
put "courses/:id", action: :update
get "courses/:id", action: :show, as: "course"
delete "courses/:id", action: :destroy
post "accounts/:account_id/courses", action: :create
get "courses/:course_id/students", action: :students
get "courses/:course_id/settings", action: :api_settings, as: "course_settings"
put "courses/:course_id/settings", action: :update_settings
get "courses/:course_id/recent_students", action: :recent_students, as: "course_recent_students"
get "courses/:course_id/users", action: :users, as: "course_users"
get "courses/:course_id/collaborations", controller: :collaborations, action: :api_index, as: "course_collaborations_index"
delete "courses/:course_id/collaborations/:id", controller: :collaborations, action: :destroy
Quiz engine choice is persisted Closes QUIZ-7286 Flag=newquizzes_on_quiz_page Test plan: In Canvas with newquizzes_on_quiz_page flag enabled: Initial selection tests: 1. As a teacher/admin, navigate to the Quizzes view 2. Click [+Quiz]. The quiz engine selection modal should appear. 3. Sielect either engine without checking the 'Remember my choice' checkbox.You should be redirected to the corresponding quiz build page. 4. Return to Quizzes view, click [+Quiz] again and select either engine. Check the 'Remember my choice' checkbox. Click 'Submit'. You should be redirected to the selected engine. 5. Return to Quizzes view, click [+Quiz] again. This time, no modal should open. Instead, you should automatically be redirected to your previously selected quiz engine. Reset selection tests: 1. As a teacher/admin, navigate to the Quizzes view 2. Click the kabob menu [...] next to the [+Quiz] button 3. Click 'Reset quiz engine choice'. A success/failure message should appear at the top of the Quizzes view. 4. Click the [+Quiz] button. The selection modal should appear. In Canvas with newquizzes_on_quiz_page flag disabled: 1. There should be no option to select/reset a quiz engine anywhere Change-Id: I4370d1463745839b949d0d153ab3bed84884d2de Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/224587 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Stephen Kacsmark <skacsmark@instructure.com> QA-Review: Alex Slaughter <aslaughter@instructure.com> Product-Review: Kevin Dougherty <jdougherty@instructure.com>
2020-01-28 05:39:55 +08:00
put "courses/:id/quizzes", action: "new_quizzes_selection_update", as: "course_new_quizzes_selection_update"
post "courses/:id/dismiss_migration_limitation_message", action: "dismiss_migration_limitation_msg", as: "course_dismiss_migration_limitation_msg"
# this api endpoint has been removed, it was redundant with just courses#users
# we keep it around for backward compatibility though
get "courses/:course_id/search_users", action: :users
get "courses/:course_id/users/:id", action: :user, as: "course_user"
get "courses/:course_id/users/:user_id/progress", action: :user_progress
get "courses/:course_id/content_share_users", action: :content_share_users, as: "course_content_share_users"
get "courses/:course_id/activity_stream", action: :activity_stream, as: "course_activity_stream"
get "courses/:course_id/activity_stream/summary", action: :activity_stream_summary, as: "course_activity_stream_summary"
get "courses/:course_id/bulk_user_progress", action: :bulk_user_progress, as: "course_bulk_user_progress"
get "courses/:course_id/todo", action: :todo_items, as: "course_todo_list_items"
post "courses/:course_id/preview_html", action: :preview_html
post "courses/:course_id/course_copy", controller: :content_imports, action: :copy_course_content
get "courses/:course_id/course_copy/:id", controller: :content_imports, action: :copy_course_status, as: :course_copy_status
get "courses/:course_id/files", controller: :files, action: :api_index, as: "course_files"
post "courses/:course_id/files", action: :create_file, as: "course_create_file"
get "courses/:course_id/folders", controller: :folders, action: :list_all_folders, as: "course_folders"
post "courses/:course_id/folders", controller: :folders, action: :create
get "courses/:course_id/folders/by_path/*full_path", controller: :folders, action: :resolve_path
get "courses/:course_id/folders/by_path", controller: :folders, action: :resolve_path
get "courses/:course_id/folders/icon_maker", controller: :folders, action: :icon_maker_folder
get "courses/:course_id/folders/media", controller: :folders, action: :media_folder
get "courses/:course_id/folders/:id", controller: :folders, action: :show, as: "course_folder"
get "media_objects", controller: "media_objects", action: :index, as: :media_objects
Update canvas media_objects api for the RCE closes LA-68 test plan: - have a user with media objects in a couple courses - have another user with a media object - GET /api/v1/media_objects > expect all the objects for the logged in user to be returned, including the sources and tracks data - query /api/v1/media_objects?&exclude[]=sources&exclude[]=tracks > expect all the objects for the logged in user to be returned, excluding the sources and tracks data (it should be _much_ faster too) - query /api/v1/courses/:course_id/media_objects?exclude[]=sources&exclude[]=tracks > expect only the media objects for the logged in user, in the given course to be returned > expect /doc/api/media_objects.html to properly document the api - query /api/v1/courses/:a_nonexistent_course_id/ > expect a 404 sorting - have some media objects with user_entered_title, some with only title. - GET /api/v1/media_objects&sort=title&order=desc > expect the results to be sorted by title descending - GET /api/v1/media_objects&sort=create_at&order=asc > expect the results to be sorted by created_at ascending - you can try other sorts updating* - PUT /api/v1/media_objects/:media_obj_id?user_entered_title=new+title - if :media_obj_id belongs to the current user > expect status=200 and the object to be returned - if :media_obj_id doesn't exist > expect status=401 - if :media_obj_id belongs to another user > expect status=401 - if user_entered_title was empty > expect status=400 - if user_entered_title was missing > expect status=400 - if user wasn't logged in > expect either a 422 (cuz the CSRF header is funky) or a 302 (redirect to the login page) - after updating - GET /media_objects/:id/info > expect the object with the new title returned - GET /api/v1/media_objects?exclude[]=sources&exclude[]=tracks > expect the object to have its new title *To PUT, the request must include a X-CSRF-Token header. The value can be found in documet.cookie on a canvas page (after running decodeURIComponent on it) Change-Id: I496b8a36f1d177054736dadb6695a25bb7aee217 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/215292 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Tested-by: Jenkins Product-Review: Ed Schiebel <eschiebel@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com>
2019-10-31 02:12:24 +08:00
get "courses/:course_id/media_objects", controller: "media_objects", action: :index, as: :course_media_objects
get "groups/:group_id/media_objects", controller: "media_objects", action: :index, as: :group_media_objects
get "media_attachments", controller: "media_objects", action: :index, as: :media_attachments
get "courses/:course_id/media_attachments", controller: "media_objects", action: :index, as: :course_media_attachments
get "groups/:group_id/media_attachments", controller: "media_objects", action: :index, as: :group_media_attachments
put "accounts/:account_id/courses", action: :batch_update
post "courses/:course_id/ping", action: :ping, as: "course_ping"
get "courses/:course_id/link_validation", action: :link_validation, as: "course_link_validation"
post "courses/:course_id/link_validation", action: :start_link_validation
post "courses/:course_id/reset_content", action: :reset_content
get "users/:user_id/courses", action: :user_index, as: "user_courses"
get "courses/:course_id/effective_due_dates", action: :effective_due_dates, as: "course_effective_due_dates"
get "courses/:course_id/permissions", action: :permissions
get "courses/:course_id/student_view_student", action: :student_view_student
end
Add account calendars api controller This api will be used by students and admins to see what account calendars are available (all available calendars, not the calendars that the user is "subscribed" to). It will also be used by admins to set account calendar visibility. Includes a miration to add an account_calendar_visible column to the accounts table. This is preferable to using a setting on Account since we'll be querying accounts using this valueas a parameter and prefer the performance of a column. closes LS-3253 flag = account_calendar_events Test plan: Part 1: index - Enroll a user in a few courses in different accounts - GET /api/v1/account_calendars as that user - Expect to see an entry for each account where the user has an enrollment, as well as all of those accounts' parents, up the chain - In the rails console, set one of the account's calendars as hidden: account = Account.find(x) account.account_calendar_visible = false account.save - GET /api/v1/account_calendars again, and expect the same result as before, but without the hidden account Part 2: show - GET /api/v1/account_calendars/xyz as the user from before, where xyz is the account id of one of the user's associated accounts - Expect to see the account calendar details - Try to request an account calendar that the user doesn't have access to; expect to see 401 - Attempt to access the hidden account calendar; expect a 401 - As an admin with the manage_account_calendar_visibility permission, attempt to access the same hidden calendar; expect success Part 3: update - As an admin with manage_account_calendar_visibility permission, PUT /api/v1/account_calendars/xyz with param visible=<true/false> - Expect the visibility to be updated accordingly - Try to update visibility as a student (or any user without the permission); expect 401 Part 4: all_calendars - As an admin with manage_account_calendar_visibility permission, GET /api/v1/accounts/xyz/account_calendars, where xyz is the *root account* id - Expect a list of all account calendars for the entire institution, regardless of visibility status - Expect this request to return 401 for students or admins without the permission Change-Id: I0a3bcd58b509c62326b0a885b87ec3f8779fcd37 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/296293 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Eric Saupe <eric.saupe@instructure.com> QA-Review: Eric Saupe <eric.saupe@instructure.com> Migration-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Jackson Howe <jackson.howe@instructure.com>
2022-07-16 05:37:03 +08:00
scope(controller: :account_calendars_api) do
get "account_calendars", action: :index, as: :account_calendars
Add account calendars api controller This api will be used by students and admins to see what account calendars are available (all available calendars, not the calendars that the user is "subscribed" to). It will also be used by admins to set account calendar visibility. Includes a miration to add an account_calendar_visible column to the accounts table. This is preferable to using a setting on Account since we'll be querying accounts using this valueas a parameter and prefer the performance of a column. closes LS-3253 flag = account_calendar_events Test plan: Part 1: index - Enroll a user in a few courses in different accounts - GET /api/v1/account_calendars as that user - Expect to see an entry for each account where the user has an enrollment, as well as all of those accounts' parents, up the chain - In the rails console, set one of the account's calendars as hidden: account = Account.find(x) account.account_calendar_visible = false account.save - GET /api/v1/account_calendars again, and expect the same result as before, but without the hidden account Part 2: show - GET /api/v1/account_calendars/xyz as the user from before, where xyz is the account id of one of the user's associated accounts - Expect to see the account calendar details - Try to request an account calendar that the user doesn't have access to; expect to see 401 - Attempt to access the hidden account calendar; expect a 401 - As an admin with the manage_account_calendar_visibility permission, attempt to access the same hidden calendar; expect success Part 3: update - As an admin with manage_account_calendar_visibility permission, PUT /api/v1/account_calendars/xyz with param visible=<true/false> - Expect the visibility to be updated accordingly - Try to update visibility as a student (or any user without the permission); expect 401 Part 4: all_calendars - As an admin with manage_account_calendar_visibility permission, GET /api/v1/accounts/xyz/account_calendars, where xyz is the *root account* id - Expect a list of all account calendars for the entire institution, regardless of visibility status - Expect this request to return 401 for students or admins without the permission Change-Id: I0a3bcd58b509c62326b0a885b87ec3f8779fcd37 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/296293 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Eric Saupe <eric.saupe@instructure.com> QA-Review: Eric Saupe <eric.saupe@instructure.com> Migration-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Jackson Howe <jackson.howe@instructure.com>
2022-07-16 05:37:03 +08:00
get "account_calendars/:account_id", action: :show, as: :account_calendar
put "account_calendars/:account_id", action: :update, as: :update_account_calendar
put "accounts/:account_id/account_calendars", action: :bulk_update, as: :bulk_update_account_calendars
get "accounts/:account_id/account_calendars", action: :all_calendars, as: :all_account_calendars
get "accounts/:account_id/visible_calendars_count", action: :visible_calendars_count, as: :visible_calendars_count
Add account calendars api controller This api will be used by students and admins to see what account calendars are available (all available calendars, not the calendars that the user is "subscribed" to). It will also be used by admins to set account calendar visibility. Includes a miration to add an account_calendar_visible column to the accounts table. This is preferable to using a setting on Account since we'll be querying accounts using this valueas a parameter and prefer the performance of a column. closes LS-3253 flag = account_calendar_events Test plan: Part 1: index - Enroll a user in a few courses in different accounts - GET /api/v1/account_calendars as that user - Expect to see an entry for each account where the user has an enrollment, as well as all of those accounts' parents, up the chain - In the rails console, set one of the account's calendars as hidden: account = Account.find(x) account.account_calendar_visible = false account.save - GET /api/v1/account_calendars again, and expect the same result as before, but without the hidden account Part 2: show - GET /api/v1/account_calendars/xyz as the user from before, where xyz is the account id of one of the user's associated accounts - Expect to see the account calendar details - Try to request an account calendar that the user doesn't have access to; expect to see 401 - Attempt to access the hidden account calendar; expect a 401 - As an admin with the manage_account_calendar_visibility permission, attempt to access the same hidden calendar; expect success Part 3: update - As an admin with manage_account_calendar_visibility permission, PUT /api/v1/account_calendars/xyz with param visible=<true/false> - Expect the visibility to be updated accordingly - Try to update visibility as a student (or any user without the permission); expect 401 Part 4: all_calendars - As an admin with manage_account_calendar_visibility permission, GET /api/v1/accounts/xyz/account_calendars, where xyz is the *root account* id - Expect a list of all account calendars for the entire institution, regardless of visibility status - Expect this request to return 401 for students or admins without the permission Change-Id: I0a3bcd58b509c62326b0a885b87ec3f8779fcd37 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/296293 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Eric Saupe <eric.saupe@instructure.com> QA-Review: Eric Saupe <eric.saupe@instructure.com> Migration-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Jackson Howe <jackson.howe@instructure.com>
2022-07-16 05:37:03 +08:00
end
scope(controller: :account_notifications) do
post "accounts/:account_id/account_notifications", action: :create, as: "account_notification"
put "accounts/:account_id/account_notifications/:id", action: :update, as: "account_notification_update"
get "accounts/:account_id/account_notifications", action: :user_index, as: "user_account_notifications" # to change the api docs
get "accounts/:account_id/users/:user_id/account_notifications", action: :user_index_deprecated # for back compat
get "accounts/:account_id/account_notifications/:id", action: :show, as: "user_account_notification_show"
get "accounts/:account_id/users/:user_id/account_notifications/:id", action: :show_deprecated
delete "accounts/:account_id/account_notifications/:id", action: :user_close_notification, as: "user_account_notification"
delete "accounts/:account_id/users/:user_id/account_notifications/:id", action: :user_close_notification_deprecated
end
scope(controller: :brand_configs_api) do
get "brand_variables", action: :show
end
scope(controller: :accounts) do
get "terms_of_service_custom_content", action: :terms_of_service_custom_content
get "settings/environment", action: :environment
end
scope(controller: :tabs) do
get "accounts/:account_id/tabs", action: :index, as: "account_tabs"
get "courses/:course_id/tabs", action: :index, as: "course_tabs"
get "groups/:group_id/tabs", action: :index, as: "group_tabs"
get "users/:user_id/tabs", action: :index, as: "user_profile_tabs"
put "courses/:course_id/tabs/:tab_id", action: :update
end
create endpoint for saving gradebook filters created some api endpoints to support all CRUD operations for saving the gradebook filter settings in the backend. fixes EVAL-2006 flag=none test plan: - create and publish a course with at least 1 teacher and one student. create - use a HTTP client to make a POST request to /api/v1/courses/:course_id/gradebook_filters with the body {"gradebook_filter": {"course_id": :course_id, "name": "test", "payload": {"foo":"bar"}} } - notice the requests response returns the object created with no errors. update - use a HTTP client to make a PUT request to /api/v1/courses/:course_id/gradebook_filters/ :gradebook_filter_id with the body {"gradebook_filter": {"id": :gradebook_filter_id, "course_id": :course_id, "name": "other", "payload": {"bar": "foo"} } } - notice the requests response returns the object with the attributes updated and no errors. show - use a HTTP client to make a GET request to /api/v1/courses/:course_id/gradebook_filters/ :gradebook_filter_id - notice the requests response returns the object with the correct data and no errors. index - use a HTTP client to make a GET request to /api/v1/courses/:course_id/gradebook_filters - notice the requests response returns an array of gradebook filters created and with no errors. Change-Id: Ib8819d9c62ae536a40719078e83ef4d2b7b5c083 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275774 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Aaron Shafovaloff <ashafovaloff@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Cody Cutrer <cody@instructure.com>
2021-10-13 03:13:30 +08:00
scope(controller: :gradebook_filters_api) do
get "courses/:course_id/gradebook_filters", action: :index
post "courses/:course_id/gradebook_filters", action: :create
get "courses/:course_id/gradebook_filters/:id", action: :show
put "courses/:course_id/gradebook_filters/:id", action: :update
delete "courses/:course_id/gradebook_filters/:id", action: :destroy
end
scope(controller: :scopes_api) do
get "accounts/:account_id/scopes", action: :index
end
scope(controller: :sections) do
get "courses/:course_id/sections", action: :index, as: "course_sections"
get "courses/:course_id/sections/:id", action: :show, as: "course_section"
get "sections/:id", action: :show
post "courses/:course_id/sections", action: :create
put "sections/:id", action: :update
delete "sections/:id", action: :destroy
post "sections/:id/crosslist/:new_course_id", action: :crosslist
delete "sections/:id/crosslist", action: :uncrosslist
end
scope(controller: :enrollments_api) do
get "courses/:course_id/enrollments", action: :index, as: "course_enrollments"
get "sections/:section_id/enrollments", action: :index, as: "section_enrollments"
get "users/:user_id/enrollments", action: :index, as: "user_enrollments"
add back ability to fetch temp enrollment provider recipients refs FOO-4041 refs FOO-4019 flag = temporary_enrollments test plan: • enable temporary enrollments feature flag • have a temporary enrollment recipient and provider • make a call to GET /api/v1/users/:user_id/temporary_enrollment_status • verify the response contains the recipient and provider temporary enrollment status if that user is a recipient or provider /doc/api/enrollments.html#method.enrollments_api.temporary_enrollments • create a user with an active temporary enrollment and an enrollment that is completed • fetch /api/v1/users/:id/enrollments with the provided args • temporary_enrollments_for_recipient=true • include=temporary_enrollment_providers • state=current_and_future • verify that the response includes the current temporary enrollment with an included "temporary_enrollment_provider" object • fetch /api/v1/users/:id/enrollments with the provided args • temporary_enrollment_recipients_for_provider=true • state=current_and_future • verify that the response includes the current temporary enrollment for the specified provider Change-Id: Ie547fea0cf2a0ee383a94a5e44a07a7ad24de0f7 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/332550 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Michael Hulse <michael.hulse@instructure.com> QA-Review: Michael Hulse <michael.hulse@instructure.com> Product-Review: Michael Hulse <michael.hulse@instructure.com>
2023-11-10 11:02:48 +08:00
get "users/:user_id/temporary_enrollment_status", action: :show_temporary_enrollment_status
get "accounts/:account_id/enrollments/:id", action: :show, as: "enrollment"
post "courses/:course_id/enrollments", action: :create
post "sections/:section_id/enrollments", action: :create
post "courses/:course_id/enrollments/:id/accept", action: :accept
post "courses/:course_id/enrollments/:id/reject", action: :reject
put "courses/:course_id/users/:user_id/last_attended", action: :last_attended
put "courses/:course_id/enrollments/:id/reactivate", action: :reactivate, as: "reactivate_enrollment"
delete "courses/:course_id/enrollments/:id", action: :destroy, as: "destroy_enrollment"
end
scope(controller: :temporary_enrollment_pairings_api) do
get "accounts/:account_id/temporary_enrollment_pairings", action: :index
get "accounts/:account_id/temporary_enrollment_pairings/:id", action: :show
get "accounts/:account_id/temporary_enrollment_pairings/new", action: :new
post "accounts/:account_id/temporary_enrollment_pairings", action: :create
delete "accounts/:account_id/temporary_enrollment_pairings/:id", action: :destroy
end
scope(controller: :terms_api) do
get "accounts/:account_id/terms", action: :index, as: "enrollment_terms"
get "accounts/:account_id/terms/:id", action: :show, as: "enrollment_term"
end
scope(controller: :terms) do
post "accounts/:account_id/terms", action: :create
put "accounts/:account_id/terms/:id", action: :update
delete "accounts/:account_id/terms/:id", action: :destroy
end
scope(controller: :authentication_audit_api) do
get "audit/authentication/logins/:login_id", action: :for_login, as: "audit_authentication_login"
get "audit/authentication/accounts/:account_id", action: :for_account, as: "audit_authentication_account"
get "audit/authentication/users/:user_id", action: :for_user, as: "audit_authentication_user"
Auditors::Authentication fixes CNVS-390 stores and allows querying by user/account/pseudonym of login/logout events. test-plan: [setup] - set up an 'auditors' keyspace in cassandra and run migrations - have shardX and shardY on one database server, and shardZ on a different database server - have accountW and accountX on shardX - have accountY and accountZ on shardY and shardZ, respectively - have userA on shardX with pseudonymAW in accountW and pseudonymAX in accountX (cross-account, single-shard user) - have userB on shardY with pseudonymBY in accountY and pseudonymBX in accountX (cross-shard user) - have userC on shardZ with pseudonymCZ in accountZ and pseudonymCX in accountX (cross-db-server user) - log in and out of each pseudonym above multiple times [index isolation] - /api/v1/audit/authentication/pseudonyms/<pseudonymAX> should include logins and logouts from pseudonymAX only - /api/v1/audit/authentication/accounts/<accountX> should include logins and logouts from pseudonymAX, pseudonymBX, and pseudonymCX but not pseudonymAW - /api/v1/audit/authentication/users/<userA> should include logins and logouts from both pseudonymAW and pseudonymAX but not pseudonymBX or pseudonymCX [permission isolation] (in each of these, either :view_statistics or :manage_user_logins on an account qualifies as "having permission") - /api/v1/audit/authentication/pseudonyms/<pseudonymAX> should be unauthorized if the current user doesn't have permission on accountX - /api/v1/audit/authentication/accounts/<accountX> should be unauthorized if the current user doesn't have permission on accountX - /api/v1/audit/authentication/users/<userA> should be unauthorized if the current user doesn't have permission on either of accountW or accountX - /api/v1/audit/authentication/users/<userA> should include logins and logouts from accountW but not from accountX if the current user has permission on accountW but not on accountX [sharding] - /api/v1/audit/authentication/users/<userB> should include logins and logouts from both pseudonymBY and pseudonymBX - /api/v1/audit/authentication/users/<userB> should not include duplicate logins and logouts from either pseudonymBY and pseudonymBX (potential for bug due to both pseudonyms' shards being on the same database server) - /api/v1/audit/authentication/users/<userC> should include logins and logouts from both pseudonymCZ and pseudonymCX Change-Id: I74b1573b346935f733fe5b07919d2d450cf07592 Reviewed-on: https://gerrit.instructure.com/21829 Reviewed-by: Brian Palmer <brianp@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2013-06-28 06:43:15 +08:00
end
scope(controller: :grade_change_audit_api) do
get "audit/grade_change/assignments/:assignment_id", action: :for_assignment, as: "audit_grade_change_assignment"
get "audit/grade_change/courses/:course_id", action: :for_course, as: "audit_grade_change_course"
get "audit/grade_change/students/:student_id", action: :for_student, as: "audit_grade_change_student"
get "audit/grade_change/graders/:grader_id", action: :for_grader, as: "audit_grade_change_grader"
add more search capabilities to audit endpoint This adds more search capabilities to the audit endpoint to give maximum flexibility to support the new gradebook history page. This adds the ability to search for course AND any combination of the following: assignment, grader, student. Permissions were not touched in this patchset, so only admins can access currently. closes CNVS-37299 test plan: - Create a course with two teachers, two assignments, and two student. - Grade the students for the assignments and change the grades a few times as each teacher - Visit the following API endpoints with appropriate ids confirming that appropriate data is returned: o /api/v1/audit/grade_change/courses/:course_id/assignments/:assignment_id o /api/v1/audit/grade_change/courses/:course_id/assignments/:assignment_id/graders/:grader_id o /api/v1/audit/grade_change/courses/:course_id/assignments/:assignment_id/graders/:grader_id/students/:student_id o /api/v1/audit/grade_change/courses/:course_id/assignments/:assignment_id/students/:student_id o /api/v1/audit/grade_change/courses/:course_id/graders/:grader_id o /api/v1/audit/grade_change/courses/:course_id/graders/:grader_id/students/:student_id o /api/v1/audit/grade_change/courses/:course_id/students/:student_id Change-Id: I86648896d49d7228ddce04864e80221da9b5f96d Reviewed-on: https://gerrit.instructure.com/114146 Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com> Tested-by: Jenkins Reviewed-by: Derek Bender <djbender@instructure.com> QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-06-03 07:24:41 +08:00
get "audit/grade_change/courses/:course_id/assignments/:assignment_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_assignment"
get "audit/grade_change/courses/:course_id/assignments/:assignment_id/graders/:grader_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_assignment_grader"
get "audit/grade_change/courses/:course_id/assignments/:assignment_id/graders/:grader_id/students/:student_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_assignment_grader_student"
get "audit/grade_change/courses/:course_id/assignments/:assignment_id/students/:student_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_assignment_student"
get "audit/grade_change/courses/:course_id/graders/:grader_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_grader"
get "audit/grade_change/courses/:course_id/graders/:grader_id/students/:student_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_grader_student"
get "audit/grade_change/courses/:course_id/students/:student_id",
action: :for_course_and_other_parameters,
as: "audit_grade_change_course_student"
get "audit/grade_change", action: :query, as: "audit_grade_change"
end
scope(controller: :course_audit_api) do
get "audit/course/courses/:course_id", action: :for_course, as: "audit_course_for_course"
get "audit/course/accounts/:account_id", action: :for_account, as: "audit_course_for_account"
end
scope(controller: :assignment_overrides) do
get "courses/:course_id/assignments/:assignment_id/overrides", action: :index
post "courses/:course_id/assignments/:assignment_id/overrides", action: :create
get "courses/:course_id/assignments/:assignment_id/overrides/:id", action: :show, as: "assignment_override"
put "courses/:course_id/assignments/:assignment_id/overrides/:id", action: :update
delete "courses/:course_id/assignments/:assignment_id/overrides/:id", action: :destroy
get "sections/:course_section_id/assignments/:assignment_id/override", action: :section_alias
get "groups/:group_id/assignments/:assignment_id/override", action: :group_alias
get "courses/:course_id/assignments/overrides", action: :batch_retrieve
put "courses/:course_id/assignments/overrides", action: :batch_update
post "courses/:course_id/assignments/overrides", action: :batch_create
end
scope(controller: :assignments_api) do
get "courses/:course_id/assignments/gradeable_students", controller: :submissions_api, action: :multiple_gradeable_students, as: "multiple_assignments_gradeable_students"
get "courses/:course_id/assignments", action: :index, as: "course_assignments"
get "courses/:course_id/assignment_groups/:assignment_group_id/assignments", action: :index, as: "course_assignment_group_assignments"
get "users/:user_id/courses/:course_id/assignments", action: :user_index, as: "user_course_assignments"
put "courses/:course_id/assignments/bulk_update", action: :bulk_update
get "courses/:course_id/assignments/:id", action: :show, as: "course_assignment"
post "courses/:course_id/assignments", action: :create
put "courses/:course_id/assignments/:id", action: :update
post "courses/:course_id/assignments/:assignment_id/duplicate", action: :duplicate
post "courses/:course_id/assignments/:assignment_id/retry_alignment_clone", action: :retry_alignment_clone
delete "courses/:course_id/assignments/:id", action: :destroy, controller: :assignments
end
scope(controller: "assignment_extensions") do
post "courses/:course_id/assignments/:assignment_id/extensions", action: :create, as: "course_assignment_extensions_create"
end
peer reviews api refs: PFS-2071, PFS-2072, PFS-2073, PFS-2074 **Test Plan PFS-2071 1. Create course with assignment, teacher and two students 2. setup peer reviews on assignment 3. As student 1 create a submission 4. As student 2 peer review submission, leave comments 5. execute the following api courses/:course_id/assignments/:assignment_id/peer_reviews 6. As account admin all information should be shown 7. As teacher all information should be shown 8. As student should see all information 9. Repeat above but set anonymous peer reviews on assignment 10. As account admin all information should be shown 11. As teacher all information should be shown 12. As student should see comments but all reviewer information should not be shown 13. include the following include parameters, include[]=submission_comments, include[]=user make sure additional information is shown according to parameter. PFS-2072 1. Follow setup from PFS-2071 2. execute a get on the following api /api/v1/courses/:course_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews 3. validate that only peer reviews for the given submission are shown PFS-2073 1. Follow setup from PFS-2071 2. execute a post on the following api, including a user_id parameter /api/v1/courses/:course_id/assignments/:assignment1_id/submissions/:submission_id/peer_reviews 3. validate that user from user_id parameter is added as a reviwer on the submission PFS-2074 1. follow setup from PFS-2071 2. execute a delete on the following api, including a user_id parameter /api/v1/courses/:course_id/assignments/:assignment1_id/submissions/:submission_id/peer_reviews 3. validate that user from user_id parameter is removed as a reviewer on the submission (cherry picked from commit 91744bbcd5a81be968139b1f68b65c3e9eaa7b4a) Change-Id: Ic09a16956cddb2f113625ff61bc733503d713abb Reviewed-on: https://gerrit.instructure.com/56936 Tested-by: Jenkins QA-Review: Adam Stone <astone@instructure.com> Reviewed-by: John Corrigan <jcorrigan@instructure.com> Product-Review: Brandon Broschinsky <brandonbr@instructure.com>
2015-06-18 00:34:45 +08:00
scope(controller: :peer_reviews_api) do
get "courses/:course_id/assignments/:assignment_id/peer_reviews", action: :index
get "sections/:section_id/assignments/:assignment_id/peer_reviews", action: :index
get "courses/:course_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews", action: :index
get "sections/:section_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews", action: :index
post "courses/:course_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews", action: :create
post "sections/:section_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews", action: :create
delete "courses/:course_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews", action: :destroy
delete "sections/:section_id/assignments/:assignment_id/submissions/:submission_id/peer_reviews", action: :destroy
end
scope(controller: :moderation_set) do
get "courses/:course_id/assignments/:assignment_id/moderated_students", action: :index, as: :moderated_students
post "courses/:course_id/assignments/:assignment_id/moderated_students", action: :create, as: :add_moderated_students
end
scope(controller: :submissions_api) do
2015-06-26 03:35:25 +08:00
[%w[course course], %w[section course_section]].each do |(context, path_prefix)|
post "#{context.pluralize}/:#{context}_id/submissions/update_grades", action: :bulk_update
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/read", action: :mark_submission_read, as: "#{context}_submission_mark_read"
delete "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/read", action: :mark_submission_unread, as: "#{context}_submission_mark_unread"
Set badge count for changes at assignment level Badge Count increments whenever there's any change at the assignment level Add rubrics info to the badge count in the grades menu flag=assignments_2_student flag=visibility_feedback_student_grades_page Closes EVAL-2445 Closes EVAL-2541 Test plan: - Enable the "Assignment Enhancements - Student" feature flag - Enable the "Improve Feedback on Students Grade Page" feature flag - Have a course with at least two students - Have an assigment with peer review enabled - Assign students to peer review each other - As the student A submit the assignment - 1. As a teacher, grade the student's A submission - As the student A go the grades page - Badge count on Grades should show up - Now refresh the page. Badge count should be gone - 2. As a teacher, leave a comment on the student's A submission - As the student A go the grades page - Badge count on Grades menu should be visible - A blue dot on the comments icon shoud display - Refresh the page. Badge count and blue dot should still be visible - Click on the comments icon - Refresh the page. Badge count and blue dot should not display - 3. As a teacher, add a rubric assessment (with comment or points) to the students A submission through SpeedGrader - As the student A go the grades page - Badge count on Grades menu should be visible - A blue dot on the rubric icon shoud display - Click on the rubric icon - Refresh the page. Badge count and blue dot should not display - 4. As a teacher, via SpeedGrader, add a rubric assessement and leave a comment on the submission - As the student A go the grades page - Badge count on Grades menu should be visible - A blue dot on the rubric icon and comments icon shoud display - Click on the rubric icon - Refresh the page. Badge count should still be visible but the blue dot is now only on the comments icons Change-Id: I966d8cb2470509536d7c8a7cc81abdbf17a35ae5 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/302162 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Derek Williams <derek.williams@instructure.com> QA-Review: Kai Bjorkman <kbjorkman@instructure.com> Product-Review: Deborah Kwak <deborah.kwak@instructure.com>
2022-09-29 05:34:29 +08:00
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/read/:item", action: :mark_submission_item_read, as: "#{context}_submission_mark_item_read"
fix student unread grade content participation currently when a student has unread grades in their grade summary, the blue unread dots appear for 5 seconds then disappear. the blue dots will display if reloaded and only permanently disappear if the student clicks into the submission. new change will make it so that when a student goes to summary page, the blue dots stay on the screen but a bulk api call is made to mark all the unread submissions as read. next time user loads the page the blue dots will not be there. fixes EVAL-2775 flag=visibility_feedback_student_grades_page flag=assignments_2_student test plan: - as teacher, make 3 changes to student's grade for 3 different assignments - as the student, view the grade summary page - notice that the unread grade blue dots appear next to those 3 assignments and do not disappear - notice that the content participation count next to grades tab is correct with a count of 3 - as the student, refresh the grade summary page - notice that the unread blue dots are no longer there and the content participation count should now be 0. Change-Id: Ief3bbe12fafe5cb4b022126b2a3bcddedd220cd2 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/308109 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Cameron Ray <cameron.ray@instructure.com> Reviewed-by: Derek Williams <derek.williams@instructure.com> Reviewed-by: Cameron Ray <cameron.ray@instructure.com> QA-Review: Kai Bjorkman <kbjorkman@instructure.com>
2023-01-05 00:42:57 +08:00
put "#{context.pluralize}/:#{context}_id/submissions/bulk_mark_read", action: :mark_bulk_submissions_as_read, as: "#{context}_submissions_bulk_mark_read"
add button to clear student badge counts there are times where the badge count is incorrect and students are unable to clear the count. this button automates a script that engineers used to run in the background to fix this issue. for site admin users, there should be a new blue button that is next to the "Print Grades" button that says "Clear Badge Counts" on the student grades page (/courses/<course_id>/grades/<user_id>). fixes EVAL-3123 flag=none test plan: - create two assignments - for each assignment, add a rubric - grade the assignments and rubric and add a comment to each submission - log in as student and view the grades page, ensure badge count is 2 and that the button is not visible - log in as teacher and view the student's grade page by navigating to ../courses/<course_id>/grades/<user_id> and ensure the button is not visible - log in as site admin and view the student's grade page and ensure the button is visible and enabled - click the button and ensure that the button becomes disabled and a success alert appears - log in as student and view the grades page, ensure badge count is reset to 0 Change-Id: Ib0e6fea3973c91a244bac4e2b1b413a0851613b0 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/318422 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jackson Huang <jackson.huang@instructure.com> Reviewed-by: Kai Bjorkman <kbjorkman@instructure.com> QA-Review: Aaron Shafovaloff <ashafovaloff@instructure.com> QA-Review: Christopher Soto <christopher.soto@instructure.com> Product-Review: Sam Garza <sam.garza@instructure.com>
2023-05-18 00:32:11 +08:00
put "#{context.pluralize}/:#{context}_id/submissions/:user_id/clear_unread", action: :submissions_clear_unread, as: "#{context}_submissions_clear_unread"
show an indicator for unread submission annotations test plan: - have canvadocs set up with canvas - make sure annotation notifications are working (this requires a canvas API key to be configured in canvadocs) - enable the "Submission feedback indicators" feature - as a student, submit a document to an assignment - as a teacher, grade the document in SpeedGrader™ and leave one or more annotations on it - as a student, click the assignment in the "recent feedback" column - you are taken to the Submission Details page, where there should be an indicator next to the "View Feedback" button that indicates unread feedback exists - click "View Feedback" - close the modal - the unread indicator should be gone - refresh the page - the unread indicator should still be gone - render API docs - use the "Get document annotations read state" returns { "read": false } or { "read": true } depending on the read state - use the "Mark document annotations as read" endpoint and ensure doing that and reloading submission details makes the unread indicator go away (note that these API endpoints are not used by the Canvas UI but I am exposing the functionality to mobile users) flag=submission_feedback_indicators refs LS-2670 Change-Id: Iedb7330bb5669efe16f7ea01da132b0d69e4ded4 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/274332 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Robin Kuss <rkuss@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2021-09-24 08:59:32 +08:00
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/document_annotations/read", action: :document_annotations_read_state, as: "#{path_prefix}_submission_document_annotations_read_state"
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/document_annotations/read", action: :mark_document_annotations_read, as: "#{path_prefix}_submission_document_annotations_mark_read"
Show a blue dot when a rubric is graded Show blue dot on the region surrounding the rubrics icon when a rubric is graded or a comment is added Closes EVAL-2419 flag=visibility_feedback_student_grades_page test plan: - Have a graded assignment with a rubric and peer reviews (manually assign peer reviews) and at least two students where one assesses each others assignments, or you can assess as a teacher via SpeedGrader where you select the student then click on the rubric - With the FF on: - As a teacher go to SpeedGrader and make a comment on the rubric or grade it. Or as a student peer review the other student's submission. - As the student who owns the submission go to the grades page - The rubric icon should be present with a gray region surrounding it. The blue dot should also show up - The blue is removed when clicking on the rubric icon. The blue dot should not show up after refreshing the page - With the FF off: - As a teacher go to SpeedGrader and make a comment on the rubric or grade it. Or as a student peer review the other student's submission. - As the student who owns the submission go to the grades page - Only the icon without the gray region and blue dot should appear Change-Id: I13f255d40e1471a4df56747af2304315c0588072 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/295765 Tested-by: Paulo Chaves <paulo.chaves@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Kai Bjorkman <kbjorkman@instructure.com> QA-Review: Kai Bjorkman <kbjorkman@instructure.com> Product-Review: Jody Sailor
2022-07-08 23:32:36 +08:00
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/rubric_comments/read", action: :rubric_assessments_read_state, as: "#{path_prefix}_submission_rubric_comments_read_state"
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/rubric_comments/read", action: :mark_rubric_assessments_read, as: "#{path_prefix}_submission_rubric_comments_mark_read"
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/rubric_assessments/read", action: :rubric_assessments_read_state, as: "#{path_prefix}_submission_rubric_assessments_read_state"
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/rubric_assessments/read", action: :mark_rubric_assessments_read, as: "#{path_prefix}_submission_rubric_assessments_mark_read"
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions", action: :index, as: "#{path_prefix}_assignment_submissions"
get "#{context.pluralize}/:#{context}_id/students/submissions", controller: :submissions_api, action: :for_students, as: "#{path_prefix}_student_submissions"
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id", action: :show, as: "#{path_prefix}_assignment_submission"
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/anonymous_submissions/:anonymous_id", action: :show_anonymous
post "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions", action: :create, controller: :submissions
post "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id/files", action: :create_file
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/:user_id", action: :update
put "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/anonymous_submissions/:anonymous_id", action: :update_anonymous
post "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submissions/update_grades", action: :bulk_update
get "#{context.pluralize}/:#{context}_id/assignments/:assignment_id/submission_summary", action: :submission_summary, as: "#{path_prefix}_assignment_submission_summary"
end
get "courses/:course_id/assignments/:assignment_id/gradeable_students", action: :gradeable_students, as: "course_assignment_gradeable_students"
end
scope(controller: :anonymous_provisional_grades) do
get "courses/:course_id/assignments/:assignment_id/anonymous_provisional_grades/status",
action: :status,
as: "course_assignment_anonymous_provisional_status"
end
Create OriginalityReport Api Create endpoint Fixes: PLAT-1906 Test Plan: - Create a new assignment with submission type online with file upload. - As a student submit a document as a submission for the assignment and get the Attachment id from the submission. - Make a post request to "/api/v1/assignments /:assignment_id/submissions/:submission_id/originality_report" with the following param in the body: "originality_report": { "external_tool_id":<id of the tool you installed>, "originality_score": <any value between 0 and 1> } - Verify a new OriginalityReport is created. - Verify create action fails if not all required params are given - Verify create action sets optional params correctly. - Verify the action requires all specified resources exists (file_id, and originality_score). - Verify the action does not allow creating a tool with an originality_score not in the 0..1 range. - Verify the action requires the attachment to be part of the submission. - verify the action requires the submission to be part of the assignment. Change-Id: Id5b0b61d399e4330c8c815bd4715735907f7cc6b Create OriginalityReport Api Create endpoint Fixes: PLAT-1906 Test Plan: - Create a new assignment with submission type online with file upload. - As a student submit a document as a submission for the assignment and get the Attachment id from the submission. - Make a post request to "/api/v1/assignments /:assignment_id/submissions/:submission_id/originality_report" with the following param in the body: "originality_report": { "external_tool_id":<id of the tool you installed>, "originality_score": <any value between 0 and 1> } - Verify a new OriginalityReport is created. - Verify create action fails if not all required params are given - Verify create action sets optional params correctly - Verify the action requires all specified resources exists (file_id, and originality_score). - Verify the action does not allow creating a tool with an originality_score not in the 0..1 range. - Verify the action requires the attachment to be part of the submission. - verify the action requires the submission to be part of the assignment. Change-Id: Id5b0b61d399e4330c8c815bd4715735907f7cc6b Reviewed-on: https://gerrit.instructure.com/94476 Tested-by: Jenkins Reviewed-by: Nathan Mills <nathanm@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2016-11-03 01:54:06 +08:00
copy to final provisional grade test plan: 1. create a moderated assignment 2. associate a rubric with the assignment 3. add a student to the moderation set, using g/63360, or if that's not available yet, the Rails console: assignment.moderated_grading_selections.create! student: student 4. submit to the assignment as a student 5. grade the assignment as a TA in speedgrader, commenting and marking the rubric in the process 6. as a teacher, view the submission using the "Get a single submission" API endpoint, including provisional_grades, submission_comments, and rubric_assessment GET /api/v1/courses/{course_id}/assignments/{assignment_id}/submissions/{user_id}?include[]=provisional_grades&include[]=submission_comments&include[]=rubric_assessment 7. retrieve the provisional_grade_id from the above, to use in the next step 8. as a teacher, call the copy_to_final_grade endpoint to copy the TA's provisional grade to the "final" provisional grade editable by moderators POST /api/v1/courses/{course_id}/assignments/{assignment_id}/provisional_grades/{provisional_grade_id}/copy_to_final_mark 9. as a teacher, repeat the GET from step 6 and ensure that the provisional grade appears twice, once with the TA as the scorer_id and once with the teacher - the teacher's entry should have final=true while the TA's is false - the comments and rubric assessment written by the TA should be included in the teacher's provisional grade, but still attributed to the TA's user id closes CNVS-23300 Change-Id: Id09f828ddb4c262ef5452a62702a3a1828091486 Reviewed-on: https://gerrit.instructure.com/63563 Reviewed-by: James Williams <jamesw@instructure.com> Tested-by: Jenkins QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com> Product-Review: Jeremy Stanley <jeremy@instructure.com>
2015-09-18 08:18:45 +08:00
scope(controller: :provisional_grades) do
add bulk selection for provisional grades closes GRADE-1480 test plan: A. Setup 1. Create a published course 2. Enroll one teacher 3. Enroll two TAs 4. Enroll three students 5. Create a moderated assignment * with Teacher as final grader 6. As the first TA: a. Visit SpeedGrader for the assignment b. Grade Student 1 c. Grade Student 2 7. As the second TA: a. Visit SpeedGrader for the assignment b. Grade Student 2 c. Grade Student 3 8. Open the Rails console 9. Note these attributes of the provisional grades: * `id` (provisional grade id) * `user_id` (student id) * `scorer_id` (grader id) assignment = Assignment.find(:id) assignment.pluck(:id, :user_id, :scorer_id) B. Verification without Anonymity * To test bulk selection, send a PUT request to: /api/v1/courses/:course_id/assignments/:assignment_id/ ↪ provisional_grades/bulk_select * Use a session for the final grader * Include in the request body an object as follows: {provisional_grade_ids: […]} * The array will contain some of the provisional grade ids noted from the Rails console * The response will include an array of objects as follows: { "assignment_id": "1", "selected_provisional_grade_id": "2", "student_id": "3" } * To verify grade selection: a. Log in or act as the Teacher b. Visit the moderation page for the assignment c. Verify the intended grades have been selected * Each of the following steps will be done in sequence without resetting anything to a prior state 1. Bulk select the following grades: * TA-1's grade for Student 1 * TA-2's grade for Student 2 2. Verify the JSON includes the following grades: * TA-1's grade for Student 1 * TA-2's grade for Student 2 3. Verify the following grades are selected: * TA-1's grade for Student 1 * TA-2's grade for Student 2 4. Bulk select the following grades: * TA-1's grade for Student 2 * TA-2's grade for Student 3 5. Verify the JSON includes the following grades: * TA-1's grade for Student 2 * TA-2's grade for Student 3 6. Verify the following grades are selected: * TA-1's grade for Student 1 * TA-1's grade for Student 2 * TA-2's grade for Student 3 7. Bulk select the following grades (listed in this order): * TA-1's grade for Student 1 * TA-2's grade for Student 3 * TA-1's grade for Student 3 8. Verify the JSON includes the following grades: * TA-1's grade for Student 3 9. Verify the following grades are selected: * TA-1's grade for Student 1 * TA-1's grade for Student 2 * TA-1's grade for Student 3 B. Verification with Anonymity 1. Enable anonymous grading for the assignment 2. Bulk select the following grades: * TA-2's grade for Student 2 * TA-2's grade for Student 3 3. Verify the JSON includes "anonymous_id" 4. Verify the JSON excludes "student_id" e1d4b3ee4d0d1a4bb647d7a149b57894d91bb503 Change-Id: I51190808a9dfd321c6110f50d6d0e4661fa86c1c Reviewed-on: https://gerrit.instructure.com/161215 Reviewed-by: Adrian Packel <apackel@instructure.com> Tested-by: Jenkins Reviewed-by: Gary Mei <gmei@instructure.com> QA-Review: James Butters <jbutters@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2018-08-18 03:09:54 +08:00
put "courses/:course_id/assignments/:assignment_id/provisional_grades/bulk_select",
action: :bulk_select,
as: "bulk_select_provisional_grades"
get "courses/:course_id/assignments/:assignment_id/provisional_grades/status",
action: :status,
as: "course_assignment_provisional_status"
post "courses/:course_id/assignments/:assignment_id/provisional_grades/publish",
action: :publish,
as: "publish_provisional_grades"
put "courses/:course_id/assignments/:assignment_id/provisional_grades/:provisional_grade_id/select",
action: :select,
as: "select_provisional_grade"
copy to final provisional grade test plan: 1. create a moderated assignment 2. associate a rubric with the assignment 3. add a student to the moderation set, using g/63360, or if that's not available yet, the Rails console: assignment.moderated_grading_selections.create! student: student 4. submit to the assignment as a student 5. grade the assignment as a TA in speedgrader, commenting and marking the rubric in the process 6. as a teacher, view the submission using the "Get a single submission" API endpoint, including provisional_grades, submission_comments, and rubric_assessment GET /api/v1/courses/{course_id}/assignments/{assignment_id}/submissions/{user_id}?include[]=provisional_grades&include[]=submission_comments&include[]=rubric_assessment 7. retrieve the provisional_grade_id from the above, to use in the next step 8. as a teacher, call the copy_to_final_grade endpoint to copy the TA's provisional grade to the "final" provisional grade editable by moderators POST /api/v1/courses/{course_id}/assignments/{assignment_id}/provisional_grades/{provisional_grade_id}/copy_to_final_mark 9. as a teacher, repeat the GET from step 6 and ensure that the provisional grade appears twice, once with the TA as the scorer_id and once with the teacher - the teacher's entry should have final=true while the TA's is false - the comments and rubric assessment written by the TA should be included in the teacher's provisional grade, but still attributed to the TA's user id closes CNVS-23300 Change-Id: Id09f828ddb4c262ef5452a62702a3a1828091486 Reviewed-on: https://gerrit.instructure.com/63563 Reviewed-by: James Williams <jamesw@instructure.com> Tested-by: Jenkins QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com> Product-Review: Jeremy Stanley <jeremy@instructure.com>
2015-09-18 08:18:45 +08:00
end
scope(controller: :submission_comments_api) do
post "/courses/:course_id/assignments/:assignment_id/submissions/:user_id/comments/files", action: :create_file
put "courses/:course_id/assignments/:assignment_id/submissions/:user_id/comments/:id", action: :update
delete "courses/:course_id/assignments/:assignment_id/submissions/:user_id/comments/:id", action: :destroy
end
post "/courses/:course_id/assignments/:assignment_id/submissions/:user_id/annotation_notification", action: :annotation_notification, controller: :submission_comments_api
scope(controller: :gradebook_history_api) do
get "courses/:course_id/gradebook_history/days", action: :days, as: "gradebook_history"
get "courses/:course_id/gradebook_history/feed", action: :feed, as: "gradebook_history_feed"
get "courses/:course_id/gradebook_history/:date", action: :day_details, as: "gradebook_history_for_day"
get "courses/:course_id/gradebook_history/:date/graders/:grader_id/assignments/:assignment_id/submissions", action: :submissions, as: "gradebook_history_submissions"
gradebook history api fixes #CNVS-2802 This provides a reimplementation of the functionality in 'lib/submission_list.rb'. That lib file has been used to produce a grade book history page, but it loads the entire history of the course at once, which is untenable. This take all the same data, and provides it through a paginated API endpoint. Using this API, a rich front end will be possible to create in order to replace the current large grade book history page, one that makes API calls to reveal data further d own the tree as it is requested. This is an unusual API endpoint in that it does not present data as it is in the database, there is a series of transformations that the submission data is put through to arrive at a versioned history where each node contains within itself some contextual knowledge of the flow of the submission progress (each version knows what the grade of the version before it was, and what the grade is today, for example). TEST PLAN: This is a new API endpoint and does not yet get used by any front end code yet. It can be played with by performing some valid API queries against the following paths: /courses/:course_id/gradebook_history/days /courses/:course_id/gradebook_history/:date ^ date is like "2013-01-31" ^ /courses/:course_id/gradebook_history/:date/graders/:grader_id/assignments/:assignment_id/submissions (yes, that last one is huge, but it does follow the nested structure described by the original grade book history page). The user that is selected for testing needs to have the "manage_grades" permission on the referenced course. API documentation is available on the controller class app/controllers/gradebook_history_api_controller.rb Change-Id: I18e0b4b967d6c20ad47b86e98adbc15b87276098 Reviewed-on: https://gerrit.instructure.com/17366 QA-Review: Clare Hetherington <clare@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Brian Palmer <brianp@instructure.com>
2013-02-01 08:35:16 +08:00
end
get "courses/:course_id/assignment_groups", controller: :assignment_groups, action: :index
scope(controller: :assignment_groups_api) do
resources :assignment_groups, path: "courses/:course_id/assignment_groups", name_prefix: "course_", except: :index
end
scope(controller: :discussion_topics) do
get "courses/:course_id/discussion_topics", action: :index, as: "course_discussion_topics"
get "groups/:group_id/discussion_topics", action: :index, as: "group_discussion_topics"
end
scope(controller: :content_migrations) do
%w[account course group user].each do |context|
get "#{context.pluralize}/:#{context}_id/content_migrations/migrators", action: :available_migrators, as: "#{context}_content_migration_migrators_list"
get "#{context.pluralize}/:#{context}_id/content_migrations/:id", action: :show, as: "#{context}_content_migration"
get "#{context.pluralize}/:#{context}_id/content_migrations", action: :index, as: "#{context}_content_migration_list"
post "#{context.pluralize}/:#{context}_id/content_migrations", action: :create, as: "#{context}_content_migration_create"
put "#{context.pluralize}/:#{context}_id/content_migrations/:id", action: :update, as: "#{context}_content_migration_update"
get "#{context.pluralize}/:#{context}_id/content_migrations/:id/selective_data", action: :content_list, as: "#{context}_content_migration_selective_data"
end
get "courses/:course_id/content_migrations/:id/asset_id_mapping", action: :asset_id_mapping
end
scope(controller: :migration_issues) do
%w[account course group user].each do |context|
get "#{context.pluralize}/:#{context}_id/content_migrations/:content_migration_id/migration_issues/:id", action: :show, as: "#{context}_content_migration_migration_issue"
get "#{context.pluralize}/:#{context}_id/content_migrations/:content_migration_id/migration_issues", action: :index, as: "#{context}_content_migration_migration_issue_list"
post "#{context.pluralize}/:#{context}_id/content_migrations/:content_migration_id/migration_issues", action: :create, as: "#{context}_content_migration_migration_issue_create"
put "#{context.pluralize}/:#{context}_id/content_migrations/:content_migration_id/migration_issues/:id", action: :update, as: "#{context}_content_migration_migration_issue_update"
end
end
scope(controller: :discussion_topics_api) do
2015-06-26 03:35:25 +08:00
%w[course group].each do |context|
put "#{context.pluralize}/:#{context}_id/discussion_topics/read_all", action: :mark_all_topic_read, as: "#{context}_discussion_mark_all_read"
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/read", action: :mark_topic_read, as: "#{context}_discussion_topic_mark_read"
delete "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/read", action: :mark_topic_unread, as: "#{context}_discussion_topic_mark_unread"
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/read_all", action: :mark_all_read, as: "#{context}_discussion_topic_mark_all_read"
delete "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/read_all", action: :mark_all_unread, as: "#{context}_discussion_topic_mark_all_unread"
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:entry_id/read", action: :mark_entry_read, as: "#{context}_discussion_topic_discussion_entry_mark_read"
delete "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:entry_id/read", action: :mark_entry_unread, as: "#{context}_discussion_topic_discussion_entry_mark_unread"
get "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id", action: :show, as: "#{context}_discussion_topic"
post "#{context.pluralize}/:#{context}_id/discussion_topics", controller: :discussion_topics, action: :create
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id", controller: :discussion_topics, action: :update
post "#{context.pluralize}/:#{context}_id/discussion_topics/reorder", controller: :discussion_topics, action: :reorder
delete "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id", controller: :discussion_topics, action: :destroy
get "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/view", action: :view, as: "#{context}_discussion_topic_view"
get "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/summaries", action: :summary, as: "#{context}_discussion_topic_summary"
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/summaries/disable", action: :disable_summary, as: "#{context}_discussion_topic_disable_summary"
post "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/summaries/:summary_id/feedback", action: :summary_feedback, as: "#{context}_discussion_topic_summary_feedback"
post "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/duplicate", action: :duplicate
get "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entry_list", action: :entry_list, as: "#{context}_discussion_topic_entry_list"
post "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries", action: :add_entry, as: "#{context}_discussion_add_entry"
get "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries", action: :entries, as: "#{context}_discussion_entries"
post "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:entry_id/replies", action: :add_reply, as: "#{context}_discussion_add_reply"
get "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:entry_id/replies", action: :replies, as: "#{context}_discussion_replies"
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:id", controller: :discussion_entries, action: :update, as: "#{context}_discussion_update_reply"
delete "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:id", controller: :discussion_entries, action: :destroy, as: "#{context}_discussion_delete_reply"
post "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/entries/:entry_id/rating",
action: :rate_entry,
as: "#{context}_discussion_topic_discussion_entry_rate"
put "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/subscribed", action: :subscribe_topic, as: "#{context}_discussion_topic_subscribe"
delete "#{context.pluralize}/:#{context}_id/discussion_topics/:topic_id/subscribed", action: :unsubscribe_topic, as: "#{context}_discussion_topic_unsubscribe"
end
finish discussion topics API supports creating and listing top-level entries in a discussion topic, and creating and listing replies to a discussion entry. listing discussion topics was already supported. includes support for attachments on top-level entries. test-plan: creating an entry under a topic should allow creating an entry under a topic and create it correctly should return json representation of the new entry should allow creating a reply to an existing top-level entry should not allow reply-to-reply should allow including attachments on top-level entries should silently ignore attachments on replies to top-level entries should include attachment info in the json response listing top-level discussion entries should return top level entries for a topic should return attachments on top level entries should include replies on top level entries should sort top-level entries by descending created_at should sort replies included on top-level entries by descending created_at should paginate top-level entries should only include the first 10 replies for each top-level entry listing replies should return replies for an entry should sort replies by descending created_at should paginate replies require initial post should allow admins to see posts without posting shouldn't allow student who hasn't posted to see shouldn't allow student's observer who hasn't posted to see should allow student who has posted to see should allow student's observer who has posted to see fixes #4752 Change-Id: I0da83e6c301be74f1ac5d2d957ebb6338a98179c Reviewed-on: https://gerrit.instructure.com/6690 Tested-by: Hudson <hudson@instructure.com> Reviewed-by: Cody Cutrer <cody@instructure.com>
2011-11-04 05:51:29 +08:00
end
scope(controller: :discussion_topic_users) do
get "courses/:course_id/discussion_topics/:topic_id/messageable_users", action: :search, as: "course_discussion_messageable_users"
get "groups/:group_id/discussion_topics/:topic_id/messageable_users", action: :search, as: "group_discussion_messageable_users"
end
scope(controller: :collaborations) do
get "collaborations/:id/members", action: :members, as: "collaboration_members"
get "courses/:course_id/potential_collaborators", action: :potential_collaborators, as: "course_potential_collaborators"
get "groups/:group_id/potential_collaborators", action: :potential_collaborators, as: "group_potential_collaborators"
end
scope(controller: "microsoft_sync/groups") do
post "courses/:course_id/microsoft_sync/group", action: :create
get "courses/:course_id/microsoft_sync/group", action: :show
delete "courses/:course_id/microsoft_sync/group", action: :destroy
Add button to schedule MSFT sync refs INTEROP-6575 flag=microsoft_group_enrollments_syncing Test Plan: - Set up your local environment for microsoft enrollment syncing using the steps in the test plan from g/260232 (if needed) - Enable the MSFT sync flag in your root account if needed - Navigate to a course with students - Go to settings -> integrations and enable the MSFT sync integration (if needed) - Click "Sync now" - validate that a spinner is shown while a network request is being made - verify a "success" message is show indicating a sync has been scheduled - verify that after a few seconds, this message becomes an info message indicating a sync currently taking place and that the user should wait before starting another. - Verify the "Sync Now" button is disabled - Run jobs - When all scheduled jobs have completed, check to see that the MSFT sync completed: MicrosoftSync::Group.find_by( course_id: <your course id> ).workflow_state == 'completed' - Referesh the page and go back to the integrations UI. Expand the details for the MSFT integration - Verify that a message is shown indicating the time remaining until the user can manually sync again - Verify the "Sync Now" button is disabled - In a rails console, reset the "last manual sync time" with MicrosoftSync::Group.find_by( course_id: <your course id> ).update!( last_manually_synced_at: 90.minutes.ago ) - Refresh the page, go to the integrations tab, and expand the MSFT sync details. - Verify the "Sync Now" button is enabled (but don't click on it yet). - Modify the "sync" action in controllers/microsoft_sync /groups_controller.rb so that the first line of the method is `head :internal_server_error and return` We just need to simulate an error temporarily. - Click the "Sync Now" button. Verify an error message is shown. - Remove the "head :internal_server_error" line from the controller - Without refreshing the page, click the "sync now" button again. Verify the error message is replaced with a success message (which transitions to an info message, as before). - Verify toggling the MSFT sync integration on/off works as before - Any other test that come to mind :) Change-Id: I99bb0a1d7f3708e4dc4784dbd1624c31292beeb0 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/262881 Reviewed-by: Xander Moffatt <xmoffatt@instructure.com> Reviewed-by: Evan Battaglia <ebattaglia@instructure.com> QA-Review: Xander Moffatt <xmoffatt@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Karl Lloyd <karl@instructure.com>
2021-04-14 13:06:29 +08:00
post "courses/:course_id/microsoft_sync/schedule_sync", action: :sync
end
scope(controller: :external_tools) do
post "/accounts/:account_id/external_tools/rce_favorites/:id", action: :add_rce_favorite, as: :account_external_tools_add_rce_favorite
delete "/accounts/:account_id/external_tools/rce_favorites/:id", action: :remove_rce_favorite, as: :account_external_tools_remove_rce_favorite
get "/courses/:course_id/external_tools/visible_course_nav_tools", action: :visible_course_nav_tools, as: :visible_course_nav_tools
Batch fetch course LTIs on the C4E dashboard This change updates the C4E dashboard to fetch LTIs in a single request instead of one request per card. To support this, a new all_visible_nav_tools API has been added in addition to the context-specific visible_course_nav_tools API that takes a context_codes[] parameter to indicate which contexts to retrieve LTIs for. fixes LS-2261 refs LS-2227 flag = none Test plan: - Log in as a teacher in a C4E course and go to their dashboard - Go to the Resources tab, expect to see buttons for all LTIs with course placements on the courses the teacher is enrolled in - If an LTI is installed in more than one course, expect clicking on the LTI's button to show a modal indicating in which course the LTI should launch - If an LTI is installed in only one course, expect clicking the button to directly launch the LTI in the course - Go to a C4E course with multiple LTIs as the teacher of the course - Expect the LTIs to show up on the Resources tab of the course's home page - Expect clicking the buttons to launch the LTIs directly - Go to the navigation tab of the course's settings page - Change the order of the LTIs, click update, and expect the new order to be reflected on the Resources tab - Go back to the navigation settings and hide one of the LTIs - Expect that LTI to no longer show up on the Resources tab - Also expect that LTI to no longer show up on the dashboard's Resources tab (for that course) Change-Id: If1516a33a93874b14ada1a1c3b32814447877163 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/265673 Reviewed-by: Nate Armstrong <narmstrong@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Nate Armstrong <narmstrong@instructure.com> Product-Review: Jeff Largent <jeff.largent@instructure.com>
2021-05-25 12:28:45 +08:00
get "/external_tools/visible_course_nav_tools", action: :all_visible_nav_tools, as: :all_visible_nav_tools
2015-06-26 03:35:25 +08:00
%w[course account].each do |context|
get "#{context}s/:#{context}_id/external_tools/sessionless_launch", action: :generate_sessionless_launch, as: "#{context}_external_tool_sessionless_launch"
get "#{context}s/:#{context}_id/external_tools/:external_tool_id", action: :show, as: "#{context}_external_tool_show"
get "#{context}s/:#{context}_id/external_tools", action: :index, as: "#{context}_external_tools"
post "#{context}s/:#{context}_id/external_tools", action: :create, as: "#{context}_external_tools_create"
post "#{context}s/:#{context}_id/create_tool_with_verification", action: :create_tool_with_verification, as: "#{context}_create_tool_with_verification"
put "#{context}s/:#{context}_id/external_tools/:external_tool_id", action: :update, as: "#{context}_external_tools_update"
delete "#{context}s/:#{context}_id/external_tools/:external_tool_id", action: :destroy, as: "#{context}_external_tools_delete"
end
get "groups/:group_id/external_tools", action: :index, as: "group_external_tools"
end
scope(controller: "lti/lti_apps") do
2015-06-26 03:35:25 +08:00
%w[course account].each do |context|
get "#{context}s/:#{context}_id/lti_apps/launch_definitions", action: :launch_definitions, as: "#{context}_launch_definitions"
get "#{context}s/:#{context}_id/lti_apps", action: :index, as: "#{context}_app_definitions"
end
end
scope(controller: "lti/tool_proxy") do
2015-06-26 03:35:25 +08:00
%w[course account].each do |context|
delete "#{context}s/:#{context}_id/tool_proxies/:tool_proxy_id",
action: :destroy,
as: "#{context}_delete_tool_proxy"
put "#{context}s/:#{context}_id/tool_proxies/:tool_proxy_id",
action: :update,
as: "#{context}_update_tool_proxy"
delete "#{context}s/:#{context}_id/tool_proxies/:tool_proxy_id/update",
action: :dismiss_update,
as: "#{context}_dismiss_update_tool_proxy"
put "#{context}s/:#{context}_id/tool_proxies/:tool_proxy_id/update",
action: :accept_update,
as: "#{context}_accept_update_tool_proxy"
end
end
scope(controller: :external_feeds) do
2015-06-26 03:35:25 +08:00
%w[course group].each do |context|
get "#{context}s/:#{context}_id/external_feeds", action: :index, as: "#{context}_external_feeds"
post "#{context}s/:#{context}_id/external_feeds", action: :create, as: "#{context}_external_feeds_create"
delete "#{context}s/:#{context}_id/external_feeds/:external_feed_id", action: :destroy, as: "#{context}_external_feeds_delete"
new discussion topics/announcement index, edit and create closes: #7172 test plan: * open discussion topic index page: - see how it looks in blank course - full course - try graded & unread filters (make sure you see things you expect to and not those you don't) - do bulk actions by clicking checkbox for a few and hitting delete and lock buttons - verify infinite scroll works - verify that as a student you don't see posts that had delayed posting - click "create new" button to make a new one, make sure it works - do all the above in the announcement index page * while viewing announcements index: - verify teacher can create external feed on right - no right side unless external feeds exist or they are teacher - external feeds are listed - only teacher can delete external feed * while editing/creating new discussion/announcement - verify that announcement cant be made into assignment - for discussion topic, set as assignment and make sure the assignment settings set. - cant change discussion -> announcement (& vise versa) - type crazy & blank input, verify that it validates it for you - title cant be longer than 254 - make sure these features work: - podcast feed - student posts in podcast feed - delayed posting - toggling threaded/unthreaded - must post before seeing replies - attach file, remove file attachment, upload new attachment should work * make sure announcements/discussions look & behave right in other places they show up (like course, user dashboard) * if you can think of any other places where you can edit/create discussions/announcements, make sure that still works Change-Id: Ib0acaff8542bf09f99cd7aa99fb3ed16c999d224 Reviewed-on: https://gerrit.instructure.com/12655 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-08-01 07:22:48 +08:00
end
end
scope(controller: :sis_imports_api) do
post "accounts/:account_id/sis_imports", action: :create
put "accounts/:account_id/sis_imports/abort_all_pending", action: :abort_all_pending
get "accounts/:account_id/sis_imports/importing", action: :importing
get "accounts/:account_id/sis_imports/:id", action: :show
get "accounts/:account_id/sis_imports", action: :index, as: "account_sis_imports"
put "accounts/:account_id/sis_imports/:id/abort", action: :abort
put "accounts/:account_id/sis_imports/:id/restore_states", action: :restore_states
end
scope(controller: :sis_import_errors_api) do
get "accounts/:account_id/sis_imports/:id/errors", action: :index, as: :sis_batch_import_errors
get "accounts/:account_id/sis_import_errors", action: :index, as: :account_sis_import_errors
end
Outcome import creation/status endpoints closes OUT-1534 Scheduling of outcome import jobs will occur in a separate PS, after this merges and OUT-1997 is merged too. test plan: - start up canvas - generate api docs: > docker-compose run --rm web bundle exec rake doc:api - load api docs in http://canvas.docker/doc/api/index.html - read over the "Outcomes CSV Format" and make sure it reads well - read over the "Outcomes Import" and make sure it reads well - obtain an access token: https://community.canvaslms.com/docs/DOC-10806-4214724194 - request an outcome import, replace "canvas-path" and "token" values: curl -F attachment=@<canvas-path>/spec/lib/outcomes/fixtures/demo.csv \ -F 'import_type=instructure_csv' \ -H "Authorization: Bearer <token>" \ http://canvas.docker/api/v1/accounts/1/outcome_imports - in a rails console, confirm that the import was accepted: > docker-compose run --rm web bin/rails console % pp OutcomeImport.last # confirm that the import is in the 'created' state, associated with your user and associated with an account context # note the "id" value for later use % pp OutcomeImport.last.attachment # confirm that the attachment is in the 'processed' state and has the filename "test_outcomes_1.csv" passed in above - request the status of the outcome import (should return a message saying "The specified resource does not exist"): curl -H "Authorization: Bearer <token>" \ http://canvas.docker/api/v1/accounts/1/outcome_imports/latest - back in the rails console created above, manually transition the import to "importing": % OutcomeImport.last.job_started - run the above curl command again, and this time the latest outcome import should be returned, in the 'importing' state - run the above curl command again, replacing "latest" with the "id" value obtained above. it should return the same response as the previous step. Change-Id: Ice7d67b625b443cec70f531f2e673face6d6fbeb Reviewed-on: https://gerrit.instructure.com/142024 Reviewed-by: Neil Gupta <ngupta@instructure.com> Reviewed-by: Frank Murphy <fmurphy@instructure.com> Tested-by: Jenkins QA-Review: Frank Murphy <fmurphy@instructure.com> Product-Review: Neil Gupta <ngupta@instructure.com>
2018-02-24 06:18:42 +08:00
scope(controller: :outcome_imports_api) do
%w[account course].each do |context|
post "#{context}s/:#{context}_id/outcome_imports(/group/:learning_outcome_group_id)", action: :create
Outcome import creation/status endpoints closes OUT-1534 Scheduling of outcome import jobs will occur in a separate PS, after this merges and OUT-1997 is merged too. test plan: - start up canvas - generate api docs: > docker-compose run --rm web bundle exec rake doc:api - load api docs in http://canvas.docker/doc/api/index.html - read over the "Outcomes CSV Format" and make sure it reads well - read over the "Outcomes Import" and make sure it reads well - obtain an access token: https://community.canvaslms.com/docs/DOC-10806-4214724194 - request an outcome import, replace "canvas-path" and "token" values: curl -F attachment=@<canvas-path>/spec/lib/outcomes/fixtures/demo.csv \ -F 'import_type=instructure_csv' \ -H "Authorization: Bearer <token>" \ http://canvas.docker/api/v1/accounts/1/outcome_imports - in a rails console, confirm that the import was accepted: > docker-compose run --rm web bin/rails console % pp OutcomeImport.last # confirm that the import is in the 'created' state, associated with your user and associated with an account context # note the "id" value for later use % pp OutcomeImport.last.attachment # confirm that the attachment is in the 'processed' state and has the filename "test_outcomes_1.csv" passed in above - request the status of the outcome import (should return a message saying "The specified resource does not exist"): curl -H "Authorization: Bearer <token>" \ http://canvas.docker/api/v1/accounts/1/outcome_imports/latest - back in the rails console created above, manually transition the import to "importing": % OutcomeImport.last.job_started - run the above curl command again, and this time the latest outcome import should be returned, in the 'importing' state - run the above curl command again, replacing "latest" with the "id" value obtained above. it should return the same response as the previous step. Change-Id: Ice7d67b625b443cec70f531f2e673face6d6fbeb Reviewed-on: https://gerrit.instructure.com/142024 Reviewed-by: Neil Gupta <ngupta@instructure.com> Reviewed-by: Frank Murphy <fmurphy@instructure.com> Tested-by: Jenkins QA-Review: Frank Murphy <fmurphy@instructure.com> Product-Review: Neil Gupta <ngupta@instructure.com>
2018-02-24 06:18:42 +08:00
get "#{context}s/:#{context}_id/outcome_imports/:id", action: :show
Allow the user to import into a specific group in the UI closes OUT-4683 flag=improved_outcomes_management Test plan: - create or download fixture CSV files: - CSV file with NO parent_guid: vendor_guid,object_type,title new_outcome,outcome,New Outcome https://bit.ly/32pJ6VD - CSV file with parent_guid: vendor_guid,object_type,title,parent_guids new_group_from_csv,group,New Group from CSV, new_outcome,outcome,New Outcome from CSV,new_group_from_csv https://bit.ly/3oLLX2C - at the default account level: - navigate to `Outcomes` - create a child group with title 'Child Group' - select `Child Group` and click in the import button at the header - import `CSV file with NO parent_guid` - assert that, at the root group: - there's a new outcome titled `New Outcome` - select `Child Group` and click in the import button at the header - import `CSV file with parent_guid` - assert that, at the root group: - there's a new group titled `New Group from CSV`: - containing an outcome titled `New Outcome from CSV` - select `Child Group` and click in the import option from the kebab - import `CSV file with NO parent_guid` - assert that, at `Child Group`: - there's a new Outcome titled `New Outcome` - select `Child Group` and click in the import option from the kebab - import `CSV file with parent_guid` - refresh the page (TODO, OUT-4798) - assert that, at `Child Group`: - there's a new group titled `New Group from CSV`: - containing an outcome titled `New Outcome from CSV` - create a course: - repeat these steps at the course level Change-Id: I568e85a636d8b84d20f12640bad52e6b19023978 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/274711 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Kyle Rosenbaum <krosenbaum@instructure.com> QA-Review: Chrystal Langston <chrystal.langston@instructure.com> Product-Review: Ben Friedman <ben.friedman@instructure.com>
2021-11-01 05:10:09 +08:00
get "#{context}s/:#{context}_id/outcome_imports/:id/created_group_ids", action: :created_group_ids
Outcome import creation/status endpoints closes OUT-1534 Scheduling of outcome import jobs will occur in a separate PS, after this merges and OUT-1997 is merged too. test plan: - start up canvas - generate api docs: > docker-compose run --rm web bundle exec rake doc:api - load api docs in http://canvas.docker/doc/api/index.html - read over the "Outcomes CSV Format" and make sure it reads well - read over the "Outcomes Import" and make sure it reads well - obtain an access token: https://community.canvaslms.com/docs/DOC-10806-4214724194 - request an outcome import, replace "canvas-path" and "token" values: curl -F attachment=@<canvas-path>/spec/lib/outcomes/fixtures/demo.csv \ -F 'import_type=instructure_csv' \ -H "Authorization: Bearer <token>" \ http://canvas.docker/api/v1/accounts/1/outcome_imports - in a rails console, confirm that the import was accepted: > docker-compose run --rm web bin/rails console % pp OutcomeImport.last # confirm that the import is in the 'created' state, associated with your user and associated with an account context # note the "id" value for later use % pp OutcomeImport.last.attachment # confirm that the attachment is in the 'processed' state and has the filename "test_outcomes_1.csv" passed in above - request the status of the outcome import (should return a message saying "The specified resource does not exist"): curl -H "Authorization: Bearer <token>" \ http://canvas.docker/api/v1/accounts/1/outcome_imports/latest - back in the rails console created above, manually transition the import to "importing": % OutcomeImport.last.job_started - run the above curl command again, and this time the latest outcome import should be returned, in the 'importing' state - run the above curl command again, replacing "latest" with the "id" value obtained above. it should return the same response as the previous step. Change-Id: Ice7d67b625b443cec70f531f2e673face6d6fbeb Reviewed-on: https://gerrit.instructure.com/142024 Reviewed-by: Neil Gupta <ngupta@instructure.com> Reviewed-by: Frank Murphy <fmurphy@instructure.com> Tested-by: Jenkins QA-Review: Frank Murphy <fmurphy@instructure.com> Product-Review: Neil Gupta <ngupta@instructure.com>
2018-02-24 06:18:42 +08:00
end
end
Outcome proficiency endpoints closes OUT-1855, OUT-2214 test plan: - create an access token, which will be used below to perform HTTP requests, see: https://canvas.instructure.com/doc/api/file.oauth.html#using-access-tokens - using a tool like Postman, set an outcome proficiency for an account. perform a POST request at the endpoint `http://canvas.docker/api/v1/accounts/1/outcome_proficiency` with a `Content-Type` header value `application/json` and body with content like: { "ratings": [ { "description": "great work", "points": 10, "mastery": true, "color": "00ff00" } ] } - retrieve the saved proficiency by performing GET request at the endpoint `http://canvas.docker/api/v1/accounts/1/outcome_proficiency`. it should match the proficiency created above. - update the proficiency by doing another POST request, but with multiple ratings, like: { "ratings": [ { "description": "great work", "points": 10, "mastery": true, "color": "00ff00" }, { "description": "bad work", "points": 0, "mastery": false, "color": "ff0000" } ] } - do a GET request to confirm the above changes were saved - do several other POST requests with multiple ratings that contain either multiple mastery ratings or none. these requests should fail with a 422 status code and an error message that contains `Only one rating can have mastery`. Change-Id: Ib301c0394a99dbf55d7d85ceef28a95075faaec2 Reviewed-on: https://gerrit.instructure.com/150095 Reviewed-by: Frank Murphy <fmurphy@instructure.com> Tested-by: Jenkins Reviewed-by: Rob Orton <rob@instructure.com> Reviewed-by: Matt Berns <mberns@instructure.com> QA-Review: Andrew Porter <hporter-c@instructure.com> Product-Review: Michael Brewer-Davis <mbd@instructure.com>
2018-04-14 06:16:16 +08:00
scope(controller: :outcome_proficiency_api) do
post "accounts/:account_id/outcome_proficiency", action: :create
get "accounts/:account_id/outcome_proficiency", action: :show
add mastery scale view to course outcomes ui Given the account level mastery scales feature flag is enabled When I view a course’s Outcomes tab Then I see the same Mastery/Calculation tabs that are available on the accounts page I can edit the course mastery scale/calculation methods if I have permission I cannot edit these if I don’t have permissions closes OUT-3880 flag=account_level_mastery_scales test plan: - as Admin, enable "Account-level Mastery Scales" - Go to any course's admin view (like http://canvas.docker/courses/1), - Go to outcomes - You should see Manage, Mastery and Calculation tabs - Click on Mastery tab - You should see Mastery form exactly like the account outcomes Mastery Tab - Edit and save this form - Click on Calculation tab - You should see Calculation form exactly like the account outcomes Calculation Tab - Edit and save this form - Go to account's outcomes (like http://canvas.docker/accounts/2/outcomes) - Navigate thought those tabs and check those values are not equal to the course`s outcomes - Try to repeat the process to different course and check the form values are not equal to every course Change-Id: I3304a1553b147280ef94033b9f1063e2df986165 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/249407 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Michael Brewer-Davis <mbd@instructure.com> Reviewed-by: Pat Renner <prenner@instructure.com> QA-Review: Pablo Gomez <pablo.gomez@instructure.com> Product-Review: Jody Sailor
2020-10-07 03:16:28 +08:00
post "courses/:course_id/outcome_proficiency", action: :create
get "courses/:course_id/outcome_proficiency", action: :show
Outcome proficiency endpoints closes OUT-1855, OUT-2214 test plan: - create an access token, which will be used below to perform HTTP requests, see: https://canvas.instructure.com/doc/api/file.oauth.html#using-access-tokens - using a tool like Postman, set an outcome proficiency for an account. perform a POST request at the endpoint `http://canvas.docker/api/v1/accounts/1/outcome_proficiency` with a `Content-Type` header value `application/json` and body with content like: { "ratings": [ { "description": "great work", "points": 10, "mastery": true, "color": "00ff00" } ] } - retrieve the saved proficiency by performing GET request at the endpoint `http://canvas.docker/api/v1/accounts/1/outcome_proficiency`. it should match the proficiency created above. - update the proficiency by doing another POST request, but with multiple ratings, like: { "ratings": [ { "description": "great work", "points": 10, "mastery": true, "color": "00ff00" }, { "description": "bad work", "points": 0, "mastery": false, "color": "ff0000" } ] } - do a GET request to confirm the above changes were saved - do several other POST requests with multiple ratings that contain either multiple mastery ratings or none. these requests should fail with a 422 status code and an error message that contains `Only one rating can have mastery`. Change-Id: Ib301c0394a99dbf55d7d85ceef28a95075faaec2 Reviewed-on: https://gerrit.instructure.com/150095 Reviewed-by: Frank Murphy <fmurphy@instructure.com> Tested-by: Jenkins Reviewed-by: Rob Orton <rob@instructure.com> Reviewed-by: Matt Berns <mberns@instructure.com> QA-Review: Andrew Porter <hporter-c@instructure.com> Product-Review: Michael Brewer-Davis <mbd@instructure.com>
2018-04-14 06:16:16 +08:00
end
scope(controller: :users) do
get "users/self/activity_stream", action: :activity_stream, as: "user_activity_stream"
get "users/activity_stream", action: :activity_stream # deprecated
get "users/self/activity_stream/summary", action: :activity_stream_summary, as: "user_activity_stream_summary"
delete "users/self/activity_stream/:id", action: "ignore_stream_item"
delete "users/self/activity_stream", action: "ignore_all_stream_items"
put "users/:user_id/followers/self", action: :follow
delete "users/:user_id/followers/self", action: :unfollow
get "users/self/todo", action: :todo_items, as: "user_todo_list_items"
get "users/self/todo_item_count", action: :todo_item_count
get "users/self/upcoming_events", action: :upcoming_events
get "users/:user_id/missing_submissions", action: :missing_submissions, as: "user_missing_submissions"
delete "users/self/todo/:asset_string/:purpose", action: :ignore_item, as: "users_todo_ignore"
post "accounts/:account_id/users", action: :create
post "accounts/:account_id/self_registration", action: :create_self_registered_user
get "accounts/:account_id/users", action: :api_index, as: "account_users"
get "users/:id", action: :api_show
put "users/:id", action: :update
delete "users/mobile_sessions", action: :expire_mobile_sessions
delete "users/:id", action: :destroy, as: "destroy_user"
delete "users/:id/sessions", action: :terminate_sessions
post "users/:user_id/files", action: :create_file
get "users/:user_id/files", controller: :files, action: :api_index, as: "user_files"
get "users/:user_id/folders", controller: :folders, action: :list_all_folders, as: "user_folders"
post "users/:user_id/folders", controller: :folders, action: :create
get "users/:user_id/folders/by_path/*full_path", controller: :folders, action: :resolve_path
get "users/:user_id/folders/by_path", controller: :folders, action: :resolve_path
get "users/:user_id/folders/:id", controller: :folders, action: :show, as: "user_folder"
get "users/:id/settings", controller: "users", action: "settings"
put "users/:id/settings", controller: "users", action: "settings", as: "user_settings"
get "users/:id/colors", controller: "users", action: "get_custom_colors"
get "users/:id/colors/:asset_string", controller: "users", action: "get_custom_color"
put "users/:id/colors/:asset_string", controller: "users", action: "set_custom_color"
get "users/:id/new_user_tutorial_statuses", action: "get_new_user_tutorial_statuses"
put "users/:id/new_user_tutorial_statuses/:page_name", action: "set_new_user_tutorial_status"
get "users/:id/dashboard_positions", controller: "users", action: "get_dashboard_positions"
put "users/:id/dashboard_positions", controller: "users", action: "set_dashboard_positions"
put "users/:id/merge_into/:destination_user_id", controller: "users", action: "merge_into"
put "users/:id/merge_into/accounts/:destination_account_id/users/:destination_user_id", controller: "users", action: "merge_into"
post "users/:id/split", controller: "users", action: "split", as: "split"
post "users/self/pandata_events_token", controller: "users", action: "pandata_events_token"
get "dashboard/dashboard_cards", controller: "users", action: "dashboard_cards", as: :dashboard_dashboard_cards
get "users/:id/graded_submissions", controller: "users", action: "user_graded_submissions", as: :user_submissions
Consider only non-observer enrollments in k5_user? If an observer is observing k5 students, but they themself have only classic (teacher or student) enrollments, then show them the classic dashboard when they're selected. uncached_k5_user? will only consider non-observer enrollments since we'll calculate k5_user? separately when an observee is selected. Also, only allow disabling/re-enabling the k5 dashboard if the observer themself is selected in the picker. If a student is selected, the student's true dashboard is loaded and options to disable are removed. This change also improves how k5_user? is used. It no longer accepts `user` or `course_ids` as kwargs, and instead will pass either the @current_user or the @selected_observed_user (with appropriate course_ids) to uncached_k5_user? as appropriate, relieving the caller from making that determination. It also simplifies uncached_k5_user by allowing it to assume that `user` is always present. flag = observer_picker closes LS-3159 Test plan: - Enroll a user as a teacher in a classic course and an observer of a student enrolled in a k5 subject - Load the dashboard as that user - Expect the classic dashboard when the user is selected - Switch to the student - Expect the k5 dashboard to load - Switch back and expect the classic dashboard to again load - Expect to be able to switch between the k5 and classic dashboards when the observer is selected, but not if a student is selected - Regression test the dashboard as different users, including k5 and classic observers and non-observers Change-Id: I0de1daaa90b317231ee33960347d29494e79d7c9 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/291246 Reviewed-by: Ed Schiebel <eschiebel@instructure.com> QA-Review: Ed Schiebel <eschiebel@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: David Lyons <lyons@instructure.com>
2022-05-06 06:33:32 +08:00
get "show_k5_dashboard", controller: "users", action: "show_k5_dashboard"
post "users/:id/clear_cache", action: :clear_cache, as: "clear_cache"
scope(controller: :user_observees) do
get "users/:user_id/observers", action: :observers, as: "user_observers"
get "users/:user_id/observees", action: :index, as: "user_observees"
post "users/:user_id/observees", action: :create
get "users/:user_id/observees/:observee_id", action: :show, as: "user_observee"
get "users/:user_id/observers/:observer_id", action: :show_observer, as: "user_observer"
put "users/:user_id/observees/:observee_id", action: :update
delete "users/:user_id/observees/:observee_id", action: :destroy
end
scope(controller: :learning_object_dates) do
get "courses/:course_id/modules/:context_module_id/date_details", action: :show, as: "course_context_module_date_details"
get "courses/:course_id/assignments/:assignment_id/date_details", action: :show, as: "course_assignment_date_details"
get "courses/:course_id/quizzes/:quiz_id/date_details", action: :show, as: "course_quizzes_quiz_date_details"
get "courses/:course_id/discussion_topics/:discussion_topic_id/date_details", action: :show, as: "course_discussion_topic_date_details"
get "courses/:course_id/pages/:page_id/date_details", action: :show, as: "course_wiki_page_date_details"
get "courses/:course_id/files/:attachment_id/date_details", action: :show, as: "course_attachment_date_details"
Add date_details#update API A new endpoint for updating date-related information for any learning object (currently supports assignments and quizzes). There is already shared infrastructure for updating an assignment (in Api::V1::Assignment) which is utilized here for assignments. Quizzes do not have such shared infrastructure, but because classic quizzes are EOL, this commit does not attempt to improve that. Support for additional learning objects (files, pages, discussions) should be relatively straightforward to add since they do not have due dates. closes LF-993 flag = differentiated_modules Test plan: - PUT /api/v1/courses/:course_id/assignments/:id/date_details with any of the following parameters on an existing assignment: due_at, unlock_at, lock_at, only_visible_to_overrides, assignment_overrides - Expect the assignment to be updated appropriately (if overrides is provided, expect all of the assignment's overrides to be updated/ deleted/added to match the provided list) - Repeat for quizzes with PUT /api/v1/courses/:course_id/quizzes/:id/date_details (same parameters) - Expect the request to fail if the user is a student or if the differentiated_modules feature flag is disabled Change-Id: I120cc7fa9094f6d031f914cdc93069f88d7290f1 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/332829 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Sarah Gerard <sarah.gerard@instructure.com> QA-Review: Sarah Gerard <sarah.gerard@instructure.com> Product-Review: Jackson Howe <jackson.howe@instructure.com>
2023-11-15 03:23:15 +08:00
put "courses/:course_id/assignments/:assignment_id/date_details", action: :update
put "courses/:course_id/quizzes/:quiz_id/date_details", action: :update
put "courses/:course_id/discussion_topics/:discussion_topic_id/date_details", action: :update
put "courses/:course_id/pages/:page_id/date_details", action: :update
put "courses/:course_id/files/:attachment_id/date_details", action: :update
end
scope(controller: :login) do
Allow the user to import into a specific group in the UI closes OUT-4683 flag=improved_outcomes_management Test plan: - create or download fixture CSV files: - CSV file with NO parent_guid: vendor_guid,object_type,title new_outcome,outcome,New Outcome https://bit.ly/32pJ6VD - CSV file with parent_guid: vendor_guid,object_type,title,parent_guids new_group_from_csv,group,New Group from CSV, new_outcome,outcome,New Outcome from CSV,new_group_from_csv https://bit.ly/3oLLX2C - at the default account level: - navigate to `Outcomes` - create a child group with title 'Child Group' - select `Child Group` and click in the import button at the header - import `CSV file with NO parent_guid` - assert that, at the root group: - there's a new outcome titled `New Outcome` - select `Child Group` and click in the import button at the header - import `CSV file with parent_guid` - assert that, at the root group: - there's a new group titled `New Group from CSV`: - containing an outcome titled `New Outcome from CSV` - select `Child Group` and click in the import option from the kebab - import `CSV file with NO parent_guid` - assert that, at `Child Group`: - there's a new Outcome titled `New Outcome` - select `Child Group` and click in the import option from the kebab - import `CSV file with parent_guid` - refresh the page (TODO, OUT-4798) - assert that, at `Child Group`: - there's a new group titled `New Group from CSV`: - containing an outcome titled `New Outcome from CSV` - create a course: - repeat these steps at the course level Change-Id: I568e85a636d8b84d20f12640bad52e6b19023978 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/274711 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Kyle Rosenbaum <krosenbaum@instructure.com> QA-Review: Chrystal Langston <chrystal.langston@instructure.com> Product-Review: Ben Friedman <ben.friedman@instructure.com>
2021-11-01 05:10:09 +08:00
get "login/session_token", action: :session_token, as: :login_session_token
end
scope(controller: :observer_alerts_api) do
get "users/:user_id/observer_alerts/unread_count", action: :alerts_count
get "users/:user_id/observer_alerts/:student_id", action: :alerts_by_student, as: "observer_alerts_by_student"
put "users/:user_id/observer_alerts/:observer_alert_id/:workflow_state", action: :update
end
scope(controller: :observer_alert_thresholds_api) do
get "users/:user_id/observer_alert_thresholds", action: :index
post "users/:user_id/observer_alert_thresholds", action: :create
get "users/:user_id/observer_alert_thresholds/:observer_alert_threshold_id", action: :show
put "users/:user_id/observer_alert_thresholds/:observer_alert_threshold_id", action: :update
delete "users/:user_id/observer_alert_thresholds/:observer_alert_threshold_id", action: :destroy
end
scope(controller: :observer_pairing_codes_api) do
post "users/:user_id/observer_pairing_codes", action: :create
end
end
scope(controller: :custom_data) do
glob = "(/*scope)"
add serializable hash of CustomData for User models fixes CNVS-11424 test plan: - rake db:migrate - if you don't already have one, set yourself up with a developer token. (you can do so from <canvas>/developer_keys) - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"message":"no data for scope"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X PUT -F 'ns=test' \ -F 'data[apple]=so tasty' \ -F 'data[kiwi]=a bit sour' \ <canvas>/api/v1/users/self/custom_data/fruit #=> {"data":{"apple":"so tasty","kiwi":"a bit sour"}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty","kiwi":"a bit sour"}}} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X DELETE -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data/fruit/kiwi #=> {"data":"a bit sour"} - $ curl -H "Authorization: Bearer <ACCESS-TOKEN>" \ -X GET -F 'ns=test' \ <canvas>/api/v1/users/self/custom_data #=> {"data":{"fruit":{"apple":"so tasty"}}} - see new API doc for more info about how it should work, but basically, you should be able to GET, PUT, and DELETE at will for any given scope, and PUTting JSON hashes creates referenceable scopes. (e.g. the DELETE above has 'kiwi' in its scope) Change-Id: If027ae4aeec14edf44275ba0372a68aef7e5600e Reviewed-on: https://gerrit.instructure.com/31173 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com> Product-Review: Jon Jensen <jon@instructure.com>
2014-03-04 03:55:14 +08:00
get "users/:user_id/custom_data#{glob}", action: "get_data"
put "users/:user_id/custom_data#{glob}", action: "set_data"
delete "users/:user_id/custom_data#{glob}", action: "delete_data"
end
scope(controller: :pseudonyms) do
get "accounts/:account_id/logins", action: :index, as: "account_pseudonyms"
get "users/:user_id/logins", action: :index, as: "user_pseudonyms"
post "accounts/:account_id/logins", action: :create
put "accounts/:account_id/logins/:id", action: :update
delete "users/:user_id/logins/:id", action: :destroy
post "users/reset_password", action: :forgot_password
post "users/:user_id/logins/:id/migrate_login_attribute", action: :migrate_login_attribute
end
scope(controller: :accounts) do
get "accounts", action: :index, as: :accounts
get "course_accounts", action: :course_accounts, as: :course_accounts
Add ability to create course from k5 dashboard Puts a button on the k5 dashboard that opens a modal to create a new course, like on the classic dashboard. The button is visible to any user with admin role. The modal queries a new endpoint (on open) which returns all accounts in which the user can create courses. The user then picks the account inside which the course is created. We also enroll the user as a teacher in the new course to mirror what is done in classic canvas. This change also adds an empty state to the k5 dashboard if the user has no enrollments - that way we can still show the 'add course' button to admins. closes LS-2123 flag=canvas_for_elementary Test plan: - As an admin of a k5 subacount with no enrollments, visit the dashboard - Expect to see the panda - Click the Add Course button, expect modal to appear - Fill out fields and click create, expect to be redirected to the new course's settings page - Also expect to have a teacher enrollment in this new course - As an admin over an account with several subaccounts, visit the k5 dashboard and open the create course modal - Expect to see all the possible accounts listed in the dropdown - Create an admin with full access to one account but remove the manage_courses permission on another account - As this admin, visit k5 dashboard and open the modal, expect to see the one account listed in the dropdown, but not the other Change-Id: Idcbd997ff314a9f035862d35166505f47be9e7cd Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/263246 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jeff Largent <jeff.largent@instructure.com> QA-Review: Jeff Largent <jeff.largent@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com>
2021-04-21 00:18:23 +08:00
get "manageable_accounts", action: :manageable_accounts, as: :manageable_accounts
get "course_creation_accounts", action: :course_creation_accounts, as: :course_creation_accounts
get "accounts/:id", action: :show, as: :account
put "accounts/:id", action: :update
get "accounts/:account_id/terms_of_service", action: :terms_of_service
get "accounts/:account_id/help_links", action: :help_links
get "accounts/:account_id/courses", action: :courses_api, as: "account_courses"
get "accounts/:account_id/sub_accounts", action: :sub_accounts, as: "sub_accounts"
get "accounts/:account_id/courses/:id", controller: :courses, action: :show, as: "account_course_show"
get "accounts/:account_id/permissions", action: :permissions
Show Account settings and edit MSFT Sync settings Added an endpoint that allows you to view the specified accounts settings, as long as you're authorized. In addition, update the update_api action to allow updating Microsoft Teams Sync settings, namely :microsoft_sync_enabled, :microsoft_sync_tenant, and :microsoft_sync_login_attribute. closes INTEROP-6631, INTEROP-6630 test-plan: - Ensure you have an authorization token with AccountAdmin privileges or higher. - Using curl/Postman/Insomnia, try to enable Microsoft Sync with the feature flag disabled. Ensure a 400 is returned. - Enable the :microsoft_group_enrollments_syncing feature flag - Try to enable Microsoft Sync without a tenant or login_attribute and ensure a 400 is returned. Gotta have that info - Try to enable Microsoft Sync with an invalid login_attribute. Choose any random string at all. Ensure you get a 400. - try to enable Microsoft Sync without a valid tenant/domain name, such as "://$$$$$", or "invalidtenant-". Ensure a 400 is returned. - Enable Microsoft Sync with a valid tenant and login_attribute. Ensure a 200 is returned. - Try and modify settings as an unauthenticated user. You should get back a 401. - To test the show settings endpoint, make sure you have some account settings set. - Try to access the account settings as an unauthenticated user. Make sure you get a 401. - Access the account settings as an authorized user (Account Admin). Ensure that you get back a JSON object that represents all of your current account settings. flag = microsoft_group_enrollments_syncing Change-Id: Ib785987621e090a80ffa63fb48be3ed63243fe56 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/261189 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Mysti Lilla <mysti@instructure.com> Product-Review: Ryan Hawkins <ryan.hawkins@instructure.com> Reviewed-by: Evan Battaglia <ebattaglia@instructure.com>
2021-03-20 06:45:15 +08:00
get "accounts/:account_id/settings", action: :show_settings
Support students in CreateCourseModal Since this modal will be used everywhere in Canvas, support students and users with no enrollments creating courses (when enabled at the root account). Students will see all accounts where they have enrollments; users with no enrollments will only see the manually- created courses subaccount. Don't show homeroom sync options to students/users with no enrollments. Expose the manually-created courses subaccount ID/basic info through a new API. flag = create_course_subaccount_picker closes LS-2678 Test plan: - Enable root account FF: create_course_subaccount_picker - In root account settings, allow techers, students, and users with no enrollments to create courses - Login to k5 dashboard as an admin and click the + (New Subject) button - Expect to see a manageable_courses network request and a dropdown to select an account (along with the checkbox to sync homerooms) - Login and open the modal as a teacher - Expect to see an enrollments network request and a dropdown with all the accounts where the user has a teacher enrollment (and the homeroom sync checkbox) - Login and open the modal as a student - Expect another enrollments network request and a dropdown with all their accounts (if there's more than one) - Expect to not see the sync options - Login as a user with no enrollments - Expect a network request to the manually_created_courses_account api - Expect to not see a dropdown with accounts or the sync options - Disable 'X can create courses' at the root account and expect the associated users to no longer see the create course modal at all - With FF disabled, expect course creation to work as before Change-Id: I0e7d49628ce6395fd366037a3134133084fe6275 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/274986 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Peyton Craighill <pcraighill@instructure.com> Reviewed-by: Robin Kuss <rkuss@instructure.com> QA-Review: Robin Kuss <rkuss@instructure.com>
2021-10-02 00:56:26 +08:00
get "manually_created_courses_account", action: :manually_created_courses_account
clean up user "deletion" fixes CNVS-1552 any time the UI/API tries to "delete" a user, it should only be trying to remove it from some root account (the @domain_root_account if not otherwise specified). if that root account was the last root account the user was associated with, then the remnants of the user are fully deleted, but only then. leave User#destroy as a short-cut to delete the user from all their accounts at once, but should not be invoked directly from any UI/API actions. test-plan: PERMISSIONS being able to remove a user from an account entails being able to: - DELETE http://accounts-domain/users/:user - DELETE /accounts/:account/users/:user both should fail or succeed together * given - Sally who's an admin with the :manage_user_logins permission on one account (Account1) and a student on another account (Account2) - Bob who's a student on both accounts - Alice who's an admin on Account1 with greater permissions than Sally * Sally should: - see "Delete My Account" on her Account1 profile - not see "Delete My Account" on her Account2 profile - not see "Delete My Account" on Bob's Account1 profile - not see "Delete My Account" on Alice's Account1 profile - see "Delete from Account1" at /users/:sally - see "Delete from Account1" at /users/:bob - not see "Delete from Account2" at /users/:sally - not see "Delete from Account2" at /users/:bob - not see "Delete from Account1" at /users/:alice - be able to remove herself from Account1 - be able to remove Bob from Account1 - not be able to remove herself from Account2 - not be able to remove Bob from Account2 - not be able to remove Alice from Account1 * given Sally's Account1 pseudonym has a SIS ID but her Account2 pseudonym doesn't, Sally should: - no longer see "Delete My Account" on her Account1 profile - no longer see "Delete from Account1" at /users/:sally - still see "Delete from Account1" at /users/:bob - no longer be able to remove herself from Account1 - still be able to remove Bob from Account1 EFFECTS * as Sally, remove Bob from Account1 via DELETE http://account1-domain/users/:bob - Bob's pseudonyms, enrollments, etc. in Account1 should be removed - Bob's pseudonyms, enrollments, etc. in Account2 should be untouched * repeat using DELETE /accounts/:account1/users/:bob, with the same expectations Change-Id: Ib7612f95d1c7e4cca36d8486950565ec096b4ab1 Reviewed-on: https://gerrit.instructure.com/41591 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: August Thornton <august@instructure.com> Reviewed-by: Cody Cutrer <cody@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2014-09-23 07:04:03 +08:00
delete "accounts/:account_id/users/:user_id", action: :remove_user
put "accounts/:account_id/users/:user_id/restore", action: :restore_user
end
scope(controller: :sub_accounts) do
post "accounts/:account_id/sub_accounts", action: :create
delete "accounts/:account_id/sub_accounts/:id", action: :destroy
end
scope(controller: :role_overrides) do
get "accounts/:account_id/roles", action: :api_index, as: "account_roles"
get "accounts/:account_id/roles/:id", action: :show
post "accounts/:account_id/roles", action: :add_role
post "accounts/:account_id/roles/:id/activate", action: :activate_role
put "accounts/:account_id/roles/:id", action: :update
delete "accounts/:account_id/roles/:id", action: :remove_role
add new permission and API endpoint for manage_catalog refs CAT-819, CAT-822 Test plan: 1. rake db:migrate and sign into Canvas as an admin 2. Visit the permissions page for your account hooked up to Catalog and switch to the Account Roles tab. 3. Note the "Manage catalog" permission does not show up. 4. Now, console in and update that account to have a setting of :catalog_enabled => true, e.g. a = Account.find(1) a.settings[:catalog_enabled] = true a.save! 5. Reload Canvas and note that "Manage catalog" now displays in the Account Roles tab. refs CAT-823 Test plan: 1. As a few different user types, make API requests to /api/v1/accounts/:id/permissions/manage_catalog For instance: curl 'http://canvas.dev:3000/api/v1/accounts/1/permissions/manage_catalog' -H 'Authorization: Bearer your-token' * Account admins should receive {granted: true} * Non-admin users should receive {granted: false} * Users with custom roles that have the Manage Catalog permission should receive {granted: true} * If :catalog_enabled is not set on the account in question, it should never return {granted: true} * Try changing up the permission name in the URL (to something other than manage_catalog). The response should be an error (status code: 400), since we only support checking manage_catalog for now. Change-Id: I4fa53665ff866f5c016f32ce72036e8b5a75bda5 Reviewed-on: https://gerrit.instructure.com/48119 Tested-by: Jenkins Reviewed-by: Ethan Gunderson <egunderson@instructure.com> Product-Review: Ethan Gunderson <egunderson@instructure.com> QA-Review: Ethan Gunderson <egunderson@instructure.com>
2015-02-03 13:43:14 +08:00
get "accounts/:account_id/permissions/:permission", action: :check_account_permission
end
scope(controller: :account_reports) do
get "accounts/:account_id/reports/:report", action: :index
get "accounts/:account_id/reports", action: :available_reports
get "accounts/:account_id/reports/:report/:id", action: :show
post "accounts/:account_id/reports/:report", action: :create, as: "account_create_report"
delete "accounts/:account_id/reports/:report/:id", action: :destroy
end
scope(controller: :admins) do
post "accounts/:account_id/admins", action: :create
delete "accounts/:account_id/admins/:user_id", action: :destroy
get "accounts/:account_id/admins", action: :index, as: "account_admins"
get "accounts/:account_id/admins/self", action: :self_roles, as: "account_self_roles"
end
scope(controller: :authentication_providers) do
get "accounts/:account_id/sso_settings", action: :show_sso_settings, as: "account_show_sso_settings_url"
put "accounts/:account_id/sso_settings", action: :update_sso_settings, as: "account_update_sso_settings_url"
get "accounts/:account_id/authentication_providers", action: :index
get "accounts/:account_id/authentication_providers/:id", action: :show
post "accounts/:account_id/authentication_providers", action: :create, as: "account_create_ap"
put "accounts/:account_id/authentication_providers/:id", action: :update, as: "account_update_ap"
delete "accounts/:account_id/authentication_providers/:id", action: :destroy, as: "account_delete_ap"
end
get "users/:user_id/page_views", controller: :page_views, action: :index, as: "user_page_views"
get "users/:user_id/profile", controller: :profile, action: :settings
get "users/:user_id/avatars", controller: :profile, action: :profile_pics
# deprecated routes, second one is solely for YARD. preferred API is api/v1/search/recipients
get "conversations/find_recipients", controller: :search, action: :recipients
get "conversations/find_recipients", controller: :conversations, action: :find_recipients
scope(controller: :conversations) do
get "conversations", action: :index, as: "conversations"
post "conversations", action: :create
get "conversations/deleted", action: :deleted_index, as: "deleted_conversations"
put "conversations/restore", action: :restore_message
post "conversations/mark_all_as_read", action: :mark_all_as_read
get "conversations/batches", action: :batches, as: "conversations_batches"
get "conversations/unread_count", action: :unread_count
get "conversations/:id", action: :show
put "conversations/:id", action: :update # stars, subscribed-ness, workflow_state
delete "conversations/:id", action: :destroy
post "conversations/:id/add_message", action: :add_message
post "conversations/:id/add_recipients", action: :add_recipients
post "conversations/:id/remove_messages", action: :remove_messages
put "conversations", action: :batch_update
delete "conversations/:id/delete_for_all", action: :delete_for_all
end
scope(controller: :communication_channels) do
get "users/:user_id/communication_channels", action: :index, as: "communication_channels"
post "users/:user_id/communication_channels", action: :create
Link to reset bounce counts for communication channels Fixes CNVS-20747 Test plan: - Create a user - Add an email address to the user - The address doesn't need to be able to actually receive messages, so put anything you want in here - Make note of the user's id - Assuming the user's id is 42, open a rails console and type: c = User.find(42).email_channel c.bounce_count = 3 c.save! - Log in as the user (actually log in, don't just masquerade) - Visit the user's settings page - Verify you see the usual warning triangle next to the user's email address - Verify you don't see the reset icon (just a refresh-like icon, two arrows pointing in a circle) - Log in as a siteadmin - Masquerade as the user - Visit the user's settings page - Verify you see both the warning triangle and the reset icon - Click the reset icon - Verify that the reset icon and the warning triangle go away - Refresh the page and verify that they're still gone - Assuming the user's id is 42, open a rails console and type: c = User.find(42).email_channel c.bounce_count = 1 c.save! - Log in as a siteadmin - Masquerade as the user - Visit the user's settings page - Verify you see only the reset icon and not the warning triangle - Click the reset icon - Verify that it goes away - Refresh the page and verify that it's still gone Change-Id: Ibd9d2e04555be2ec3eae811fd93f2cba0645d870 Reviewed-on: https://gerrit.instructure.com/55139 Reviewed-by: Joel Hough <joel@instructure.com> Tested-by: Jenkins QA-Review: Adrian Russell <arussell@instructure.com> Product-Review: Allison Weiss <allison@instructure.com>
2015-10-07 12:27:50 +08:00
post "users/:user_id/communication_channels/:id", action: :reset_bounce_count, as: "reset_bounce_count"
get "accounts/:account_id/bounced_communication_channels.csv", action: :bouncing_channel_report, defaults: { format: :csv }
get "accounts/:account_id/bounced_communication_channels", action: :bouncing_channel_report
post "accounts/:account_id/bounced_communication_channels/reset", action: :bulk_reset_bounce_counts
get "accounts/:account_id/unconfirmed_communication_channels.csv", action: :unconfirmed_channel_report, defaults: { format: :csv }
get "accounts/:account_id/unconfirmed_communication_channels", action: :unconfirmed_channel_report
post "accounts/:account_id/unconfirmed_communication_channels/confirm", action: :bulk_confirm
delete "users/self/communication_channels/push", action: :delete_push_token
delete "users/:user_id/communication_channels/:id", action: :destroy
delete "users/:user_id/communication_channels/:type/:address", action: :destroy, constraints: { address: %r{[^/?]+} }
end
scope(controller: :notification_preferences) do
get "users/:user_id/communication_channels/:communication_channel_id/notification_preferences", action: :index
get "users/:user_id/communication_channels/:communication_channel_id/notification_preference_categories", action: :category_index
get "users/:user_id/communication_channels/:type/:address/notification_preferences", action: :index, constraints: { address: %r{[^/?]+} }
get "users/:user_id/communication_channels/:communication_channel_id/notification_preferences/:notification", action: :show
get "users/:user_id/communication_channels/:type/:address/notification_preferences/:notification", action: :show, constraints: { address: %r{[^/?]+} }
put "users/self/communication_channels/:communication_channel_id/notification_preferences/:notification", action: :update
put "users/self/communication_channels/:type/:address/notification_preferences/:notification", action: :update, constraints: { address: %r{[^/?]+} }
put "users/self/communication_channels/:communication_channel_id/notification_preferences", action: :update_all
put "users/self/communication_channels/:type/:address/notification_preferences", action: :update_all, constraints: { address: %r{[^/?]+} }
put "users/self/communication_channels/:communication_channel_id/notification_preference_categories/:category", action: :update_preferences_by_category
end
scope(controller: :comm_messages_api) do
get "comm_messages", action: :index, as: "comm_messages"
end
scope(controller: :services_api) do
get "services/kaltura", action: :show_kaltura_config
post "services/kaltura_session", action: :start_kaltura_session
get "services/rce_config", action: :rce_config
end
scope(controller: :calendar_events_api) do
get "calendar_events", action: :index, as: "calendar_events"
get "users/:user_id/calendar_events", action: :user_index, as: "user_calendar_events"
post "calendar_events", action: :create
get "calendar_events/visible_contexts", action: :visible_contexts
get "calendar_events/:id", action: :show, as: "calendar_event"
put "calendar_events/:id", action: :update
delete "calendar_events/:id", action: :destroy
post "calendar_events/:id/reservations", action: :reserve
post "calendar_events/:id/reservations/:participant_id", action: :reserve, as: "calendar_event_reserve"
get "calendar_events/:id/participants", action: :participants, as: "calendar_event_participants"
post "calendar_events/save_selected_contexts", action: :save_selected_contexts
Add “Other calendars” section to the calendar Sidebar This PS adds the new "other calendars" section to the calendar sidebar, this section should behave as the current calendar section, a new API is also added to manage the accounts the user wants to keep in the calendar, and a flag to mark the feature as seen fixes LS-3250, LS-3251 flag= account_calendar_events Test plan: - Enable the “Account-level calendars” flag in the site admin account - Go to the calendar and expect to see the new “Other Calendars” section with the empty state “Click the "+" icon to add a calendar” - Expect to see the “NEW” pill. - Click on the plus button and refresh the page. - Expect not to see the “NEW” pill again. - Add some account ids to your user preferences, e.g. setting a breakpoint and run @current_user.set_preference(:enabled_account_calendars ,<account_ids>) - Go to the calendar and expect to see the accounts you set in the “other calendars” section. - Expect to be able to set custom colors to the accounts and save them as selected_contexts - Click the X next to the account and expect the account to be removed - Refresh the page and expect the account not to appear again. Change-Id: Icd3f44995cd693b2594c6d88972cb1bc54dcd935 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/296594 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jackson Howe <jackson.howe@instructure.com> QA-Review: Jackson Howe <jackson.howe@instructure.com> Product-Review: Allison Howell <allison.howell@instructure.com>
2022-07-20 09:30:47 +08:00
post "calendar_events/save_enabled_account_calendars", action: :save_enabled_account_calendars
get "courses/:course_id/calendar_events/timetable", action: :get_course_timetable
post "courses/:course_id/calendar_events/timetable", action: :set_course_timetable
post "courses/:course_id/calendar_events/timetable_events", action: :set_course_timetable_events
end
scope(controller: :appointment_groups) do
get "appointment_groups", action: :index, as: "appointment_groups"
post "appointment_groups", action: :create
get "appointment_groups/next_appointment", action: :next_appointment
get "appointment_groups/:id", action: :show, as: "appointment_group"
put "appointment_groups/:id", action: :update
delete "appointment_groups/:id", action: :destroy
get "appointment_groups/:id/users", action: :users, as: "appointment_group_users"
get "appointment_groups/:id/groups", action: :groups, as: "appointment_group_groups"
end
scope(controller: :groups) do
resources :groups, except: :index
get "users/self/groups", action: :index, as: "current_user_groups"
get "accounts/:account_id/groups", action: :context_index, as: "account_user_groups"
get "courses/:course_id/groups", action: :context_index, as: "course_user_groups"
get "groups/:group_id/users", action: :users, as: "group_users"
get "groups/:group_id/permissions", action: :permissions
post "groups/:group_id/invite", action: :invite
post "groups/:group_id/files", action: :create_file
post "groups/:group_id/preview_html", action: :preview_html
post "group_categories/:group_category_id/groups", action: :create
get "groups/:group_id/activity_stream", action: :activity_stream, as: "group_activity_stream"
get "groups/:group_id/activity_stream/summary", action: :activity_stream_summary, as: "group_activity_stream_summary"
put "groups/:group_id/followers/self", action: :follow
delete "groups/:group_id/followers/self", action: :unfollow
get "groups/:group_id/collaborations", controller: :collaborations, action: :api_index, as: "group_collaborations_index"
delete "groups/:group_id/collaborations/:id", controller: :collaborations, action: :destroy
scope(controller: :group_memberships) do
resources :memberships, path: "groups/:group_id/memberships", name_prefix: "group_", controller: :group_memberships
resources :users, path: "groups/:group_id/users", name_prefix: "group_", controller: :group_memberships, except: [:index, :create]
end
get "groups/:group_id/files", controller: :files, action: :api_index, as: "group_files"
get "groups/:group_id/folders", controller: :folders, action: :list_all_folders, as: "group_folders"
post "groups/:group_id/folders", controller: :folders, action: :create
get "groups/:group_id/folders/by_path/*full_path", controller: :folders, action: :resolve_path
get "groups/:group_id/folders/by_path", controller: :folders, action: :resolve_path
get "groups/:group_id/folders/media", controller: :folders, action: :media_folder
get "groups/:group_id/folders/:id", controller: :folders, action: :show, as: "group_folder"
end
Create DeveloperKeyAccountBinding API Closes PLAT-3208 Test Plan: - For all new endpoints verify the the user must have the manage developer key permission for the requestd account. CREATE - In a root account create a developer key. - Using the new binding create endpoint create a developer key account binding: POST { "developer_key_account_binding": { "workflow_state": "on" } } - Verify a DeveloperKeyAccountBinding was created with a workflow state of 'on', an account id pointing to the root account, and a develoepr key pointing to the root account developer key. - Create a developer key in a sub account. - Repeate the above process but create a binding for the sub account and sub account developer key. - Verify you cannont create a binding using the root account id and the sub account develope key id. UPDATE PUT { "developer_key_account_binding": { "workflow_state": "off" } } - Verify you can use the update endpoint to modify the workflow_state of the DeveloperKeyAccountBinding create previously in the root account. - Do the same for sub accounts. INDEX - Verify the endpoint lists all DeveloperKeyAccountBindings from the account specified by the account_id param. - Verify the endpoint lists all DeveloperKeyAccountBindings from any parent accounts. - Verify the endpoint lists all DeveloperKeyAccountBindings from the site admin account. Change-Id: Id81b1d5ef0eb1d6a62ca180b66be6f92a285c3de Reviewed-on: https://gerrit.instructure.com/143908 Tested-by: Jenkins Reviewed-by: Stewie aka Nicholas Stewart <nstewart@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2018-03-17 04:59:43 +08:00
scope(controller: :developer_key_account_bindings) do
2018-03-20 01:09:59 +08:00
post "accounts/:account_id/developer_keys/:developer_key_id/developer_key_account_bindings", action: :create_or_update
Create DeveloperKeyAccountBinding API Closes PLAT-3208 Test Plan: - For all new endpoints verify the the user must have the manage developer key permission for the requestd account. CREATE - In a root account create a developer key. - Using the new binding create endpoint create a developer key account binding: POST { "developer_key_account_binding": { "workflow_state": "on" } } - Verify a DeveloperKeyAccountBinding was created with a workflow state of 'on', an account id pointing to the root account, and a develoepr key pointing to the root account developer key. - Create a developer key in a sub account. - Repeate the above process but create a binding for the sub account and sub account developer key. - Verify you cannont create a binding using the root account id and the sub account develope key id. UPDATE PUT { "developer_key_account_binding": { "workflow_state": "off" } } - Verify you can use the update endpoint to modify the workflow_state of the DeveloperKeyAccountBinding create previously in the root account. - Do the same for sub accounts. INDEX - Verify the endpoint lists all DeveloperKeyAccountBindings from the account specified by the account_id param. - Verify the endpoint lists all DeveloperKeyAccountBindings from any parent accounts. - Verify the endpoint lists all DeveloperKeyAccountBindings from the site admin account. Change-Id: Id81b1d5ef0eb1d6a62ca180b66be6f92a285c3de Reviewed-on: https://gerrit.instructure.com/143908 Tested-by: Jenkins Reviewed-by: Stewie aka Nicholas Stewart <nstewart@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2018-03-17 04:59:43 +08:00
end
scope(controller: :developer_keys) do
delete "developer_keys/:id", action: :destroy
put "developer_keys/:id", action: :update
get "accounts/:account_id/developer_keys", action: :index, as: "account_developer_keys"
post "accounts/:account_id/developer_keys", action: :create
end
scope(controller: "lti/registrations") do
delete "accounts/:account_id/lti_registrations/:id", action: :destroy
get "accounts/:account_id/lti_registrations/:id", action: :show
LIME: Add Registration update endpoint why: - To allow admin's to update the nickname for a registration - To scaffold out updating for later stages closes INTEROP-8506 flag=lti_registrations_page test-plan: - Enable the lti_registrations_page flag - Go through the dynamic registration workflow on the dev keys page to create an LTI Registration. Take note of it's id, most easily by doing: `Lti::Registration.last.id` - Ensure you have an access token that has admin rights - Send a curl request like the following: ``` curl -X PUT 'https://<canvas>/api/v1/accounts/<account_id>/registrations/<registration_id>' \ -H "Authorization: Bearer <token>" \ -d 'registration[admin_nickname]=A New Nickname' ``` - You should get back JSON representing the registration. - The registration should show that it was updated_by the user associated with your access token. - Try to update the created_by user by modifying the curl request to include it. You should only be able to change the admin_nickname. - Try sending the request without an access token. You should get back a 401. - Create an Lti::Registration manually in the Rails console. ``` Lti::Registration.create!(name: "A Great Name", account: Account.default, created_by: User.first, updated_by: User.first, admin_nickname: "nickname") ``` - Take note of it's ID and try to update it through the API. It should fail, as only registrations associated with a dynamic registration can be updated (for now) - For bonus points you could also try using an access token associated with a user that doesn't have admin permissions. Change-Id: I7d7c5a42f2f2fac201fb0b3ed464a1c45dbde1d4 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/349212 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Xander Moffatt <xmoffatt@instructure.com> Reviewed-by: Tucker Mcknight <tmcknight@instructure.com> QA-Review: Tucker Mcknight <tmcknight@instructure.com> Product-Review: Alexis Nast <alexis.nast@instructure.com>
2024-06-05 04:30:52 +08:00
put "accounts/:account_id/lti_registrations/:id", action: :update
end
scope(controller: :immersive_reader) do
get "immersive_reader/authenticate", action: :authenticate
end
scope(controller: :search) do
get "search/rubrics", action: "rubrics", as: "search_rubrics"
get "search/recipients", action: "recipients", as: "search_recipients"
get "search/all_courses", action: "all_courses", as: "search_all_courses"
end
post "files/:id/create_success", controller: :files, action: :api_create_success, as: "files_create_success"
get "files/:id/create_success", controller: :files, action: :api_create_success
scope(controller: :files) do
post "files/:id/create_success", action: :api_create_success
get "files/:id/create_success", action: :api_create_success
match "/api/v1/files/:id/create_success", via: [:options], action: :api_create_success_cors
inst-fs upload preflight (and capture fixes) fixes CNVS-38591 when the inst-fs service is enabled, generate a preflight response tailored for inst-fs instead of for S3. the service will then receive the POSTed file data, generate it, and ping Canvas at the embedded capture URL. compatible with existing Canvas UI. along the way, some cleanup refactoring in api_attachment_preflight: * instead of taking submission_context and inferring a folder from that, have the submission API be responsible for determining the folder and then just specify it. note that the folder inference was the only use of submission_context, the submission API was the only caller of api_preflight_json to specify submission_context, and the folder option we took over was previously both broken and unused. * simplify the remaining folder inference code. if a folder is specified by the code (vs. the user in params), assume they have necessary access (the :manage_contents permission would fail for a student making a submission) * correctly abort if params[:on_duplicate] is invalid. before, if the UI provided an explicit but invalid value, it would cause a double render error. * inline process_attachment_params for update, and skip it on preflight. the UI never provides any of the possible params but display_name for preflight, which is then ignored from the process_attachment_params result because it's treated separately TODO: tests * InstFS.upload_preflight_json * api_attachment_preflight: - uploading a file to a submission (submissions_api#create_file) when the submissions_folder feature is enabled stores the file in the user's submissions folder - student uploading a file to a submission is not blocked by permissions - user with :manage_contents permission on a folder is not blocked when uploading to that folder - user without :manage_contents permission on a folder is blocked when attempting to upload to that folder - no double render error on on_duplicate=invalid - updates to lock_at, etc., on a file (via files#api_update) stick * files#api_capture: - reject if over quota and not flagged quota_exempt - attachment.locked based on usage rights settings - attachment.handle_duplicates - content migration success callback triggered * InstFS.authenticated_url: - includes iat claim - expiration is a timestamp test-plan: inst-fs upload happy path: - have inst-fs service running, have canvas configured to be able to find and share a secret with it, and enable the inst-fs plugin setting - go to the files area, or a discussion, or a conversation, etc., and upload a file. - the file should be successfully uploaded - NOTE: known issue, there seems to be a race condition in the service responding 201 Created with a Location before Canvas is ready to respond to that Location. This will make the upload appear to fail. But if you refresh the page, the file should be present. This race condition will be fixed in a later commit; it has already been filed as a separate bug. - attempt to download/preview the file - download/preview should work, and should be served from inst-fs quota enforcement: - configure a course to have a quota - select a file that should exceed that quota when uploaded - bypassing the canvas UI, access the preflight endpoint directly while providing the true size; preflight should fail - access the preflight endpoint directly while providing a false size that would fit inside the quota; preflight should succeed - attempt to POST the file to the returned upload_url with the returned upload_params; the upload should fail locking pending usage rights: - configure the account to lock files without usage rights - upload a file - the newly created file should be locked - assign usage rights to the new file - it should unlock path collisions: - upload a file to a folder - upload a distinct file but with the same filename to the same folder - should be prompted to rename or overwrite - select rename; the newly uploaded file should have the filename modified to avoid the collision - repeat, but selecting overwrite; the filename should now refer to the new file, and the old file should not be accessible in the UI non-inst-fs unharmed: - disable the inst-fs plugin setting - do general regression tests on file uploads (whether S3 or local storage) Change-Id: I2bff1e3c31a3ed0955c29e677a422b7149253318 Reviewed-on: https://gerrit.instructure.com/124929 Tested-by: Jenkins Reviewed-by: Andrew Huff <ahuff@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2017-09-06 02:53:02 +08:00
post "files/capture", action: :api_capture, as: "files_capture"
modules api, closes #10404 also modifies the discussion topic and assignment API controllers to make sure "must_view" requirements are fulfilled test plan: * check the API documentation; ensure it looks okay * create a course with module items of each supported type * set completion criteria of each supported type * create another module, so you can set prerequisites * use the list modules API and verify its output matches the course and the documentation * as a teacher, "state" should be missing * as a student, "state" should be "locked", "unlocked", "started", or "completed" * use the show module API and verify the correct information is returned for a single module * use the list module items API and verify the output * as a teacher, the "completion_requirement" omits the "completed" flag * as a student, "completed" should be true or false, depending on whether the requirement was met * use the show module API and verify the correct information is returned for a single module item * last but not least, verify "must view" requirements can be fulfilled through the api_data_endpoints supplied for files, pages, discussions, and assignments * files are viewed when downloading their content * pages are viewed by the show action (where content is returned) * discussions are viewed when marked read via the mark_topic_read or mark_all_read actions * assignments are viewed by the show action (where description is returned). they are not viewed if the assignment is locked and the user does not have access to the content yet. Change-Id: I0cbbbc542f69215e7b396a501d4d86ff2f76c149 Reviewed-on: https://gerrit.instructure.com/13626 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com>
2012-09-12 01:16:48 +08:00
# 'attachment' (rather than 'file') is used below so modules API can use polymorphic_url to generate an item API link
get "files/:id", action: :api_show, as: "attachment"
get "files/:id/icon_metadata", action: :icon_metadata
delete "files/:id", action: :destroy
put "files/:id", action: :api_update
post "files/:id/reset_verifier", action: :reset_verifier
# exists as an alias of GET for backwards compatibility
#
# older API clients were told to POST to the value of the Location header
# returned after upload to S3, when that was the create_success URL.
# that's no longer necessary, but they are still given a Location header
# pointed at this endpoint which they can GET for the file details (which
# create_success would have provided).
#
# such behavior is now undocumented, and subject to removal once open
# sourcing of inst-fs is complete.
#
# to actually change the file metadata (e.g. rename), the PUT route above
# must be used.
post "files/:id", action: :api_show
get "files/:id/:uuid/status", action: :api_file_status, as: "file_status"
get "files/:id/public_url", action: :public_url
get "courses/:course_id/files/file_ref/:migration_id", action: :file_ref
%w[course group user].each do |context|
get "#{context}s/:#{context}_id/files/quota", action: :api_quota
get "#{context}s/:#{context}_id/files/:id", action: :api_show, as: "#{context}_attachment"
end
end
scope(controller: :folders) do
get "folders/:id", action: :show
get "folders/:id/folders", action: :api_index, as: "list_folders"
get "folders/:id/files", controller: :files, action: :api_index, as: "list_files"
delete "folders/:id", action: :api_destroy
put "folders/:id", action: :update
post "folders/:folder_id/folders", action: :create, as: "create_folder"
post "folders/:folder_id/files", action: :create_file
post "folders/:dest_folder_id/copy_file", action: :copy_file
post "folders/:dest_folder_id/copy_folder", action: :copy_folder
end
scope(controller: :favorites) do
get "users/self/favorites/courses", action: :list_favorite_courses, as: :list_favorite_courses
post "users/self/favorites/courses/:id", action: :add_favorite_course, as: :add_favorite_course
delete "users/self/favorites/courses/:id", action: :remove_favorite_course, as: :remove_favorite_course
delete "users/self/favorites/courses", action: :reset_course_favorites
get "users/self/favorites/groups", action: :list_favorite_groups, as: :list_favorite_groups
post "users/self/favorites/groups/:id", action: :add_favorite_groups, as: :add_favorite_groups
delete "users/self/favorites/groups/:id", action: :remove_favorite_groups, as: :remove_favorite_groups
delete "users/self/favorites/groups", action: :reset_groups_favorites
end
scope(controller: :wiki_pages_api) do
get "courses/:course_id/front_page", action: :show_front_page
get "groups/:group_id/front_page", action: :show_front_page
put "courses/:course_id/front_page", action: :update_front_page
put "groups/:group_id/front_page", action: :update_front_page
post "courses/:course_id/pages/:url_or_id/duplicate", action: :duplicate
allow PUT requests to create wiki pages implicitly testing note: this change affects all wiki page endpoints: api, draft state, and non-draft state. basic functionality for all of these pages should be verified, specifically when dealing with non-existent or deleted pages. test plan: * PUT to /api/v1/courses/:course_id/front_page - variations: * wiki_page[title] - provided/not provided * wiki_page[published] - true/false/not provided * wiki_page[hide_from_students] - true/false/not provided (hiding/unpublishing the front page is not allowed) * PUT to /api/v1/courses/:course_id/pages/non-existent-page - same variations as front_page (above) * navigating to a non-existent/deleted page (draft state/non-draft state) - should redirect teachers to the edit page - should redirect students to the index page (with an alert message indicating why) * navigating to the 'Pages' tab (non-draft state) - if the 'Front Page' exists - shows the page - if the 'Front Page' has been deleted (with draft state enabled) - shows the edit page - if the 'Front Page' has never existed - shows the edit page * all other pages functionality should remain unchanged - non-draft state UI - show page - edit page - draft state UI - index page - show page - edit page - api - .../pages - GET (index) - POST (create page) - .../front_page - GET (show front page) - PUT (create/update front page) - .../pages/page-url - GET (show page) - PUT (create/update page) - DELETE (destroy page) fixes CNVS-8488 Change-Id: I563e6944e1602e0b21ab69c6fe2dcd643c06611d Reviewed-on: https://gerrit.instructure.com/23590 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> Product-Review: Bracken Mosbacker <bracken@instructure.com>
2013-08-22 23:43:03 +08:00
get "courses/:course_id/pages", action: :index, as: "course_wiki_pages"
get "groups/:group_id/pages", action: :index, as: "group_wiki_pages"
get "courses/:course_id/pages/:url_or_id", action: :show, as: "course_wiki_page"
get "groups/:group_id/pages/:url_or_id", action: :show, as: "group_wiki_page"
get "courses/:course_id/pages/:url_or_id/revisions", action: :revisions, as: "course_wiki_page_revisions"
get "groups/:group_id/pages/:url_or_id/revisions", action: :revisions, as: "group_wiki_page_revisions"
get "courses/:course_id/pages/:url_or_id/revisions/latest", action: :show_revision
get "groups/:group_id/pages/:url_or_id/revisions/latest", action: :show_revision
get "courses/:course_id/pages/:url_or_id/revisions/:revision_id", action: :show_revision
get "groups/:group_id/pages/:url_or_id/revisions/:revision_id", action: :show_revision
post "courses/:course_id/pages/:url_or_id/revisions/:revision_id", action: :revert
post "groups/:group_id/pages/:url_or_id/revisions/:revision_id", action: :revert
post "courses/:course_id/pages", action: :create
post "groups/:group_id/pages", action: :create
put "courses/:course_id/pages/:url_or_id", action: :update
put "groups/:group_id/pages/:url_or_id", action: :update
delete "courses/:course_id/pages/:url_or_id", action: :destroy
delete "groups/:group_id/pages/:url_or_id", action: :destroy
get "courses/:course_id/page_title_availability", action: :check_title_availability, as: "course_page_title_availability"
get "groups/:group_id/page_title_availability", action: :check_title_availability, as: "group_page_title_availability"
end
scope(controller: :context_modules_api) do
get "courses/:course_id/modules", action: :index, as: "course_context_modules"
get "courses/:course_id/modules/:id", action: :show, as: "course_context_module"
put "courses/:course_id/modules", action: :batch_update
post "courses/:course_id/modules/:module_id/duplicate", action: :duplicate
post "courses/:course_id/modules", action: :create, as: "course_context_module_create"
put "courses/:course_id/modules/:id", action: :update, as: "course_context_module_update"
delete "courses/:course_id/modules/:id", action: :destroy
put "courses/:course_id/modules/:id/relock", action: :relock
end
scope(controller: :context_module_items_api) do
get "courses/:course_id/modules/:module_id/items", action: :index, as: "course_context_module_items"
get "courses/:course_id/modules/:module_id/items/:id", action: :show, as: "course_context_module_item"
put "courses/:course_id/modules/:module_id/items/:id/done", action: :mark_as_done, as: "course_context_module_item_done"
delete "courses/:course_id/modules/:module_id/items/:id/done", action: :mark_as_not_done, as: "course_context_module_item_not_done"
get "courses/:course_id/module_item_redirect/:id", action: :redirect, as: "course_context_module_item_redirect"
get "courses/:course_id/module_item_sequence", action: :item_sequence
post "courses/:course_id/modules/:module_id/items", action: :create, as: "course_context_module_items_create"
put "courses/:course_id/modules/:module_id/items/:id", action: :update, as: "course_context_module_item_update"
delete "courses/:course_id/modules/:module_id/items/:id", action: :destroy
post "courses/:course_id/modules/:module_id/items/:id/mark_read", action: :mark_item_read
post "courses/:course_id/modules/:module_id/items/:id/select_mastery_path", action: :select_mastery_path
post "courses/:course_id/modules/items/:id/duplicate", action: :duplicate, as: :course_context_module_item_duplicate
end
scope(controller: :module_assignment_overrides) do
get "courses/:course_id/modules/:context_module_id/assignment_overrides", action: :index, as: "module_assignment_overrides_index"
put "courses/:course_id/modules/:context_module_id/assignment_overrides", action: :bulk_update
end
scope(controller: "quizzes/quiz_assignment_overrides") do
get "courses/:course_id/quizzes/assignment_overrides", action: :index, as: "course_quiz_assignment_overrides"
get "courses/:course_id/new_quizzes/assignment_overrides", action: :new_quizzes, as: "course_new_quizzes_assignment_overrides"
quiz index optimizations Closes CNVS-15109, CNVS-15173 CHANGES ------- - "auto-grading" of due submissions that was previously done synchronously in the index action is now done in a DJ - when viewing the index page, you don't get to see due/available dates on load, instead the dates are fetched on the client-side and load progressively - new API endpoint for retrieving assignment overrides for a bunch of quizzes at [GET] /courses/:course_id/quizzes/assignment_overrides - we now cache the user's quiz permissions - Canvas AMS API serializer now accepts a new option, see docs - QuizSerializer behavior changed radically: - "takeable", "submitted_students", "unsubmitted_students" disabled - all associations disabled including the submission, assignment group, and any student participants - it can now utilize preloaded permissions Rationale behind disabling things in the serializer is that these were exclusive for the "show" action, so the next step forwards is to allow the serializer to recognize different "modes" for output (e.g, for index and one for show) and tailor the associations/fields accordingly. Using "#filter" right now isn't cutting it, because assocs get loaded anyway. REFACTORING ----------- - broke down index into three actions for visibility: 1. default, Draft-State version 2. legacy non-DS version that's not reachable in the UI, kept around until we upgrade the tests 3. ember version - legacy non-DS ERB code goes into its own file - moved code that used to grade due submissions inside index to SubmissionGrader in preparation to remove it from there entirely - cleaned up internal docs for the Canvas AMS api serializer TEST PLAN ---- ---- - create ~30 quizzes + make one of them have many questions + make a good number of submissions (i tested with 420 and 20 students) - create multiple sections + specify date overrides for certain sections, and have at least one student enrolled in that section - as a teacher and/or an observer, go to quizzes index + verify the page renders fine + verify that you see "loading indicators" in the due/available field which get replaced with actual dates when they're loaded + verify it's faster than the version in master (should be at least 60% faster) - as a student in the general section, go to quizzes index + verify the page renders + verify you see the same loading behavior for dates as in teacher view - as a student in one of the section with overrides, go to index: + verify you see the overridden date Change-Id: I741d89625da1b858148baa95e881fcc75c1802e5 Reviewed-on: https://gerrit.instructure.com/40350 Reviewed-by: Derek DeVries <ddevries@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Trevor deHaan <tdehaan@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com>
2014-08-31 15:20:52 +08:00
end
scope(controller: "quizzes/quizzes_api") do
get "courses/:course_id/quizzes", action: :index, as: "course_quizzes"
post "courses/:course_id/quizzes", action: :create, as: "course_quiz_create"
get "courses/:course_id/quizzes/:id", action: :show, as: "course_quiz"
put "courses/:course_id/quizzes/:id", action: :update, as: "course_quiz_update"
delete "courses/:course_id/quizzes/:id", action: :destroy, as: "course_quiz_destroy"
post "courses/:course_id/quizzes/:id/reorder", action: :reorder, as: "course_quiz_reorder"
post "courses/:course_id/quizzes/:id/validate_access_code", action: :validate_access_code, as: "course_quiz_validate_access_code"
end
scope(controller: "quizzes_next/quizzes_api") do
get "courses/:course_id/all_quizzes", action: :index, as: "course_all_quizzes"
end
scope(controller: "quizzes/quiz_submission_users") do
get "courses/:course_id/quizzes/:id/submission_users", action: :index, as: "course_quiz_submission_users"
post "courses/:course_id/quizzes/:id/submission_users/message", action: :message, as: "course_quiz_submission_users_message"
end
scope(controller: "quizzes/quiz_groups") do
get "courses/:course_id/quizzes/:quiz_id/groups/:id", action: :show, as: "course_quiz_group"
post "courses/:course_id/quizzes/:quiz_id/groups", action: :create, as: "course_quiz_group_create"
put "courses/:course_id/quizzes/:quiz_id/groups/:id", action: :update, as: "course_quiz_group_update"
delete "courses/:course_id/quizzes/:quiz_id/groups/:id", action: :destroy, as: "course_quiz_group_destroy"
post "courses/:course_id/quizzes/:quiz_id/groups/:id/reorder", action: :reorder, as: "course_quiz_group_reorder"
end
scope(controller: "quizzes/quiz_questions") do
get "courses/:course_id/quizzes/:quiz_id/questions", action: :index, as: "course_quiz_questions"
get "courses/:course_id/quizzes/:quiz_id/questions/:id", action: :show, as: "course_quiz_question"
post "courses/:course_id/quizzes/:quiz_id/questions", action: :create, as: "course_quiz_question_create"
put "courses/:course_id/quizzes/:quiz_id/questions/:id", action: :update, as: "course_quiz_question_update"
delete "courses/:course_id/quizzes/:quiz_id/questions/:id", action: :destroy, as: "course_quiz_question_destroy"
end
scope(controller: "quizzes/quiz_reports") do
post "courses/:course_id/quizzes/:quiz_id/reports", action: :create, as: "course_quiz_reports_create"
Quiz Reports API - force regeneration Extends the quiz reports API with the ability to re-trigger failed CSV generation jobs, and to abort them completely. The UI is extended to utilize those new APIs. Closes CNVS-16525 TEST PLAN ---- ---- - create a quiz with a file upload question - take the quiz by a student and upload a file, then submit - turn on new stats and go to new stats page - click the "Student Analysis" report generator button and verify that the CSV file is generated and you get prompted to save it Now... we break the student's submission by removing the attachment and then the student analysis will start failing to generate. Launch a rails console and perform the following command: [ 'Quizzes::QuizSubmission', 'Quizzes::QuizStatistics' ].each do |type| Attachment.where({ context_type: type }).last.destroy! end - reload the stats page + the "Student Analysis" button should now read that it had never been generated, that's right because we just removed the CSV file attachment using the console + try generating the report again - verify that it blows up + you should now see a notification as in the screencast - clicking the "retry" link should retry generating the report (which will fail again) - clicking the "cancel" link should remove the notification - clicking "Dismiss" should dismiss the notification, but if you reload the page, it's still there Change-Id: I467a9030c3ef94d685ec20b31dd533e530e24758 Reviewed-on: https://gerrit.instructure.com/43862 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Trevor deHaan <tdehaan@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> Product-Review: Derek DeVries <ddevries@instructure.com>
2014-10-29 00:11:34 +08:00
delete "courses/:course_id/quizzes/:quiz_id/reports/:id", action: :abort, as: "course_quiz_reports_abort"
get "courses/:course_id/quizzes/:quiz_id/reports", action: :index, as: "course_quiz_reports"
get "courses/:course_id/quizzes/:quiz_id/reports/:id", action: :show, as: "course_quiz_report"
end
scope(controller: "quizzes/quiz_submission_files") do
post "courses/:course_id/quizzes/:quiz_id/submissions/self/files", action: :create, as: "quiz_submission_files"
end
scope(controller: "quizzes/quiz_submissions_api") do
Deterministically get a submission for a user fixes CNVS-30098 The course/:course_id/quizzes/:quiz_id/submissions api returns different things in different cases and the mobile teams want a way to be able to easily get the submission for the current user so they don't have to do client-side filtering on all of the apps. Let's add that as course/:course_id/quizzes/:quiz_id/submission that'll only ever give any one submission for you. Also update the docs for the existing API so it is more clear what it does. test plan: - request the new API as a student without a quiz submission and verify you are returned an empty set of quiz submissions - request the new API as a student with a quiz submission that is not yet submitted and verify that you are returned a single quiz submission with workflow_state = untaken - reuqest the new API as a student with a quiz submission that is submitted and verify that you are returned a single quiz submission with workfow_state = complete - request the new API as a student with a quiz submission that has many submitted attempts and verify that you are returned a single quiz submission with workflow_state = complete and attempt number is the latest attempt - request the new API as a teacher or admin and verify that you are returned an empty set of quiz submissions - request the new API as a teacher or admin who is also a student with a quiz submission and verify that you are returned only your one quiz submission Change-Id: Ib364e9c4be0f196c10892dafe5bad75c86acbdbc Reviewed-on: https://gerrit.instructure.com/83846 Reviewed-by: Davis Lynn McClellan <dmcclellan@instructure.com> Tested-by: Jenkins QA-Review: Robin Kuss <rkuss@instructure.com> Product-Review: Brandon Pluim <bpluim@instructure.com>
2016-06-29 05:51:09 +08:00
get "courses/:course_id/quizzes/:quiz_id/submission", action: :submission, as: "course_quiz_user_submission"
get "courses/:course_id/quizzes/:quiz_id/submissions", action: :index, as: "course_quiz_submissions"
get "courses/:course_id/quizzes/:quiz_id/submissions/:id", action: :show, as: "course_quiz_submission"
get "courses/:course_id/quizzes/:quiz_id/submissions/:id/time", action: :time, as: "course_quiz_submission_time"
post "courses/:course_id/quizzes/:quiz_id/submissions", action: :create, as: "course_quiz_submission_create"
put "courses/:course_id/quizzes/:quiz_id/submissions/:id", action: :update, as: "course_quiz_submission_update"
post "courses/:course_id/quizzes/:quiz_id/submissions/:id/complete", action: :complete, as: "course_quiz_submission_complete"
end
scope(controller: "quizzes/outstanding_quiz_submissions") do
get "courses/:course_id/quizzes/:quiz_id/outstanding_quiz_submissions", action: :index, path_name: "outstanding_quiz_submission_index"
post "courses/:course_id/quizzes/:quiz_id/outstanding_quiz_submissions", action: :grade, path_name: "outstanding_quiz_submission_grade"
end
scope(controller: "quizzes/quiz_extensions") do
post "courses/:course_id/quizzes/:quiz_id/extensions", action: :create, as: "course_quiz_extensions_create"
add api for quiz submission extensions quiz submissions can have their time limit or number of attempts extended. we can extend both existing quiz submissions, and also those that don't exist yet. adding this functionality to the existing quiz submissions api would muddle up responsibilities. So instead we post all extensions to a the quiz extensions api which is specifically meant for adding extensions to a submission whether it has been started yet or not. Also add 'manually_unlocked' to the quiz submissions api. this field lets us know if a student can take a quiz after it has been locked for everyone else. fixes CNVS-13165 test plan - There is a new attribute added to quiz_submissions objects in the api called 'manually_unlocked'. This attribute will now show up when returning results back from - GET /api/v1/courses/:course_id/quizzes/:quiz_id/submissions (index) - GET /api/v1/courses/:course_id/quizzes/:quiz_id/submissions/:id (show) - There is a new endpoint to create quiz extensions. This should work to create quiz extensions for users that both have existing quiz submissions started, and users who have not yet started a quiz: - POST /api/v1/courses/:course_id/quizzes/:quiz_id/extensions (create) - Check Permissions on the new quiz extension endpoint. Only teachers should be able to extend the quizzes. - Check that all the documentation looks okay for quiz extensions. Change-Id: Ie23113c1f30e139a1e376475fb35a2cf3ce0212c Reviewed-on: https://gerrit.instructure.com/35111 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Ahmad Amireh <ahmad@instructure.com> QA-Review: Caleb Guanzon <cguanzon@instructure.com> Product-Review: Derek DeVries <ddevries@instructure.com>
2014-05-20 04:04:00 +08:00
end
scope(controller: "quizzes/course_quiz_extensions") do
post "courses/:course_id/quiz_extensions", action: :create
end
scope(controller: "quizzes/quiz_submission_events_api") do
get "courses/:course_id/quizzes/:quiz_id/submissions/:id/events", action: :index, as: "course_quiz_submission_events"
post "courses/:course_id/quizzes/:quiz_id/submissions/:id/events", action: :create, as: "create_quiz_submission_events"
end
scope(controller: "quizzes/quiz_submission_questions") do
get "/quiz_submissions/:quiz_submission_id/questions", action: :index, as: "quiz_submission_questions"
post "/quiz_submissions/:quiz_submission_id/questions", action: :answer, as: "quiz_submission_question_answer"
get "/quiz_submissions/:quiz_submission_id/questions/:id/formatted_answer", action: :formatted_answer, as: "quiz_submission_question_formatted_answer"
get "/quiz_submissions/:quiz_submission_id/questions/:id", action: :show, as: "quiz_submission_question"
put "/quiz_submissions/:quiz_submission_id/questions/:id/flag", action: :flag, as: "quiz_submission_question_flag"
put "/quiz_submissions/:quiz_submission_id/questions/:id/unflag", action: :unflag, as: "quiz_submission_question_unflag"
Quiz Submission Questions API - Update This patch provides support for answering Quiz Questions via the API. closes CNVS-9844, CNVS-10225 TEST PLAN ---- ---- Testing this will be a bit rough because there are many variations and validations to cover. I'll spare the validations that are covered by specs from the test plan. Create a quiz with a question of *each* type except "Text" and "File Upload". There's a script that creates a quiz with its questions automatically for you if you don't want to keep doing this manually. See references. > Answering Questions Now you need to answer each question via the API. Most of them vary in formats, but they are fully specified in the API documentation page (along with examples). See DOCUMENTATION for more info. > Flagging Questions Flagging, and unflagging, a question is the same regardless of its type, see the "EXAMPLE REQUESTS" section. > Access Validations Here are some generic, non-question based validations to verify. You should NOT be able to answer a question if: - the quiz submission has been turned in - the quiz submission is overdue - the Access Code for the quiz is invalid - the IP filter of the Quiz prohibits you from taking the quiz - the quiz submission :validation_token is incorrectly specified (ie, other students shouldn't be able to answer your questions) - you don't specify the latest :attempt, so if the Quiz has multiple attempts, and this is your 2nd take, you specify an :attempt of 1, 3, or anything but 2 should fail - NEW: turn quiz into an OQAAT quiz with the "Can't go back" flag on; the API should not reject all requests to modify any of the questions with a 501 error saying that type of quizzes is not supported yet (support will come in CNVS-10224) > Grading Also, when you're done answering the questions, take a look at the grades and make sure everything gets graded just like it does when using the UI directly. > Verifying results in the browser While taking a quiz in the canvas UI, the scripts perform backups in the background that would overwrite any changes you do via the API. If you want to verify the changes you make via the API from the UI, you must append "?backup=false" to the take quiz page URL, something like this: http://localhost:3000/courses/1/quizzes/1/take?backup=false Setting that flag will (for now) disable the backup behaviour and should make things tick. EXAMPLE REQUESTS ------- -------- Don't forget to set the 'Content-Type' header to 'application/json'! > Answering a Multiple-Choice question [PUT] /api/v1/quiz_submissions/:quiz_submission_id/questions/:id { "attempt": 1, "validation_token": "1babd0...", "answer": 10 } > Flagging a question [PUT] /api/v1/quiz_submissions/:quiz_submission_id/questions/:id/flag { "attempt": 1, "validation_token": "1babd0..." } > Unflagging a question [PUT] /api/v1/quiz_submissions/:quiz_submission_id/questions/:id/unflag { "attempt": 1, "validation_token": "1babd0..." } DOCUMENTATION ------------- Run `bundle exec rake doc:api` and check out the Quiz Submission Questions page. There's an Appendix that contains example requests for each question type, as well as the errors produced by each handler. LINKS ----- - bootstrap script: https://gist.github.com/amireh/e7e8f835ffbf1d053e4c - direct link to the API documentation page: http://canvas.docs.kodoware.com/quiz_submission_questions.html Change-Id: I9a958323ece8854bc21a24c2affd8dc3972e46d5 Reviewed-on: https://gerrit.instructure.com/27206 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> QA-Review: Myller de Araujo <myller@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com>
2013-12-10 17:15:01 +08:00
end
scope(controller: "quizzes/quiz_ip_filters") do
get "courses/:course_id/quizzes/:quiz_id/ip_filters", action: :index, as: "course_quiz_ip_filters"
Quiz IP Filters API controller - #index This patch moves rendering of IP filters from the QuizzesController into a separate, specialized API controller - QuizzesIpFilters. The rendered IP filter object is backwards-compatible, as in it provides the same three attributes: name, account, and filter. However, the endpoint output has been modified to scope the array of filters under "quiz_ip_filters". The front-end/JS part has been adjusted to accommodate this change. REFACTORING ----------- In an effort to reduce complexity, I've also taken to refactor all the :before_filters that were looking up Quiz in the current context across all Quiz controllers (where it was applicable), and that was done by introducing a new component set: API Helpers. API Helpers are modules that can be mixed-in, just like the API Modules, that are really just a place to hold routines common between the API and the regular controllers. I've put the first one in lib/api/v1/helpers, namespaced under Api::V1::Helpers... TEST PLAN ---- ---- - Create a Quiz. No questions. - Set an IP filter of 192.168.1.1 on the Quiz - the restriction should still hold like it usually does - Perform a GET request to this endpoint: /courses/:course_id/quizzes/:quiz_id/ip_filters - A list of filters should be returned in JSON-API format containing the filter you set for the Quiz - Add one or more IP Filters on the account-level, and: - Re-perform the GET query: - The list should contain both the Quiz and the Account filters - Using the IP Filter search box from the Quiz settings page: - It should still properly list the available filters refs CNVS-8988, CNVS-9586 Change-Id: I75c1b85024a58e6accd1627b7bee3da1185d2658 Reviewed-on: https://gerrit.instructure.com/26440 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> QA-Review: Myller de Araujo <myller@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com>
2013-11-19 17:06:49 +08:00
end
scope(controller: "quizzes/quiz_statistics") do
get "courses/:course_id/quizzes/:quiz_id/statistics", action: :index, as: "course_quiz_statistics"
end
Quiz IP Filters API controller - #index This patch moves rendering of IP filters from the QuizzesController into a separate, specialized API controller - QuizzesIpFilters. The rendered IP filter object is backwards-compatible, as in it provides the same three attributes: name, account, and filter. However, the endpoint output has been modified to scope the array of filters under "quiz_ip_filters". The front-end/JS part has been adjusted to accommodate this change. REFACTORING ----------- In an effort to reduce complexity, I've also taken to refactor all the :before_filters that were looking up Quiz in the current context across all Quiz controllers (where it was applicable), and that was done by introducing a new component set: API Helpers. API Helpers are modules that can be mixed-in, just like the API Modules, that are really just a place to hold routines common between the API and the regular controllers. I've put the first one in lib/api/v1/helpers, namespaced under Api::V1::Helpers... TEST PLAN ---- ---- - Create a Quiz. No questions. - Set an IP filter of 192.168.1.1 on the Quiz - the restriction should still hold like it usually does - Perform a GET request to this endpoint: /courses/:course_id/quizzes/:quiz_id/ip_filters - A list of filters should be returned in JSON-API format containing the filter you set for the Quiz - Add one or more IP Filters on the account-level, and: - Re-perform the GET query: - The list should contain both the Quiz and the Account filters - Using the IP Filter search box from the Quiz settings page: - It should still properly list the available filters refs CNVS-8988, CNVS-9586 Change-Id: I75c1b85024a58e6accd1627b7bee3da1185d2658 Reviewed-on: https://gerrit.instructure.com/26440 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Derek DeVries <ddevries@instructure.com> QA-Review: Myller de Araujo <myller@instructure.com> Product-Review: Ahmad Amireh <ahmad@instructure.com>
2013-11-19 17:06:49 +08:00
scope(controller: "polling/polls") do
get "polls", action: :index, as: "polls"
post "polls", action: :create, as: "poll_create"
get "polls/:id", action: :show, as: "poll"
put "polls/:id", action: :update, as: "poll_update"
delete "polls/:id", action: :destroy, as: "poll_destroy"
end
scope(controller: "polling/poll_choices") do
get "polls/:poll_id/poll_choices", action: :index, as: "poll_choices"
post "polls/:poll_id/poll_choices", action: :create, as: "poll_choices_create"
get "polls/:poll_id/poll_choices/:id", action: :show, as: "poll_choice"
put "polls/:poll_id/poll_choices/:id", action: :update, as: "poll_choice_update"
delete "polls/:poll_id/poll_choices/:id", action: :destroy, as: "poll_choice_destroy"
add polling session and submission apis fixes CNVS-12474, CNVS-12477, CNVS-12478 this commit fleshes out the API endpoints for polling sessions and submissions, and solidifies the other polling endpoints. Test plan - Full tests on the following endpoints: - Polls are the basic data model of the polling app. They can take a question attribute and a description attribute. They are only creatable and modifiable by teachers. - GET /api/v1/polls (index action) - POST /api/v1/polls (create action) - GET /api/v1/polls/:id (show action) - PUT /api/v1/polls/:id (update action) - DELETE /api/v1/polls/:id (destroy action) - Poll choices belong to polls. They consist of the particular answers a submitter can choose when participating in a poll session. They have attributes of text (the answer text), their associated poll, and an 'is_correct' boolean attribute. The 'is_correct' attribute show not be accessible by students. Poll choices are only creatable and modifiable by the creator of the poll. - GET /api/v1/polls/:poll_id/poll_choices (index action) - POST /api/v1/polls/:poll_id/poll_choices (create action) - GET /api/v1/polls/:poll_id/poll_choices/:id (show action) - PUT /api/v1/polls/:poll_id/poll_choices/:id (update action) - DELETE /api/v1/polls/:poll_id/poll_choices/:id (destroy action) - Poll sessions are for publishing a poll so that it can accept submissions. They should only be createable / modifiable by teachers. Only students that are enrolled in the associated course of the poll session should be allowed to view them. The show action of a poll session acts differently for a teacher. They are able to see the results of the voting that has taken place by students since the session was published. - GET /api/v1/polls/:poll_id/poll_sessions (index action) - POST /api/v1/polls/:poll_id/poll_sessions (create action) - GET /api/v1/polls/:poll_id/poll_sessions/:id (show action) - PUT /api/v1/polls/:poll_id/poll_sessions/:id (update action) - DELETE /api/v1/polls/:poll_id/poll_sessions/:id (destroy action) - GET /api/v1/polls/:poll_id/poll_sessions/:id/publish (publish action) - GET /api/v1/polls/:poll_id/poll_sessions/:id/close (close action) - Poll submissions are for submitting an answer for a particular poll session. A student should only be allowed to submit a poll choice for a session they're able to view, and they can only submit one poll choice per poll session. - GET /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions/:id (show action) - POST /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions (create action) Change-Id: Ifcfd72ec30597e37fc54c687fb7d61a644d7348c Reviewed-on: https://gerrit.instructure.com/34605 Reviewed-by: Derek DeVries <ddevries@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Caleb Guanzon <cguanzon@instructure.com> Product-Review: Josh Simpson <jsimpson@instructure.com>
2014-05-06 05:58:49 +08:00
end
scope(controller: "polling/poll_sessions") do
get "polls/:poll_id/poll_sessions", action: :index, as: "poll_sessions"
post "polls/:poll_id/poll_sessions", action: :create, as: "poll_sessions_create"
get "polls/:poll_id/poll_sessions/:id", action: :show, as: "poll_session"
put "polls/:poll_id/poll_sessions/:id", action: :update, as: "poll_session_update"
delete "polls/:poll_id/poll_sessions/:id", action: :destroy, as: "poll_session_destroy"
get "polls/:poll_id/poll_sessions/:id/open", action: :open, as: "poll_session_publish"
get "polls/:poll_id/poll_sessions/:id/close", action: :close, as: "poll_session_close"
get "poll_sessions/opened", action: :opened, as: "poll_sessions_opened"
get "poll_sessions/closed", action: :closed, as: "poll_sessions_closed"
add polling session and submission apis fixes CNVS-12474, CNVS-12477, CNVS-12478 this commit fleshes out the API endpoints for polling sessions and submissions, and solidifies the other polling endpoints. Test plan - Full tests on the following endpoints: - Polls are the basic data model of the polling app. They can take a question attribute and a description attribute. They are only creatable and modifiable by teachers. - GET /api/v1/polls (index action) - POST /api/v1/polls (create action) - GET /api/v1/polls/:id (show action) - PUT /api/v1/polls/:id (update action) - DELETE /api/v1/polls/:id (destroy action) - Poll choices belong to polls. They consist of the particular answers a submitter can choose when participating in a poll session. They have attributes of text (the answer text), their associated poll, and an 'is_correct' boolean attribute. The 'is_correct' attribute show not be accessible by students. Poll choices are only creatable and modifiable by the creator of the poll. - GET /api/v1/polls/:poll_id/poll_choices (index action) - POST /api/v1/polls/:poll_id/poll_choices (create action) - GET /api/v1/polls/:poll_id/poll_choices/:id (show action) - PUT /api/v1/polls/:poll_id/poll_choices/:id (update action) - DELETE /api/v1/polls/:poll_id/poll_choices/:id (destroy action) - Poll sessions are for publishing a poll so that it can accept submissions. They should only be createable / modifiable by teachers. Only students that are enrolled in the associated course of the poll session should be allowed to view them. The show action of a poll session acts differently for a teacher. They are able to see the results of the voting that has taken place by students since the session was published. - GET /api/v1/polls/:poll_id/poll_sessions (index action) - POST /api/v1/polls/:poll_id/poll_sessions (create action) - GET /api/v1/polls/:poll_id/poll_sessions/:id (show action) - PUT /api/v1/polls/:poll_id/poll_sessions/:id (update action) - DELETE /api/v1/polls/:poll_id/poll_sessions/:id (destroy action) - GET /api/v1/polls/:poll_id/poll_sessions/:id/publish (publish action) - GET /api/v1/polls/:poll_id/poll_sessions/:id/close (close action) - Poll submissions are for submitting an answer for a particular poll session. A student should only be allowed to submit a poll choice for a session they're able to view, and they can only submit one poll choice per poll session. - GET /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions/:id (show action) - POST /api/v1/polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions (create action) Change-Id: Ifcfd72ec30597e37fc54c687fb7d61a644d7348c Reviewed-on: https://gerrit.instructure.com/34605 Reviewed-by: Derek DeVries <ddevries@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Caleb Guanzon <cguanzon@instructure.com> Product-Review: Josh Simpson <jsimpson@instructure.com>
2014-05-06 05:58:49 +08:00
end
scope(controller: "polling/poll_submissions") do
post "polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions", action: :create, as: "poll_submissions_create"
get "polls/:poll_id/poll_sessions/:poll_session_id/poll_submissions/:id", action: :show, as: "poll_submission"
end
scope(controller: "live_assessments/assessments") do
2015-06-26 03:35:25 +08:00
get "courses/:course_id/live_assessments", action: :index, as: "course_live_assessments"
post "courses/:course_id/live_assessments", action: :create, as: "course_live_assessment_create"
end
scope(controller: "live_assessments/results") do
2015-06-26 03:35:25 +08:00
get "courses/:course_id/live_assessments/:assessment_id/results", action: :index, as: "course_live_assessment_results"
post "courses/:course_id/live_assessments/:assessment_id/results", action: :create, as: "course_live_assessment_result_create"
end
scope(controller: "support_helpers/turnitin") do
get "support_helpers/turnitin/md5", action: :md5
get "support_helpers/turnitin/error2305", action: :error2305
get "support_helpers/turnitin/shard", action: :shard
get "support_helpers/turnitin/assignment", action: :assignment
get "support_helpers/turnitin/pending", action: :pending
get "support_helpers/turnitin/expired", action: :expired
get "support_helpers/turnitin/refresh_lti_attachment", action: :lti_attachment
end
scope(controller: "support_helpers/plagiarism_platform") do
get "support_helpers/plagiarism_platform/add_service", action: :add_service
get "support_helpers/plagiarism_platform/resubmit_for_assignment/:assignment_id", action: :resubmit_for_assignment
end
scope(controller: "support_helpers/crocodoc") do
get "support_helpers/crocodoc/shard", action: :shard
get "support_helpers/crocodoc/submission", action: :submission
end
scope(controller: "support_helpers/submission_lifecycle_manage") do
get "support_helpers/submission_lifecycle_manage/course", action: :course
end
scope(controller: :outcome_groups_api) do
2015-06-26 03:35:25 +08:00
%w[global account course].each do |context|
prefix = ((context == "global") ? context : "#{context}s/:#{context}_id")
unless context == "global"
get "#{prefix}/outcome_groups", action: :index, as: "#{context}_outcome_groups"
get "#{prefix}/outcome_group_links", action: :link_index, as: "#{context}_outcome_group_links"
end
get "#{prefix}/root_outcome_group", action: :redirect, as: "#{context}_redirect"
get "#{prefix}/outcome_groups/account_chain", action: :account_chain, as: "#{context}_account_chain"
get "#{prefix}/outcome_groups/:id", action: :show, as: "#{context}_outcome_group"
put "#{prefix}/outcome_groups/:id", action: :update
delete "#{prefix}/outcome_groups/:id", action: :destroy
get "#{prefix}/outcome_groups/:id/outcomes", action: :outcomes, as: "#{context}_outcome_group_outcomes"
get "#{prefix}/outcome_groups/:id/available_outcomes", action: :available_outcomes, as: "#{context}_outcome_group_available_outcomes"
post "#{prefix}/outcome_groups/:id/outcomes", action: :link
put "#{prefix}/outcome_groups/:id/outcomes/:outcome_id", action: :link, as: "#{context}_outcome_link"
delete "#{prefix}/outcome_groups/:id/outcomes/:outcome_id", action: :unlink
get "#{prefix}/outcome_groups/:id/subgroups", action: :subgroups, as: "#{context}_outcome_group_subgroups"
post "#{prefix}/outcome_groups/:id/subgroups", action: :create
post "#{prefix}/outcome_groups/:id/import", action: :import, as: "#{context}_outcome_group_import"
post "#{prefix}/outcome_groups/:id/batch", action: :batch, as: "#{context}_outcome_group_batch"
end
end
scope(controller: :outcomes_api) do
get "outcomes/:id", action: :show, as: "outcome"
put "outcomes/:id", action: :update
delete "outcomes/:id", action: :destroy
get "courses/:course_id/outcome_alignments", action: :outcome_alignments
end
scope(controller: :outcome_results) do
get "courses/:course_id/outcome_rollups", action: :rollups, as: "course_outcome_rollups"
get "courses/:course_id/outcome_results", action: :index, as: "course_outcome_results"
post "courses/:course_id/assign_outcome_order", action: :outcome_order, as: "course_outcomes_order"
end
scope(controller: :outcomes_academic_benchmark_import_api) do
# These can be uncommented when implemented
# get "global/outcomes_import", action: :index
# get "global/outcomes_import/:id", action: :show
# put "global/outcomes_import/:id", action: :cancel
# get "global/outcomes_import/list/:guid", action: :list
get "global/outcomes_import/available", action: :available
post "global/outcomes_import", action: :create
get "global/outcomes_import/migration_status/:migration_id", action: :migration_status
end
scope(controller: :group_categories) do
resources :group_categories, except: [:index, :create]
get "accounts/:account_id/group_categories", action: :index, as: "account_group_categories"
get "courses/:course_id/group_categories", action: :index, as: "course_group_categories"
post "accounts/:account_id/group_categories", action: :create
post "courses/:course_id/group_categories", action: :create
post "group_categories/:group_category_id/import", action: :import
get "group_categories/:group_category_id/groups", action: :groups, as: "group_category_groups"
get "group_categories/:group_category_id/users", action: :users, as: "group_category_users"
get "group_categories/:group_category_id/export", action: :export, as: "group_category_export", defaults: { format: :csv }
post "group_categories/:group_category_id/assign_unassigned_members", action: "assign_unassigned_members", as: "group_category_assign_unassigned_members"
end
scope(controller: :progress) do
get "progress/:id", action: :show, as: "progress"
gradebook exporter progress indicator when gradebook export is initiated add progress bar for user along with new success message. also handle user cancelling exports fixes EVAL-2625 flag=none test plan: - open gradebook (both enhanced/normal) - click on export button - click on either of the Export gradebook options - verify that shortly after button press the alert message is shown that export has started - verify that progress bar displays and eventually goes to 100% - verify that after the export reaches 100% that a success message is shown and ~3 seconds both the success message and progress bar disappear - verify that you are able to do additional exports both before reloading page and after - additional functionality to test is the cancel export - trigger an upload and before the export finishes click on the X button to cancel the export - once clicked the progress bar should go away and an alert info message should be displayed letting the user know they cancelled. - verify that you are able to do additional exports both before reloading page and after Change-Id: I757c1da4a31b9744e8f00455b7ae7736bf605df7 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/301343 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Derek Williams <derek.williams@instructure.com> Reviewed-by: Kai Bjorkman <kbjorkman@instructure.com> QA-Review: Cameron Ray <cameron.ray@instructure.com> Product-Review: Deborah Kwak <deborah.kwak@instructure.com>
2022-09-14 00:24:09 +08:00
post "progress/:id/cancel", action: :cancel
end
scope(controller: :app_center) do
2015-06-26 03:35:25 +08:00
%w[course account].each do |context|
prefix = "#{context}s/:#{context}_id/app_center"
get "#{prefix}/apps", action: :index, as: "#{context}_app_center_apps"
get "#{prefix}/apps/:app_id/reviews", action: :reviews, as: "#{context}_app_center_app_reviews"
get "#{prefix}/apps/:app_id/reviews/self", action: :review, as: "#{context}_app_center_app_review"
post "#{prefix}/apps/:app_id/reviews/self", action: :add_review
end
end
feature flags infrastructure and API 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>
2013-10-22 23:28:26 +08:00
scope(controller: :feature_flags) do
2015-06-26 03:35:25 +08:00
%w[course account user].each do |context|
feature flags infrastructure and API 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>
2013-10-22 23:28:26 +08:00
prefix = "#{context}s/:#{context}_id/features"
get prefix.to_s, action: :index, as: "#{context}_features"
get "#{prefix}/enabled", action: :enabled_features, as: "#{context}_enabled_features"
get "#{prefix}/flags/:feature", action: :show
put "#{prefix}/flags/:feature", action: :update
delete "#{prefix}/flags/:feature", action: :delete
feature flags infrastructure and API 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>
2013-10-22 23:28:26 +08:00
end
get "features/environment", action: :environment
feature flags infrastructure and API 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>
2013-10-22 23:28:26 +08:00
end
scope(controller: :conferences) do
%w[course group].each do |context|
prefix = "#{context}s/:#{context}_id/conferences"
get prefix, action: :index, as: "#{context}_conferences"
post prefix.to_s, action: :create
post "#{prefix}/:conference_id/recording_ready", action: :recording_ready, as: "#{context}_conferences_recording_ready"
end
Add API endpoint for a user's conferences flag=none closes MBL-14123 Test plan: - Enable BigBlueButton (or similar) on your local Canvas - (you can enable BBB at /plugins/big_blue_button) - Have a course with at least one student (S1) - Within the course, create a group set, and create at least one group with S1 in it - Create a conference for the course - Invite S1 (or check "Invite all course members" on creation) - Do not start the conference yet - Create a conference for S1's group from the group homepage - Invite S1 (or check "Invite all group members" on creation) - Do not start the conference yet - Logged in as S1, access the endpoint: - /api/v1/conferences - You should get a JSON response containing both the conferences you created above (contained in the "conferences" hash) - /api/v1/conferences?state=live - You should get a JSON response with an empty array (contained in the "conferences" hash) - Start one or more of the conferences you created - Access the endpoint again; this time, it should include the conferences you just started - Stop the conferences you started - Access the endpoint again; it should be back to returning an empty array Change-Id: Id91ca3a8a42fd1f1f9e092c3e30a0e788134886e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/230542 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Reviewed-by: Keith Garner <kgarner@instructure.com> QA-Review: Nate Armstrong <narmstrong@instructure.com> Product-Review: Keith Garner <kgarner@instructure.com>
2020-03-19 02:55:42 +08:00
get "conferences", action: :for_user, as: "conferences"
end
scope(controller: :custom_gradebook_columns_api) do
prefix = "courses/:course_id/custom_gradebook_columns"
get prefix, action: :index, as: "course_custom_gradebook_columns"
post prefix, action: :create
2015-06-26 03:35:25 +08:00
post "#{prefix}/reorder", action: :reorder, as: "custom_gradebook_columns_reorder"
put "#{prefix}/:id", action: :update, as: "course_custom_gradebook_column"
delete "#{prefix}/:id", action: :destroy
end
scope(controller: :custom_gradebook_column_data_api) do
prefix = "courses/:course_id/custom_gradebook_columns/:id/data"
get prefix, action: :index, as: "course_custom_gradebook_column_data"
put "#{prefix}/:user_id", action: :update, as: "course_custom_gradebook_column_datum"
put "courses/:course_id/custom_gradebook_column_data", action: :bulk_update, as: "course_custom_gradebook_column_bulk_data"
end
scope(controller: :content_exports_api) do
zip content exports for course, group, user test plan: 1. use the content exports api with export_type=zip to export files from courses, groups, and users a. confirm only users who have permission to download files from these contexts can perform the export b. confirm that deleted files and folders do not show up in the downloaded archive c. confirm that students cannot download locked files or folders from courses this way d. check the progress endpoint and make sure it increments sanely 2. perform selective content exports by passing an array of ids in select[folders] and/or select[attachments]. for example, ?select[folders][]=123&select[folders][]=456 ?select[attachments][]=345 etc. a. any selected files, plus the full contents of any selected folders (that the caller has permission to see) should be included - that means locked files and subfolders should be excluded from the archive b. if all selected files and folders are descendants of the same subfolder X, the export should be named "X_export.zip" and all paths inside the zip should be relative to it. for example, if you are exporting A/B/1 and A/C/2, you should get "A_export.zip" containing files "B/1" and "C/2". 3. use the index and show endpoints to list and view content exports in courses, groups, and users a. confirm students cannot view non-zip course exports (such as common cartridge exports) b. confirm students cannot view other users' file (zip) exports, in course, group, and user context c. confirm teachers cannot view other users' file (zip) exports, in course, group, and user context (but can still view course [cc] exports initiated by other teachers) 4. look at /courses/X/content_exports (web, not API) a. confirm teachers see file exports they performed b. confirm teachers do not see file exports performed by other teachers c. confirm teachers see all non-zip course exports (cc/qti) including those initiated by other teachers 5. as a site admin user, perform a zip export of another user's files. then, as that other user, go to /dashboard/data_exports and confirm that the export performed by the site admin user is not shown. fixes CNVS-12706 Change-Id: Ie9b58e44ac8006a9c9171b3ed23454bf135385b0 Reviewed-on: https://gerrit.instructure.com/34341 Reviewed-by: James Williams <jamesw@instructure.com> QA-Review: Trevor deHaan <tdehaan@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Product-Review: Jon Willesen <jonw@instructure.com>
2014-07-18 04:00:32 +08:00
%w[course group user].each do |context|
context_prefix = "#{context.pluralize}/:#{context}_id"
prefix = "#{context_prefix}/content_exports"
get prefix, action: :index, as: "#{context}_content_exports"
post prefix, action: :create
get "#{prefix}/:id", action: :show
put "#{prefix}/:id/fail", action: :fail
zip content exports for course, group, user test plan: 1. use the content exports api with export_type=zip to export files from courses, groups, and users a. confirm only users who have permission to download files from these contexts can perform the export b. confirm that deleted files and folders do not show up in the downloaded archive c. confirm that students cannot download locked files or folders from courses this way d. check the progress endpoint and make sure it increments sanely 2. perform selective content exports by passing an array of ids in select[folders] and/or select[attachments]. for example, ?select[folders][]=123&select[folders][]=456 ?select[attachments][]=345 etc. a. any selected files, plus the full contents of any selected folders (that the caller has permission to see) should be included - that means locked files and subfolders should be excluded from the archive b. if all selected files and folders are descendants of the same subfolder X, the export should be named "X_export.zip" and all paths inside the zip should be relative to it. for example, if you are exporting A/B/1 and A/C/2, you should get "A_export.zip" containing files "B/1" and "C/2". 3. use the index and show endpoints to list and view content exports in courses, groups, and users a. confirm students cannot view non-zip course exports (such as common cartridge exports) b. confirm students cannot view other users' file (zip) exports, in course, group, and user context c. confirm teachers cannot view other users' file (zip) exports, in course, group, and user context (but can still view course [cc] exports initiated by other teachers) 4. look at /courses/X/content_exports (web, not API) a. confirm teachers see file exports they performed b. confirm teachers do not see file exports performed by other teachers c. confirm teachers see all non-zip course exports (cc/qti) including those initiated by other teachers 5. as a site admin user, perform a zip export of another user's files. then, as that other user, go to /dashboard/data_exports and confirm that the export performed by the site admin user is not shown. fixes CNVS-12706 Change-Id: Ie9b58e44ac8006a9c9171b3ed23454bf135385b0 Reviewed-on: https://gerrit.instructure.com/34341 Reviewed-by: James Williams <jamesw@instructure.com> QA-Review: Trevor deHaan <tdehaan@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Product-Review: Jon Willesen <jonw@instructure.com>
2014-07-18 04:00:32 +08:00
end
get "courses/:course_id/content_list", action: :content_list, as: "course_content_list"
add endpoint /api/v1/courses/:course_id/content_exports/:id closes QUIZ-13324 flag=none prerequisite: * have site admin access tokens set up * not sure if you have site admin tokens set? this may help https://instructure.slack.com/archives/G015HU5JY90/p1709330547760219?thread_ts=1709321072.821909&cid=G015HU5JY90 https://instructure.atlassian.net/wiki/spaces/QUIZ/pages/85965832229/Migrate+to+Site+Admin+tokens+in+dev+environments test plan: - pull the changes from g/341082 into quiz_lti - open Canvas - go to a course, and open the Settings page - export the course (as a common cartridge) - save the course ID and comon cartridge ContentExport ID - open a rails console in quiz_lti - activate your shard - run to load the "client" ``` include Canvas::ApiClientCommon override_context(my_course_context) ``` - send put requests to update the content export with new quizzes export settings ``` r = client.put_content_export( {content_export: {new_quizzes_export_url: 'https://some.url', new_quizzes_export_state: 'completed'}}, course_id: MY_COURSE_ID, content_export_id: CANVAS_CONTENT_EXPORT_ID) r.response ``` - MY_COURSE_ID can be set as the course ID, for example, 5, or uuid, in which case it should be set with the following format "uuid:dyaO8caUY0a6cwgcqDocjOCCYyO1EzNXQXG7fVdQ" - open a rails console in canvas and find the ContentExport record - inspect the content export settings - observe that the new_quizzes_export_url and new_quizzes_export_state settings have the values you sent from quiz_lti - send another put request and try to update other fields, for example, export_type - observe that the fields don't update Change-Id: Iade9b3cbc09c04ed1ff6a2e40865c3e0cde5fd8d Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/341091 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: James Logan <james.logan@instructure.com> QA-Review: Ricardo Oliveira <ricardo.oliveira@instructure.com> Product-Review: Marissa Pio Roda <marissa.pioroda@instructure.com>
2024-02-23 04:56:08 +08:00
put "courses/:course_id/content_exports/:id", action: :update
end
scope(controller: :epub_exports) do
get "courses/:course_id/epub_exports/:id", {
action: :show
}
get "epub_exports", {
action: :index
}
post "courses/:course_id/epub_exports", {
action: :create
}
end
scope(controller: :web_zip_exports) do
get "courses/:course_id/web_zip_exports", action: :index, as: "web_zip_exports"
get "courses/:course_id/web_zip_exports/:id", action: :show
end
scope(controller: :grading_standards_api) do
get "courses/:course_id/grading_standards", action: :context_index
get "accounts/:account_id/grading_standards", action: :context_index
get "courses/:course_id/grading_standards/:grading_standard_id", action: :context_show
get "accounts/:account_id/grading_standards/:grading_standard_id", action: :context_show
post "accounts/:account_id/grading_standards", action: :create
post "courses/:course_id/grading_standards", action: :create
end
get "/crocodoc_session", controller: "crocodoc_sessions", action: "show", as: :crocodoc_session
get "/canvadoc_session", controller: "canvadoc_sessions", action: "show", as: :canvadoc_session
post "/canvadoc_session", controller: "canvadoc_sessions", action: "create"
scope(controller: :grading_period_sets) do
get "accounts/:account_id/grading_period_sets", action: :index, as: :account_grading_period_sets
post "accounts/:account_id/grading_period_sets", action: :create
patch "accounts/:account_id/grading_period_sets/:id", action: :update, as: :account_grading_period_set
delete "accounts/:account_id/grading_period_sets/:id", action: :destroy
end
scope(controller: :grading_periods) do
remove account association from grading periods and their groups Accounts will no longer be directly associated with grading periods or grading period groups. A grading period group can: * have only one or more enrollment terms * belong only to a course (for legacy data) Testing Notes: * To create a GradingPeriodGroup for an EnrollmentTerm: * Create an EnrollmentTerm `enrollment_term` * `group = GradingPeriodGroup.new(title: "Example")` * `group.enrollment_terms << enrollment_term` * `group.save!` test plan: A. repeat tests with commit at SHA: 861015a B. grading standards for an account 1. find or create an Account 2. visit `/accounts/[account id]/grading_standards` 3. verify there is no grading periods UI 4. verify that grading schemes are still manageable C. grading standards for a course with grading periods 1. find or create: a. an Account b. an EnrollmentTerm for the Account c. a Course for that Account 2. associate the Course with the EnrollmentTerm 3. in the Rails console `bundle exec rails console` a. create a GradingPeriodGroup for the Course b. create at least one GradingPeriod in the course group c. create a GradingPeriodGroup for the EnrollmentTerm d. create at least one GradingPeriod in the term group 4. visit `/courses/[course id]/grading_standards` 5. verify the grading period(s) on the course are present 5. verify the grading period(s) on the term are not present 6. verify that grading schemes are still manageable D. grading standards for a course with no grading periods 1. find or create: a. an Account b. an EnrollmentTerm for the Account c. a Course for that Account 2. associate the Course with the EnrollmentTerm 3. in the Rails console `bundle exec rails console` a. create a GradingPeriodGroup for the EnrollmentTerm b. create at least one GradingPeriod in the group 4. visit `/courses/[course id]/grading_standards` 5. verify the grading periods on the term are present 6. verify that grading schemes are still manageable closes CNVS-26725 Change-Id: I7883cb421c87ebb91c818223c0483557fdd5e40a Reviewed-on: https://gerrit.instructure.com/78167 Reviewed-by: Derek Bender <djbender@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> QA-Review: KC Naegle <knaegle@instructure.com> Tested-by: Jenkins Product-Review: Keith T. Garner <kgarner@instructure.com>
2016-04-22 06:09:15 +08:00
# FIXME: This route will be removed/replaced with CNVS-27101
get "accounts/:account_id/grading_periods", action: :index, as: :account_grading_periods
get "courses/:course_id/grading_periods", action: :index, as: :course_grading_periods
get "courses/:course_id/grading_periods/:id", action: :show, as: :course_grading_period
patch "courses/:course_id/grading_periods/batch_update",
action: :batch_update,
as: :course_grading_period_batch_update
put "courses/:course_id/grading_periods/:id", action: :update, as: :course_grading_period_update
delete "courses/:course_id/grading_periods/:id", action: :destroy, as: :course_grading_period_destroy
delete grading periods and grading period sets allows the user to delete grading periods and grading period sets after confirmation. closes CNVS-27105 test plan 1 - grading period deletion: - go to the account grading periods page for an account with at least 2 grading period sets with some grading periods in them - click the trash can icon next to a grading period - verify an alert pops up asking the user to confirm that they want to delete the period - verify the period is not deleted if you click cancel - verify the period is deleted if you click OK - kill your server locally, and attempt to delete a grading period by clicking the trash icon. verify a message is displayed that says an error occured while deleting the grading period test plan 2 - grading period set deletion: - go to the account grading periods page for an account with at least 2 grading period sets - click the trash can icon next to a grading period set name - verify an alert pops up asking the user to confirm that they want to delete the set - verify the set is not deleted if you click cancel - verify the set is deleted if you click OK - kill your server locally, and attempt to delete a grading period set by clicking the trash icon. verify a message is displayed that says an error occured while deleting the grading period set test plan 3 - permissions: - go to a sub account grading periods page - verify there are no trash can icons Change-Id: Ic7a48e6a1fd2d2fb515c2e159bc547b104cbf3ac Reviewed-on: https://gerrit.instructure.com/81686 Reviewed-by: Jeremy Neander <jneander@instructure.com> Tested-by: Jenkins Reviewed-by: Keith T. Garner <kgarner@instructure.com> QA-Review: Amber Taniuchi <amber@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2016-06-07 00:28:17 +08:00
delete "accounts/:account_id/grading_periods/:id", action: :destroy, as: :account_grading_period_destroy
create new grading periods on account grading standards page When visiting the grading standards page, account admins need to be able to create new grading periods within grading period sets for their accounts. This implements that. closes CNVS-27102 To create a grading period, perform the following steps: 1. Select or create: a. a root account b. a root account admin c. an active enrollment term (required for grading period set) d. an active grading period set 2. Visit the account grading standards page 3. Expand a/the grading period set 4. Verify that the '+ Grading Period' button is visible 5. Click the '+ Grading Period' button 6. Fill in the form with: a. any title b. the given (or any) start date c. the given (or any) end date after the given start date 7. Click 'Create' 8. Verify: a. An flash message indicates a successful save b. The grading period is visible c. The grading period was created in the database d. The grading period has the expected attributes e. All grading periods are sorted by start date f. The grading period form was dismissed 9. OR verify: a. An flash message indicates a failure b. The grading period was not created c. The grading period form was not dismissed 10. Refresh the page 11. Verify the page reflects the expected presence/absence of the existing/created grading periods test plan: A. Can create a grading period with valid dates B. Can create multiple grading periods with valid dates C. Cannot create a grading period with an end date before its start date D. Cannot create a grading period without: 1. title 2. start date 3. end date E. Cannot create a grading period with a date range that includes the start date and/or end date of other grading periods F. Clicking 'Cancel' dismisses the form G. Creating a grading period between two other grading periods will display it between those grading periods H. Creating a grading period before any other grading periods will display it above those grading periods I. Can only view with sub accounts 1. Select or create: a. a root account b. an active enrollment term (required for grading period set) c. an active grading period set 2. Visit the account grading standards page 3. Expand a/the grading period set 4. Verify that the '+ Grading Period' button is NOT visible Change-Id: Ia6d2d5248a6e96815b2f881f5088dd46cc040e57 Reviewed-on: https://gerrit.instructure.com/81010 Tested-by: Jenkins QA-Review: KC Naegle <knaegle@instructure.com> Reviewed-by: Spencer Olson <solson@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com>
2016-06-02 09:29:09 +08:00
patch "grading_period_sets/:set_id/grading_periods/batch_update",
action: :batch_update,
as: :grading_period_set_periods_update
end
scope(controller: :usage_rights) do
%w[course group user].each do |context|
content_prefix = "#{context.pluralize}/:#{context}_id"
put "#{content_prefix}/usage_rights", action: :set_usage_rights
delete "#{content_prefix}/usage_rights", action: :remove_usage_rights
get "#{content_prefix}/content_licenses", action: :licenses
end
end
scope(controller: "bookmarks/bookmarks") do
get "users/self/bookmarks/", action: :index, as: :bookmarks
get "users/self/bookmarks/:id", action: :show
post "users/self/bookmarks", action: :create
delete "users/self/bookmarks/:id", action: :destroy
put "users/self/bookmarks/:id", action: :update
end
scope(controller: :course_nicknames) do
get "users/self/course_nicknames", action: :index, as: :course_nicknames
get "users/self/course_nicknames/:course_id", action: :show
put "users/self/course_nicknames/:course_id", action: :update
delete "users/self/course_nicknames/:course_id", action: :delete
delete "users/self/course_nicknames", action: :clear
end
All of the stuff from the save_a_theme dev branch this commit is the result of squashing a bunch of others together. this is everything that was already on the dev/save_a_theme branch as well as the "Add specs" commit. I left the test plans from some of the squashed commits in case they are helpful for QA Test plan: - Recompile assets, restart Canvas and clear browser cache - Go to Admin > [Your school name] - Click on Themes in the context menu - You should now see a collections page with a theme card for all the themes you have in Theme Editor: http://screencast.com/t/lb5vozF7 - Note: it might be my database, but on my end, I don't see a theme card for my Canvas default theme. There are also some brand colors missing for my theme cards. I'll be interested to see if you hit the same thing. These are issues that we can resolve with Ryan when he is back. - You should be able to click on the Apply and Delete buttons and see the confirm-overlays. We still need final copy for these. Test plan: - Go to your institution's Settings page and click Themes on the context menu. - You should now see a page listing all the default and user-created themes in your Canvas installation. - Clicking on each theme will open it inside theme editor. - The current/active theme will be correctly styled with a green outline change redirect targets and messages in theme editor test plan: exiting theme editor should redirect you back to the /accounts/x/themes page instead of /acounts/x make room for footer in theme editor test plan: in theme editor, scroll the preview to the bottom you should be able to scroll all the way, without having the bottom cut off by the footer remove "theme editor" button from account user/course search this is not needed since "Themes" now shows up in the left nav. test plan: turn on the 'Course and User Search' feature flag go to accounts/x you should not see a "theme editor" button on the right aka, not like this: http://cl.ly/2G2C3p3s3n0C fix "Exit" button in theme editor we were warning "you will lose unsaved changes" even when you hand not made any changes add specs to "Save A theme" stuff closes: CNVS-27961 test plan: do a whole regression test on the theme editor don't show both "k12 theme" and "canvas default" as options fixes: CNVS-25495 description (and test plan): if you are a k12 school, rather than seeing both "Canvas Default" and "K12 Theme" as options on the tiles of system themes to start from, you should now just see "Canvas Default". if you pick that, it should show the k12 theme. Change-Id: I5c2512e576dcb2aedaa899e17080d9c106e159ca Reviewed-on: https://gerrit.instructure.com/78163 Tested-by: Jenkins Reviewed-by: Rob Orton <rob@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com> QA-Review: Ryan Shaw <ryan@instructure.com>
2016-01-19 03:29:32 +08:00
scope(controller: :shared_brand_configs) do
post "accounts/:account_id/shared_brand_configs", action: :create
put "accounts/:account_id/shared_brand_configs/:id", action: :update
delete "shared_brand_configs/:id", action: :destroy
end
scope(controller: :errors) do
post "error_reports", action: :create
end
scope(controller: :jwts) do
post "jwts", action: :create
add endpoint to refresh jwt with with workflows now that services jwts have a concept of workflows and extra data encoded in the token based on workflow requirements, the existing jwts endpoint is insufficient for refreshing expired jwts. to some extent it was already broken since it lost the context when refreshed with that endpoint a new refresh endpoint has been addded that takes an exisintg jwt as a param. this makes it possible to get a new token with the same workflows, state, and context as an existing expired token as long as the token matches your user and is requested with a valid session or oauth token. tokens may only be used for refresh up to six hours past expiration. refs CNVS-35199 test plan: - go to "Pages" in a couse with RCS enabled - open the console, and get the jwt from ENV.JWT - wait at least an hour - make a POST to [same-domain]/api/v1/jwts/refresh with the token as the `jwt` param - it should return a json response with a token property - copy the token - open up your rails console - run Canvas::Security.ServicesJwt.new("[copied token]").original_token - should return hash with the following proerties - should have :sub with your users global id - should have :domain that matches your canvas domain - should have :context_type of Course - should have :context_id of the course you generated the original token from - should have :workflows with rich_content and ui - repeat process masquerading as another user - when making a the post to the refresh endpoint use your user and set a param `as_user_id` to the id of the user you are masquerading as - the hash in the console should have - :sub with the global id of the user you are masquerading as - :masq_sub with your user id Change-Id: I399569ed8f2d3d0646728f72910456b77b3ed46a Reviewed-on: https://gerrit.instructure.com/102909 Reviewed-by: Tucker McKnight <tmcknight@instructure.com> QA-Review: Tucker McKnight <tmcknight@instructure.com> Tested-by: Jenkins Product-Review: Brent Burgoyne <bburgoyne@instructure.com>
2017-02-23 00:16:49 +08:00
post "jwts/refresh", action: :refresh
end
scope(controller: :inst_access_tokens) do
upgrade graphql gem to latest fixes INTEROP-6951 upgrade required some tweaks including the following: - `GraphQL::Execution::Interpreter` removed from CanvasSchema because it is now included in GraphQL::Schema by default - `BaseMutation.input_type` adds arguments properly instead of using `merge!`, which blows up because `own_arguments` is a frozen Hash. (see https://github.com/rmosolgo/graphql-ruby/commit/55a955a84) - `NotificationPreferencesContextType` gets defined just once to avoid errors from specifying dupicate enum values each time its reopened - `.graphql_name` needed in a couple of places where `.name` (or implicit `.to_s` from string interpolation) previously worked. (see https://github.com/rmosolgo/graphql-ruby/blob/master/CHANGELOG.md#breaking-changes-14) - `GraphQL::Schema` uses the new `GrpahQL::Pagination::Connections` connections by default (previously `GraphQL::Relay::BaseConnection`), so our custom `PatchedArrayConnection` and `DynamoConnection` classes got redone in accordance with the new interface. - https://github.com/rmosolgo/graphql-ruby/pull/2792 made it so argument names are used as-specified, while previously they were automatically snake-cased. so the `gradingPeriodId` argument of `AssignmentFilterInputType` is now specified in snake-case, and everyone is happy. (note that in the generated GQL schema definition, it remains camel-cased, so the client interface is unchanged). - some sloppy queries in specs have been cleaned up because the GQL parser has been tightened up and was no longer recognizing them. also, unrelated to the gem bump, but the inst_access_tokens route was typo'd as a singular. here it's corrected to the plural. test plan: - since it's just a version bump, spec coverage should be sufficient Change-Id: Ib73eed4c1356833dfe245188b0841c98ae2c378a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/270132 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Ethan Vizitei <evizitei@instructure.com> QA-Review: Michael Ziwisky <mziwisky@instructure.com> Product-Review: Michael Ziwisky <mziwisky@instructure.com>
2021-07-28 13:49:16 +08:00
post "inst_access_tokens", action: :create
InstID tokens, part 1: generation fixes INTEROP-6913, INTEROP-6892, INTEROP-6893, INTEROP-6920 flag = none This commit introduces the InstID token, a signed and encrypted JWT (aka JWE) that will soon be usable for Canvas API access (that's "part 2"). If the InstID class is configured with a private signing key and public encryption key, it will be able to produce encrypted JWTs and validate and deserialize decrypted JWTs. If it is configured with only a public signing key, it cannot produce tokens but it can still validate and deserialize decrypted ones. Therefore this class can be used by the identity provider (currently Canvas) to produce tokens, but also by any services that want to use InstID tokens for authentication. test plan: 1) generate two RSA keypairs. one way to generate a keypair is from a rails console: > keypair = Canvas::Security::RSAKeyPair.new > puts keypair.private_key.to_s > puts keypair.public_key.to_s 2) choose which one is for signing and which is for encryption, then add the private signing key and the public encryption key to your rails credentials: - run `bin/rails credentials:edit` - add an entry like the following, and then save and close your editor: ``` inst_id: encryption_key: | -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvY1EMlGm1daM87ejGuFX <...snip...> /wIDAQAB -----END PUBLIC KEY----- signing_key: | -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAnDwED/QOB0f0H6TOZqLmjaPqA7m8c40NDXkAa6u5cK8zCbk3 <...snip...> QhjPgifBwTrzj21484CfiPfy5oe756Exerj8PIlRrE/hxWRSDwBIOg== -----END RSA PRIVATE KEY----- ``` 3) open a rails console and do: > id = InstID.for_user('user-uuid') > id.to_token # make sure this doesn't blow up > token = id.to_unencrypted_token > decoded_id = InstID.from_token(token) > id.jwt_payload == decoded_id.jwt_payload # => true TODO in followup commits: - make canvas accept InstID tokens for auth Change-Id: Ie550c17507c26f9944bd62a747a6a63161e8e770 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/268872 Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> QA-Review: Michael Ziwisky <mziwisky@instructure.com> Product-Review: Michael Ziwisky <mziwisky@instructure.com>
2021-07-13 11:46:17 +08:00
end
scope(controller: :gradebook_settings) do
put "courses/:course_id/gradebook_settings", action: :update, as: :course_gradebook_settings_update
end
scope(controller: :announcements_api) do
get "announcements", action: :index, as: :announcements
end
add new Rubric API endpoint closes OUT-358 refs PFS-4925 test plan: - review new API documentation - create some rubrics in the context of an account - create some rubrics in the context of a course - attach the rubrics to some assignments - for at least one assignment, enable peer reviews and assign some students - as a teacher, assess the assignment - as a student, complete some peer reviews - go to the following endpoints api/v1/accounts/{account_id}/rubrics - should list all rubrics in the given account api/v1/courses/{course_id}/rubrics - should list all rubrics in the given course api/v1/accounts/{account_id}/rubrics/{rubric_id} - should list the specific account rubric api/v1/courses/{course_id}/rubrics/{rubric_id} - should list the specific course rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=assessments - should include all assessments for the rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=graded_assessments - should include only the assessment(s) used for grading the rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=peer_assessments - should include only the peer_assessment(s) for the rubric - when getting assessments, add the following parameters &style=full should return the full data hash associated with returned assessments &style=comments_only should only return the comments from an assessment's data hash - when entering in invalid values for include or style, an error should be returned that provides you with the valid values for the respective parameters Change-Id: Ib46900d4c58e06d6fa2771614ba2efa11d3b5b6c Reviewed-on: https://gerrit.instructure.com/87702 Tested-by: Jenkins Reviewed-by: Michael Brewer-Davis <mbd@instructure.com> QA-Review: Alex Ortiz-Rosado <aortiz@instructure.com> Product-Review: Josh Simpson <jsimpson@instructure.com>
2016-08-13 04:40:02 +08:00
scope(controller: :release_notes) do
get "release_notes", action: :index, as: :release_notes
post "release_notes", action: :create
get "release_notes/latest", action: :latest
get "release_notes/unread_count", action: :unread_count
put "release_notes/:id", action: :update
delete "release_notes/:id", action: :destroy
put "release_notes/:id/published", action: :publish
delete "release_notes/:id/published", action: :unpublish
end
add new Rubric API endpoint closes OUT-358 refs PFS-4925 test plan: - review new API documentation - create some rubrics in the context of an account - create some rubrics in the context of a course - attach the rubrics to some assignments - for at least one assignment, enable peer reviews and assign some students - as a teacher, assess the assignment - as a student, complete some peer reviews - go to the following endpoints api/v1/accounts/{account_id}/rubrics - should list all rubrics in the given account api/v1/courses/{course_id}/rubrics - should list all rubrics in the given course api/v1/accounts/{account_id}/rubrics/{rubric_id} - should list the specific account rubric api/v1/courses/{course_id}/rubrics/{rubric_id} - should list the specific course rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=assessments - should include all assessments for the rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=graded_assessments - should include only the assessment(s) used for grading the rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=peer_assessments - should include only the peer_assessment(s) for the rubric - when getting assessments, add the following parameters &style=full should return the full data hash associated with returned assessments &style=comments_only should only return the comments from an assessment's data hash - when entering in invalid values for include or style, an error should be returned that provides you with the valid values for the respective parameters Change-Id: Ib46900d4c58e06d6fa2771614ba2efa11d3b5b6c Reviewed-on: https://gerrit.instructure.com/87702 Tested-by: Jenkins Reviewed-by: Michael Brewer-Davis <mbd@instructure.com> QA-Review: Alex Ortiz-Rosado <aortiz@instructure.com> Product-Review: Josh Simpson <jsimpson@instructure.com>
2016-08-13 04:40:02 +08:00
scope(controller: :rubrics_api) do
get "accounts/:account_id/rubrics", action: :index, as: :account_rubrics
get "accounts/:account_id/rubrics/:id", action: :show
get "courses/:course_id/rubrics", action: :index, as: :course_rubrics
get "courses/:course_id/rubrics/:id", action: :show
get "courses/:course_id/rubrics/:id/used_locations", action: "used_locations", as: "rubrics_course_used_locations"
get "accounts/:account_id/rubrics/:id/used_locations", action: "used_locations", as: "rubrics_account_used_locations"
post "courses/:course_id/rubrics", controller: :rubrics, action: :create
put "courses/:course_id/rubrics/:id", controller: :rubrics, action: :update
delete "courses/:course_id/rubrics/:id", controller: :rubrics, action: :destroy
add new Rubric API endpoint closes OUT-358 refs PFS-4925 test plan: - review new API documentation - create some rubrics in the context of an account - create some rubrics in the context of a course - attach the rubrics to some assignments - for at least one assignment, enable peer reviews and assign some students - as a teacher, assess the assignment - as a student, complete some peer reviews - go to the following endpoints api/v1/accounts/{account_id}/rubrics - should list all rubrics in the given account api/v1/courses/{course_id}/rubrics - should list all rubrics in the given course api/v1/accounts/{account_id}/rubrics/{rubric_id} - should list the specific account rubric api/v1/courses/{course_id}/rubrics/{rubric_id} - should list the specific course rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=assessments - should include all assessments for the rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=graded_assessments - should include only the assessment(s) used for grading the rubric api/v1/courses/{course_id}/rubrics/{rubric_id}?include=peer_assessments - should include only the peer_assessment(s) for the rubric - when getting assessments, add the following parameters &style=full should return the full data hash associated with returned assessments &style=comments_only should only return the comments from an assessment's data hash - when entering in invalid values for include or style, an error should be returned that provides you with the valid values for the respective parameters Change-Id: Ib46900d4c58e06d6fa2771614ba2efa11d3b5b6c Reviewed-on: https://gerrit.instructure.com/87702 Tested-by: Jenkins Reviewed-by: Michael Brewer-Davis <mbd@instructure.com> QA-Review: Alex Ortiz-Rosado <aortiz@instructure.com> Product-Review: Josh Simpson <jsimpson@instructure.com>
2016-08-13 04:40:02 +08:00
end
scope(controller: :rubric_associations) do
post "courses/:course_id/rubric_associations", action: :create
put "courses/:course_id/rubric_associations/:id", action: :update
delete "courses/:course_id/rubric_associations/:id", action: :destroy
end
Expose Rubric Assessment API endpoints CUD Test Plan. Use postman or curl to test the following endpoints Remember to change the: :course_id with the appropiate course_id :rubric_association_id with the appropiate rubric_association_id :id with the rubric_assessment_id POST 'courses/:course_id/rubric_associations/ :rubric_association_id/rubric_assessments' params example: { "rubric_assessment": { "user_id": "22", "assessment_type": "grading", "criterion__7226": { "points": "3", "comments": "", "save_comment": "0" } }, "graded_anonymously": "false" } PUT 'courses/:course_id/rubric_associations/ :rubric_association_id/rubric_assessments/:id' params example: { "rubric_assessment": { "user_id": "22", "assessment_type": "grading", "criterion__7226": { "points": "3", "comments": "", "save_comment": "0" } }, "graded_anonymously": "false" } DELETE 'courses/:course_id/rubric_associations/ :rubric_association_id/rubric_assessments/:id' refs: PFS-11756 Change-Id: Ib67898f2dec37c3438e1d8f5745c20f1c41113e0 Reviewed-on: https://gerrit.instructure.com/180683 Tested-by: Jenkins QA-Review: Aiona Rae Hernandez <ahernandez@instructure.com> QA-Review: Brian Watson <bwatson@instructure.com> Reviewed-by: Neil Gupta <ngupta@instructure.com> Reviewed-by: Colin Cromar <ccromar@instructure.com> Reviewed-by: Augusto Callejas <acallejas@instructure.com> Product-Review: Augusto Callejas <acallejas@instructure.com> (cherry picked from commit d17de50121f60104c136b0a1831db786b816231c) Reviewed-on: https://gerrit.instructure.com/183188 Product-Review: Neil Gupta <ngupta@instructure.com>
2019-02-06 06:34:04 +08:00
scope(controller: :rubric_assessment_api) do
post "courses/:course_id/rubric_associations/:rubric_association_id/rubric_assessments", controller: :rubric_assessments, action: :create
put "courses/:course_id/rubric_associations/:rubric_association_id/rubric_assessments/:id", controller: :rubric_assessments, action: :update
delete "courses/:course_id/rubric_associations/:rubric_association_id/rubric_assessments/:id", controller: :rubric_assessments, action: :destroy
end
scope(controller: "master_courses/master_templates") do
get "courses/:course_id/blueprint_templates/:template_id", action: :show
get "courses/:course_id/blueprint_templates/:template_id/associated_courses", action: :associated_courses, as: :course_blueprint_associated_courses
put "courses/:course_id/blueprint_templates/:template_id/update_associations", action: :update_associations
get "courses/:course_id/blueprint_templates/:template_id/unsynced_changes", action: :unsynced_changes, as: :course_blueprint_unsynced_changes
post "courses/:course_id/blueprint_templates/:template_id/migrations", action: :queue_migration
get "courses/:course_id/blueprint_templates/:template_id/migrations", action: :migrations_index, as: :course_blueprint_migrations
get "courses/:course_id/blueprint_templates/:template_id/migrations/:id", action: :migrations_show
get "courses/:course_id/blueprint_templates/:template_id/migrations/:id/details", action: :migration_details
put "courses/:course_id/blueprint_templates/:template_id/restrict_item", action: :restrict_item
get "courses/:course_id/blueprint_subscriptions", action: :subscriptions_index, as: :course_blueprint_subscriptions
get "courses/:course_id/blueprint_subscriptions/:subscription_id/migrations", action: :imports_index, as: :course_blueprint_imports
get "courses/:course_id/blueprint_subscriptions/:subscription_id/migrations/:id", action: :imports_show
get "courses/:course_id/blueprint_subscriptions/:subscription_id/migrations/:id/details", action: :import_details
end
scope(controller: :late_policy) do
get "courses/:id/late_policy", action: :show
post "courses/:id/late_policy", action: :create
patch "courses/:id/late_policy", action: :update
end
Planner API Closes FALCOR-183 Closes FALCOR-184 Closes FALCOR-255 Closes FALCOR-186 Closes FALCOR-187 Closes FALCOR-188 Closes FALCOR-189 Closes FALCOR-147 Closes FALCOR-148 Test Plan: * As a student in an account with the Student Planner feature flag enabled * In a course with multiple upcoming due assignments in the current and following weeks * Test that the following API endpoints provide you with the data described: get '/api/v1/planner/items' * Should return a list matching that of the todo list endpoint, while adding an additional key named `visible_in_planner` get '/api/v1/planner/overrides' * Should return a list of previously created PlannerOverrides get '/api/v1/planner/overrides/:override_id' * Should return the specific override for the passed in id put '/api/v1/planner/overrides/:override_id' * Should update an existing override's `visible` value to match what was passed in the request. No other values should be updated post '/api/v1/planner/overrides' * Should create a new PlannerOverride with the specified `plannable_type`, `plannable_id`, and `visible` values. `user_id` should match that of the user making the request delete '/api/v1/planner/overrides/:override_id' * Should set the PlannerOverride's `deleted_at` to when the request was made, as well as updating the `workflow_state` to `deleted` Change-Id: I03890a525f8201a8df1d2f1290cdcd549ba548d7 Reviewed-on: https://gerrit.instructure.com/107495 Tested-by: Jenkins Reviewed-by: Steven Burnett <sburnett@instructure.com> QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Dan Minkevitch <dan@instructure.com>
2017-05-11 12:40:45 +08:00
scope(controller: :planner) do
get "planner/items", action: :index, as: :planner_items
get "users/:user_id/planner/items", action: :index, as: :user_planner_items
end
Planner API Closes FALCOR-183 Closes FALCOR-184 Closes FALCOR-255 Closes FALCOR-186 Closes FALCOR-187 Closes FALCOR-188 Closes FALCOR-189 Closes FALCOR-147 Closes FALCOR-148 Test Plan: * As a student in an account with the Student Planner feature flag enabled * In a course with multiple upcoming due assignments in the current and following weeks * Test that the following API endpoints provide you with the data described: get '/api/v1/planner/items' * Should return a list matching that of the todo list endpoint, while adding an additional key named `visible_in_planner` get '/api/v1/planner/overrides' * Should return a list of previously created PlannerOverrides get '/api/v1/planner/overrides/:override_id' * Should return the specific override for the passed in id put '/api/v1/planner/overrides/:override_id' * Should update an existing override's `visible` value to match what was passed in the request. No other values should be updated post '/api/v1/planner/overrides' * Should create a new PlannerOverride with the specified `plannable_type`, `plannable_id`, and `visible` values. `user_id` should match that of the user making the request delete '/api/v1/planner/overrides/:override_id' * Should set the PlannerOverride's `deleted_at` to when the request was made, as well as updating the `workflow_state` to `deleted` Change-Id: I03890a525f8201a8df1d2f1290cdcd549ba548d7 Reviewed-on: https://gerrit.instructure.com/107495 Tested-by: Jenkins Reviewed-by: Steven Burnett <sburnett@instructure.com> QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Dan Minkevitch <dan@instructure.com>
2017-05-11 12:40:45 +08:00
scope(controller: :planner_overrides) do
get "planner/overrides", action: :index, as: :planner_overrides
get "planner/overrides/:id", action: :show
put "planner/overrides/:id", action: :update
Planner API Closes FALCOR-183 Closes FALCOR-184 Closes FALCOR-255 Closes FALCOR-186 Closes FALCOR-187 Closes FALCOR-188 Closes FALCOR-189 Closes FALCOR-147 Closes FALCOR-148 Test Plan: * As a student in an account with the Student Planner feature flag enabled * In a course with multiple upcoming due assignments in the current and following weeks * Test that the following API endpoints provide you with the data described: get '/api/v1/planner/items' * Should return a list matching that of the todo list endpoint, while adding an additional key named `visible_in_planner` get '/api/v1/planner/overrides' * Should return a list of previously created PlannerOverrides get '/api/v1/planner/overrides/:override_id' * Should return the specific override for the passed in id put '/api/v1/planner/overrides/:override_id' * Should update an existing override's `visible` value to match what was passed in the request. No other values should be updated post '/api/v1/planner/overrides' * Should create a new PlannerOverride with the specified `plannable_type`, `plannable_id`, and `visible` values. `user_id` should match that of the user making the request delete '/api/v1/planner/overrides/:override_id' * Should set the PlannerOverride's `deleted_at` to when the request was made, as well as updating the `workflow_state` to `deleted` Change-Id: I03890a525f8201a8df1d2f1290cdcd549ba548d7 Reviewed-on: https://gerrit.instructure.com/107495 Tested-by: Jenkins Reviewed-by: Steven Burnett <sburnett@instructure.com> QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Dan Minkevitch <dan@instructure.com>
2017-05-11 12:40:45 +08:00
post "planner/overrides", action: :create
delete "planner/overrides/:id", action: :destroy
Planner API Closes FALCOR-183 Closes FALCOR-184 Closes FALCOR-255 Closes FALCOR-186 Closes FALCOR-187 Closes FALCOR-188 Closes FALCOR-189 Closes FALCOR-147 Closes FALCOR-148 Test Plan: * As a student in an account with the Student Planner feature flag enabled * In a course with multiple upcoming due assignments in the current and following weeks * Test that the following API endpoints provide you with the data described: get '/api/v1/planner/items' * Should return a list matching that of the todo list endpoint, while adding an additional key named `visible_in_planner` get '/api/v1/planner/overrides' * Should return a list of previously created PlannerOverrides get '/api/v1/planner/overrides/:override_id' * Should return the specific override for the passed in id put '/api/v1/planner/overrides/:override_id' * Should update an existing override's `visible` value to match what was passed in the request. No other values should be updated post '/api/v1/planner/overrides' * Should create a new PlannerOverride with the specified `plannable_type`, `plannable_id`, and `visible` values. `user_id` should match that of the user making the request delete '/api/v1/planner/overrides/:override_id' * Should set the PlannerOverride's `deleted_at` to when the request was made, as well as updating the `workflow_state` to `deleted` Change-Id: I03890a525f8201a8df1d2f1290cdcd549ba548d7 Reviewed-on: https://gerrit.instructure.com/107495 Tested-by: Jenkins Reviewed-by: Steven Burnett <sburnett@instructure.com> QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Dan Minkevitch <dan@instructure.com>
2017-05-11 12:40:45 +08:00
end
scope(controller: :planner_notes) do
get "planner_notes", action: :index, as: :planner_notes
BookmarkedCollection for Planner API Closes FALCOR-325 Fixes FALCOR-361 Test Plan Date Range Testing: * With "Student Planner" enabled * As a student * Make a GET request to /api/v1/planner/items with ?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD&filter=new_activity * The response should only contain results with new activity between those time ranges (test with dates and dates with times) Pagination Testing: * With "Student Planner" enabled * As a student * Make a GET request to /api/v1/planner/items with some combination of start_date, end_date, and filter * Include a a `per_page` param * The response should only contain only `per_page` number of results * The response should contain a `Link` header with links to the current, next, and previous pages (you should see a URL with a `page=bookmark:[bunch of characters]`) * Copy the `page` param from the `Link` header for the next page of results * Make a request with the newly copied `page=bookmark:[stuff]` parameter added to the request * You should get the next page of results in the response * The previous and next URLs in the `Link` response header should return the previous and next page of results Regression Testing: * Full regression test of "New Student Planner" Change-Id: Ie6352aec71f5de3c60981aaeee65119cc43ed6f7 Reviewed-on: https://gerrit.instructure.com/114848 Reviewed-by: Steven Burnett <sburnett@instructure.com> Tested-by: Jenkins QA-Review: Deepeeca Soundarrajan <dsoundarrajan@instructure.com> Product-Review: Dan Minkevitch <dan@instructure.com>
2017-06-09 10:52:02 +08:00
get "planner_notes/:id", action: :show, as: :planner_notes_show
put "planner_notes/:id", action: :update
post "planner_notes", action: :create
delete "planner_notes/:id", action: :destroy
end
scope(controller: :content_shares) do
post "users/:user_id/content_shares", action: :create
get "users/:user_id/content_shares/sent", action: :index, defaults: { list: "sent" }, as: :user_sent_content_shares
get "users/:user_id/content_shares/received", action: :index, defaults: { list: "received" }, as: :user_received_content_shares
get "users/:user_id/content_shares/unread_count", action: :unread_count
get "users/:user_id/content_shares/:id", action: :show
delete "users/:user_id/content_shares/:id", action: :destroy
post "users/:user_id/content_shares/:id/add_users", action: :add_users
put "users/:user_id/content_shares/:id", action: :update
end
scope(controller: :csp_settings) do
%w[course account].each do |context|
get "#{context.pluralize}/:#{context}_id/csp_settings", action: :get_csp_settings
put "#{context.pluralize}/:#{context}_id/csp_settings", action: :set_csp_setting
end
put "accounts/:account_id/csp_settings/lock", action: :set_csp_lock
post "accounts/:account_id/csp_settings/domains", action: :add_domain
post "accounts/:account_id/csp_settings/domains/batch_create", action: :add_multiple_domains
delete "accounts/:account_id/csp_settings/domains", action: :remove_domain
get "accounts/:account_id/csp_log", action: :csp_log
end
Update canvas media_objects api for the RCE closes LA-68 test plan: - have a user with media objects in a couple courses - have another user with a media object - GET /api/v1/media_objects > expect all the objects for the logged in user to be returned, including the sources and tracks data - query /api/v1/media_objects?&exclude[]=sources&exclude[]=tracks > expect all the objects for the logged in user to be returned, excluding the sources and tracks data (it should be _much_ faster too) - query /api/v1/courses/:course_id/media_objects?exclude[]=sources&exclude[]=tracks > expect only the media objects for the logged in user, in the given course to be returned > expect /doc/api/media_objects.html to properly document the api - query /api/v1/courses/:a_nonexistent_course_id/ > expect a 404 sorting - have some media objects with user_entered_title, some with only title. - GET /api/v1/media_objects&sort=title&order=desc > expect the results to be sorted by title descending - GET /api/v1/media_objects&sort=create_at&order=asc > expect the results to be sorted by created_at ascending - you can try other sorts updating* - PUT /api/v1/media_objects/:media_obj_id?user_entered_title=new+title - if :media_obj_id belongs to the current user > expect status=200 and the object to be returned - if :media_obj_id doesn't exist > expect status=401 - if :media_obj_id belongs to another user > expect status=401 - if user_entered_title was empty > expect status=400 - if user_entered_title was missing > expect status=400 - if user wasn't logged in > expect either a 422 (cuz the CSRF header is funky) or a 302 (redirect to the login page) - after updating - GET /media_objects/:id/info > expect the object with the new title returned - GET /api/v1/media_objects?exclude[]=sources&exclude[]=tracks > expect the object to have its new title *To PUT, the request must include a X-CSRF-Token header. The value can be found in documet.cookie on a canvas page (after running decodeURIComponent on it) Change-Id: I496b8a36f1d177054736dadb6695a25bb7aee217 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/215292 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Tested-by: Jenkins Product-Review: Ed Schiebel <eschiebel@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com>
2019-10-31 02:12:24 +08:00
scope(controller: :media_objects) do
put "media_objects/:media_object_id", action: "update_media_object", as: :update_media_object
post "media_objects", action: "create_media_object", as: :create_media_object
put "media_attachments/:attachment_id", action: "update_media_object", as: :update_media_attachment
post "media_attachments", action: "create_media_object", as: :create_media_attachment
Update canvas media_objects api for the RCE closes LA-68 test plan: - have a user with media objects in a couple courses - have another user with a media object - GET /api/v1/media_objects > expect all the objects for the logged in user to be returned, including the sources and tracks data - query /api/v1/media_objects?&exclude[]=sources&exclude[]=tracks > expect all the objects for the logged in user to be returned, excluding the sources and tracks data (it should be _much_ faster too) - query /api/v1/courses/:course_id/media_objects?exclude[]=sources&exclude[]=tracks > expect only the media objects for the logged in user, in the given course to be returned > expect /doc/api/media_objects.html to properly document the api - query /api/v1/courses/:a_nonexistent_course_id/ > expect a 404 sorting - have some media objects with user_entered_title, some with only title. - GET /api/v1/media_objects&sort=title&order=desc > expect the results to be sorted by title descending - GET /api/v1/media_objects&sort=create_at&order=asc > expect the results to be sorted by created_at ascending - you can try other sorts updating* - PUT /api/v1/media_objects/:media_obj_id?user_entered_title=new+title - if :media_obj_id belongs to the current user > expect status=200 and the object to be returned - if :media_obj_id doesn't exist > expect status=401 - if :media_obj_id belongs to another user > expect status=401 - if user_entered_title was empty > expect status=400 - if user_entered_title was missing > expect status=400 - if user wasn't logged in > expect either a 422 (cuz the CSRF header is funky) or a 302 (redirect to the login page) - after updating - GET /media_objects/:id/info > expect the object with the new title returned - GET /api/v1/media_objects?exclude[]=sources&exclude[]=tracks > expect the object to have its new title *To PUT, the request must include a X-CSRF-Token header. The value can be found in documet.cookie on a canvas page (after running decodeURIComponent on it) Change-Id: I496b8a36f1d177054736dadb6695a25bb7aee217 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/215292 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Tested-by: Jenkins Product-Review: Ed Schiebel <eschiebel@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com>
2019-10-31 02:12:24 +08:00
end
scope(controller: :media_tracks) do
get "media_objects/:media_object_id/media_tracks", action: "index", as: :list_media_tracks
put "media_objects/:media_object_id/media_tracks", action: "update", as: :update_media_tracks
get "media_attachments/:attachment_id/media_tracks", action: "index", as: :list_media_attachment_tracks
put "media_attachments/:attachment_id/media_tracks", action: "update", as: :update_media_attachment_tracks
end
scope(controller: "conditional_release/rules") do
# TODO: can rearrange so assignment is in path if desired once we're no longer maintaining backwards compat
get "courses/:course_id/mastery_paths/rules", action: "index"
get "courses/:course_id/mastery_paths/rules/:id", action: "show"
post "courses/:course_id/mastery_paths/rules", action: "create"
put "courses/:course_id/mastery_paths/rules/:id", action: "update"
delete "courses/:course_id/mastery_paths/rules/:id", action: "destroy"
end
scope(controller: "conditional_release/stats") do
# TODO: can rearrange so assignment is in path if desired once we're no longer maintaining backwards compat
get "courses/:course_id/mastery_paths/stats/students_per_range", action: "students_per_range"
get "courses/:course_id/mastery_paths/stats/student_details", action: "student_details"
end
scope(controller: :history) do
get "users/:user_id/history", action: "index", as: :user_history
end
Add bulk override grade update endpoint closes EVAL-1330 flag=none Test plan: - Have a course with final grade override enabled and some students and grading periods - Take note of the IDs of one or more students - Make a PUT request to the API endpoint: - /api/v1/courses/<courseid>/update_final_grade_overrides - With a JSON request body like the following (you can add additional records if you feel like it): { "grading_period_id": "1", "override_scores": [ {"override_score":"60", "student_id":"7"}, {"override_score":"61", "student_id":"125"} ] } - (Replace the grading period and student IDs above with values applicable to you, or remove the grading_period_id parameter entirely apply the change to the course override score) - Check that the request returns a Progress object (which should finish in short order) and that override grades in the gradebook are updated to the values you set - Check that changing override scores in this way populates gradebook history - Check that the following return unauthorized errors: - Accessing the endpoint for a course without final grade override enabled - Accessing the endpoint for a concluded course - Accessing the endpoint as a user who does hnot have permission to manage grades - Smoke test setting override grades manually from Gradebook - Make sure it still works and populates gradebook history as before Change-Id: I78d19d899485b40c6c812867a89b8352c215955f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/253921 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Gary Mei <gmei@instructure.com> Reviewed-by: Syed Hussain <shussain@instructure.com> QA-Review: Syed Hussain <shussain@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com>
2020-12-01 04:45:32 +08:00
scope(controller: :gradebooks) do
put "courses/:course_id/update_final_grade_overrides", action: "update_final_grade_overrides"
Create endpoint for "apply score to ungraded" closes EVAL-2037 flag=apply_score_to_ungraded Test plan: - Have a course whose account has the "Apply Score to Ungraded" feature enabled - Have some assignments and students, and make sure some of the submissions are ungraded - As an instructor in said course, make a PUT request to the endpoint: /api/v1/courses/<id>/apply_score_to_ungraded_submissions with a request that has a body like: { "percent": "50.0" } - The request should return a Progress object - It should also start a job that applies a score of 50% to all ungraded submissions in the course, one by one - Check that the newly-applied grades are reflected in gradebook and gradebook history (note that the process may take some time) Smoke-test the request with some additional parameters, such as: - "excused": "true" (in place of the "percent" parameter) - This should excuse any ungraded submissions rather than grading them - "assignment_group_id": <an assignment group ID> - This should only apply grades to ungraded submissions for assignments within the specified assignment group - "only_apply_to_past_due": "true" - This should only apply grades to submissions past their due date Change-Id: Ib9ce8824ad8794f1dc41d40d65bc6891f77a0541 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/278613 Reviewed-by: Eduardo Escobar <eduardo.escobar@instructure.com> Reviewed-by: Syed Hussain <shussain@instructure.com> Reviewed-by: Kai Bjorkman <kbjorkman@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com> QA-Review: Kai Bjorkman <kbjorkman@instructure.com>
2021-11-18 03:33:16 +08:00
put "courses/:course_id/apply_score_to_ungraded_submissions", action: "apply_score_to_ungraded_submissions"
Add bulk override grade update endpoint closes EVAL-1330 flag=none Test plan: - Have a course with final grade override enabled and some students and grading periods - Take note of the IDs of one or more students - Make a PUT request to the API endpoint: - /api/v1/courses/<courseid>/update_final_grade_overrides - With a JSON request body like the following (you can add additional records if you feel like it): { "grading_period_id": "1", "override_scores": [ {"override_score":"60", "student_id":"7"}, {"override_score":"61", "student_id":"125"} ] } - (Replace the grading period and student IDs above with values applicable to you, or remove the grading_period_id parameter entirely apply the change to the course override score) - Check that the request returns a Progress object (which should finish in short order) and that override grades in the gradebook are updated to the values you set - Check that changing override scores in this way populates gradebook history - Check that the following return unauthorized errors: - Accessing the endpoint for a course without final grade override enabled - Accessing the endpoint for a concluded course - Accessing the endpoint as a user who does hnot have permission to manage grades - Smoke test setting override grades manually from Gradebook - Make sure it still works and populates gradebook history as before Change-Id: I78d19d899485b40c6c812867a89b8352c215955f Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/253921 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Gary Mei <gmei@instructure.com> Reviewed-by: Syed Hussain <shussain@instructure.com> QA-Review: Syed Hussain <shussain@instructure.com> Product-Review: Syed Hussain <shussain@instructure.com>
2020-12-01 04:45:32 +08:00
end
scope(controller: :course_paces) do
post "courses/:course_id/course_pacing", action: :create
get "courses/:course_id/course_pacing/new", action: :new
get "courses/:course_id/course_pacing/:id", action: :api_show
put "courses/:course_id/course_pacing/:id", action: :update
delete "courses/:course_id/course_pacing/:id", action: :destroy
post "courses/:course_id/course_pacing/:id/publish", action: :publish
post "courses/:course_id/course_pacing/compress_dates", action: :compress_dates
end
2022-02-16 00:10:48 +08:00
scope(controller: :blackout_dates) do
get "courses/:course_id/blackout_dates", action: :index
get "accounts/:account_id/blackout_dates", action: :index
post "courses/:course_id/blackout_dates", action: :create
post "accounts/:account_id/blackout_dates", action: :create
get "courses/:course_id/blackout_dates/new", action: :new
get "accounts/:account_id/blackout_dates/new", action: :new
get "courses/:course_id/blackout_dates/:id", action: :show
get "accounts/:account_id/blackout_dates/:id", action: :show
put "courses/:course_id/blackout_dates/:id", action: :update
put "accounts/:account_id/blackout_dates/:id", action: :update
delete "courses/:course_id/blackout_dates/:id", action: :destroy
delete "accounts/:account_id/blackout_dates/:id", action: :destroy
Save updated blackout dates to the backend refs LS-3029 flag=course_paces flag=course_paces_blackout_dates This commit saves pending blackout date changes when the user clicks Publish. It does not format the pending blackout date chnages in the tray test plan: - with the site admin flag "course_paces_blackout_dates" enabled (it is by default in dev and ci) - in a course with paces enabled, a module with a few assignments - click Settings -> Blackout Dates and create some blackout dates between your start date and the last assignment's due date > expect the assignment due dates to adjust to skip over the blackout dates > expect the "Unpublished changes" notice to include 1 for updated blackout dates - click cancel > expect the blackout dates to revert - add them back - click publish > expect to see a PUT to the blackout_dates api followed by a PUT to the course_pace/:id api > expect everything in the UI to be disabled while all this is going on > expect the notice to tell you blackout dates are being saved followed by the pace is being published, followed by "All changes published" - refresh the page - open settings -> blackout dates > expect the dates to be what you saved before - open the blackout dates modal, delete one and save - click Cancel to cancel unpublished chnanges - open the blackout daes modal > expect the deleted one to be listed - disable the flag - make sure everything still works but there is no blackout dates UI in settings and Publish still works Change-Id: Icad39d7a6f2806effe38be8627f08b234625da30 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/288311 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Eric Saupe <eric.saupe@instructure.com> QA-Review: Eric Saupe <eric.saupe@instructure.com> Product-Review: Ed Schiebel <eschiebel@instructure.com>
2022-03-29 06:10:41 +08:00
put "courses/:course_id/blackout_dates", action: :bulk_update
2022-02-16 00:10:48 +08:00
end
scope(controller: :eportfolios_api) do
get "users/:user_id/eportfolios", action: :index, as: :eportfolios
get "eportfolios/:id", action: :show
delete "eportfolios/:id", action: :delete
get "eportfolios/:eportfolio_id/pages", action: :pages, as: :eportfolio_pages
put "eportfolios/:eportfolio_id/moderate", action: :moderate
put "users/:user_id/eportfolios", action: :moderate_all
put "eportfolios/:eportfolio_id/restore", action: :restore
end
scope(controller: "course_pacing/section_paces_api") do
get "courses/:course_id/sections/:course_section_id/pace", action: :show, as: :section_pace
post "courses/:course_id/sections/:course_section_id/paces", action: :create, as: :new_section_pace
patch "courses/:course_id/sections/:course_section_id/pace", action: :update, as: :patch_section_pace
delete "courses/:course_id/sections/:course_section_id/pace", action: :delete, as: :delete_section_pace
end
scope(controller: "course_pacing/student_enrollment_paces_api") do
get "courses/:course_id/student_enrollments/:student_enrollment_id/pace", action: :show, as: :student_enrollment_pace
post "courses/:course_id/student_enrollments/:student_enrollment_id/paces", action: :create, as: :new_student_enrollment_pace
patch "courses/:course_id/student_enrollments/:student_enrollment_id/pace", action: :update, as: :patch_student_enrollment_pace
delete "courses/:course_id/student_enrollments/:student_enrollment_id/pace", action: :delete, as: :delete_student_enrollment_pace
end
scope(controller: "course_pacing/pace_contexts_api") do
get "courses/:course_id/pace_contexts", action: :index, as: :pace_contexts
end
scope(controller: "smart_search") do
get "courses/:course_id/smartsearch", action: :search, as: :course_smart_search_query
get "courses/:course_id/smartsearch/log", action: :log
get "courses/:course_id/smartsearch/index_status", action: :index_status
# TODO: add account level search
end
scope(controller: "user_notes") do
put "users/:user_id/user_notes/suppress_deprecation_notice", action: :suppress_deprecation_notice
end
2011-02-01 09:57:29 +08:00
end
Update canvas media_objects api for the RCE closes LA-68 test plan: - have a user with media objects in a couple courses - have another user with a media object - GET /api/v1/media_objects > expect all the objects for the logged in user to be returned, including the sources and tracks data - query /api/v1/media_objects?&exclude[]=sources&exclude[]=tracks > expect all the objects for the logged in user to be returned, excluding the sources and tracks data (it should be _much_ faster too) - query /api/v1/courses/:course_id/media_objects?exclude[]=sources&exclude[]=tracks > expect only the media objects for the logged in user, in the given course to be returned > expect /doc/api/media_objects.html to properly document the api - query /api/v1/courses/:a_nonexistent_course_id/ > expect a 404 sorting - have some media objects with user_entered_title, some with only title. - GET /api/v1/media_objects&sort=title&order=desc > expect the results to be sorted by title descending - GET /api/v1/media_objects&sort=create_at&order=asc > expect the results to be sorted by created_at ascending - you can try other sorts updating* - PUT /api/v1/media_objects/:media_obj_id?user_entered_title=new+title - if :media_obj_id belongs to the current user > expect status=200 and the object to be returned - if :media_obj_id doesn't exist > expect status=401 - if :media_obj_id belongs to another user > expect status=401 - if user_entered_title was empty > expect status=400 - if user_entered_title was missing > expect status=400 - if user wasn't logged in > expect either a 422 (cuz the CSRF header is funky) or a 302 (redirect to the login page) - after updating - GET /media_objects/:id/info > expect the object with the new title returned - GET /api/v1/media_objects?exclude[]=sources&exclude[]=tracks > expect the object to have its new title *To PUT, the request must include a X-CSRF-Token header. The value can be found in documet.cookie on a canvas page (after running decodeURIComponent on it) Change-Id: I496b8a36f1d177054736dadb6695a25bb7aee217 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/215292 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Tested-by: Jenkins Product-Review: Ed Schiebel <eschiebel@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com>
2019-10-31 02:12:24 +08:00
# this is not a "normal" api endpoint in the sense that it is not documented or
Expose delayed jobs as an API route This patch exposes delayed jobs data as an API route, which makes it accessible using a bearer token. Currently, a token is not accepted as valid authentication, and an Unauthorized error is returned to the client. Test plan: - create a user in the Site Admin account and grant it admin rights to Site Admin - create a user in the Site Admin account (or any other account) but do not grant it admin rights to Site Admin - create some delayed jobs, failed and otherwise - test the following routes: -`GET /api/v1/jobs?only=jobs&flavor=[failed|future|current|waiting]`: should return list of jobs for specified flavor in JSON -`GET /api/v1/jobs/:id`: should return a specific non-failed job -`GET /api/v1/jobs/:id`: should return a specific failed job - `POST /api/v1/jobs/batch_update` with body `update_action=destroy&job_ids[]=$id1&job_ids[]=$id2`: (replacing $id1 and $id2 with the IDs of real non-failed jobs) should return a success message with count of destroyed jobs. - `POST /api/v1/jobs/batch_update` with body `update_action=destroy&job_ids[]=$id1&job_ids[]=$id2&flavor=failed`: (replacing $id1 and $id2 with the IDs of real failed jobs) will fail pending instructure/canvas-jobs#2 (with that pull, it will return a success message with count of destroyed jobs). - `POST /api/v1/jobs/batch_update` with body `update_action=destroy&flavor=future`: should return a success message with count of destroyed jobs - `POST /api/v1/jobs/batch_update` with body `update_action=hold&flavor=future`: should return an error report (can't hold failed jobs). When testing the routes, using the second user created (without Site Admin rights) should throw an Unauthorized error. Using a developer key should throw an Invalid Token error.
2015-10-10 06:43:00 +08:00
# generally available to hosted customers. it also does not respect the normal
# pagination options; however, jobs_controller already accepts `limit` and `offset`
# paramaters and defines a sane default limit
ApiRouteSet::V1.draw(self) do
scope(controller: :jobs) do
get "jobs", action: :index
get "jobs/:id", action: :show
post "jobs/batch_update", action: :batch_update
end
# jobs_v2 actually does do regular pagination, but the comments above
# otherwise still apply
scope(controller: :jobs_v2) do
get "jobs2/:bucket/by_:group/search", action: :search
get "jobs2/:bucket/by_:group", action: :grouped_info, as: :jobs_grouped_info
get "jobs2/:bucket", action: :list, as: :jobs_list, constraints: { bucket: /running|queued|future|failed/ }
get "jobs2/clusters", action: :clusters, as: :job_clusters
get "jobs2/:id", action: :lookup, constraints: { id: /\d+/ }
post "jobs2/:id/requeue", action: :requeue
put "jobs2/manage", action: :manage
API to unstuck strands/singletons w/o next_in_strand test plan: - queue some jobs in a new strand while explicitly setting next_in_strand to false, e.g. 5.times { delay(strand: 'sad', next_in_strand: false).sleep(1) } - also queue a singleton that way: delay(singleton: 'stuck', next_in_strand: false).sleep(1) - verify the strand and singleton are orphaned in the jobs_v2 user interface (strand / singleton tabs) - do PUT /api/v1/jobs2/unstuck?strand=X, refresh the page, and verify that the strand is unstuck - if max_concurrent is > 1 on a strand, the PUT should unleash the right number of jobs and return the count - do PUT /api/v1/jobs2/unstuck?singleton=Y, refresh the page, and verify the singleton is unstuck - ensure the unstuck endpoint returns 0 when called on a strand or singleton that isn't stuck - ensure the unstuck endpoint returns status 404 when called on a strand or singleton that doesn't exist - run PUT /api/v1/jobs2/unstuck without specifying a singleton or strand, and it should queue a job that unstucks all the stucks. it returns progress information you can query using the Progress API (which will unfortunately go straight from 0 to 100% unless you are in an environment with multiple jobs shards) - sanity check increasing strand parallelism (since the `unleash_more_jobs` functionality was moved into the gem) flag=jobs_v2 refs DE-1314 Change-Id: I687163f2d104aa5ef9cd1621d7081cc38343361e Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/300662 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Aaron Ogata <aogata@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Jeremy Stanley <jeremy@instructure.com>
2022-09-10 00:09:13 +08:00
put "jobs2/unstuck", action: :unstuck
get "jobs2/throttle/check", action: :throttle_check
put "jobs2/throttle", action: :throttle
get "jobs2/stuck/strands", action: :stuck_strands, as: :jobs_stuck_strands
get "jobs2/stuck/singletons", action: :stuck_singletons, as: :jobs_stuck_singletons
end
end
Expose delayed jobs as an API route This patch exposes delayed jobs data as an API route, which makes it accessible using a bearer token. Currently, a token is not accepted as valid authentication, and an Unauthorized error is returned to the client. Test plan: - create a user in the Site Admin account and grant it admin rights to Site Admin - create a user in the Site Admin account (or any other account) but do not grant it admin rights to Site Admin - create some delayed jobs, failed and otherwise - test the following routes: -`GET /api/v1/jobs?only=jobs&flavor=[failed|future|current|waiting]`: should return list of jobs for specified flavor in JSON -`GET /api/v1/jobs/:id`: should return a specific non-failed job -`GET /api/v1/jobs/:id`: should return a specific failed job - `POST /api/v1/jobs/batch_update` with body `update_action=destroy&job_ids[]=$id1&job_ids[]=$id2`: (replacing $id1 and $id2 with the IDs of real non-failed jobs) should return a success message with count of destroyed jobs. - `POST /api/v1/jobs/batch_update` with body `update_action=destroy&job_ids[]=$id1&job_ids[]=$id2&flavor=failed`: (replacing $id1 and $id2 with the IDs of real failed jobs) will fail pending instructure/canvas-jobs#2 (with that pull, it will return a success message with count of destroyed jobs). - `POST /api/v1/jobs/batch_update` with body `update_action=destroy&flavor=future`: should return a success message with count of destroyed jobs - `POST /api/v1/jobs/batch_update` with body `update_action=hold&flavor=future`: should return an error report (can't hold failed jobs). When testing the routes, using the second user created (without Site Admin rights) should throw an Unauthorized error. Using a developer key should throw an Invalid Token error.
2015-10-10 06:43:00 +08:00
# this is not a "normal" api endpoint in the sense that it is not documented
# or called directly, it's used as the redirect in the file upload process
# for local files. it also doesn't use the normal oauth authentication
# system, so we can't put it in the api uri namespace.
post "files_api" => "files#api_create", :as => :api_v1_files_create
get "login/oauth2/auth" => "oauth2_provider#auth", :as => :oauth2_auth
post "login/oauth2/token" => "oauth2_provider#token", :as => :oauth2_token
get "login/oauth2/confirm" => "oauth2_provider#confirm", :as => :oauth2_auth_confirm
post "login/oauth2/accept" => "oauth2_provider#accept", :as => :oauth2_auth_accept
get "login/oauth2/deny" => "oauth2_provider#deny", :as => :oauth2_auth_deny
delete "login/oauth2/token" => "oauth2_provider#destroy", :as => :oauth2_logout
Add asymmetric encryption for service tokens refs FOO-2410 test plan: - in dynamic_settings.yml, add the following block: ``` store: canvas: services-jwt: # these are all the same JWK but with different kid # to generate a new key, run the following in a Canvas console: # # key = OpenSSL::PKey::RSA.generate(2048) # key.public_key.to_jwk(kid: Time.now.utc.iso8601).to_json jwk-past.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-05-18T22:33:20Z_a\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" jwk-present.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-06-18T22:33:20Z_b\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" jwk-future.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-07-18T22:33:20Z_c\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" ``` - Ensure /internal/services/jwks loads correctly - In console, ensure `CanvasSecurity::ServicesJwt.decrypt(Base64.decode64(CanvasSecurity::ServicesJwt.for_user('localhost', User.first)))` and `CanvasSecurity::ServicesJwt.decrypt(Base64.decode64(CanvasSecurity::ServicesJwt.for_user('localhost', User.first, symmetric: true)))` both work and produce sensible looking output Change-Id: I13c6c35cc92ed12d03bf97e89e590614e11c6d47 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275160 QA-Review: August Thornton <august@instructure.com> Product-Review: August Thornton <august@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Reviewed-by: Evan Battaglia <ebattaglia@instructure.com>
2021-10-05 03:20:31 +08:00
get "login/oauth2/jwks" => "security#jwks", :as => :oauth2_jwks
add postMessage forwarder for LTI platform storage why: * the LTI platform storage requires for security purposes that get/put_data requests are sent to the OIDC auth origin (eg canvas.docker or canvas.instructure.com), _not_ the current canvas domain * this new route will redirect to the right OIDC auth origin and listen for postMessages from tools, and forward them to the main Canvas window for proper processing * as well as forward response messages back to the sender closes INTEROP-7583 flag=none test plan: * have multiple domains to access canvas locally (eg shard2.canvas.docker etc) * in config/dynamic_settings.yml, set development.config.canvas.canvas.lti_post_message_forwarding_domain to "canvas.docker" * add this line to ui/features/post_message_forwarding/index.ts on line 23: `console.log({PARENT_DOMAIN})` * in your browser, go to your other domain, like "shard2.canvas.docker/post_message_forwarding" * that should redirect to "canvas.docker/post_message_forwarding" and include a token in the url * you should see `{PARENT_DOMAIN: "shard2.canvas.docker"}` in your browser console (or whatever your other domain is) * further testing of the forwarding functionality is in a later commit where this forwarder is added to canvas proper Change-Id: I3bd3572a719b618ccd4e33a57a85cea8edfce9d3 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/298103 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Mark Starkman <mark.starkman@instructure.com> Product-Review: Evan Battaglia <ebattaglia@instructure.com> Reviewed-by: Mark Starkman <mark.starkman@instructure.com> Reviewed-by: Evan Battaglia <ebattaglia@instructure.com> QA-Review: Evan Battaglia <ebattaglia@instructure.com>
2022-08-05 04:50:19 +08:00
get "post_message_forwarding", controller: "lti/platform_storage", action: :post_message_forwarding, as: :lti_post_message_forwarding
Provide Default Icon for editor_button placement Tools with the editor_button placement now have the right to remain silent as to an icon_url. Tools have the right to an icon; if they cannot afford an icon, one will be appointed for them. closes INTEROP-8426 flag=allow_lti_tools_editor_button_placement_without_icon Test plan: - Ensure the feature flag is on (default in dev) - Create LTI tools with no icon_url at the top level or in the editor button placement. You can try some of the following for the name of the tool (or 'title' in LTI 1.3). (Or you can test some of these out directly with the /lti/tool_default_icon endpoint, with the name parameter) - titles that start with some punctuation/whitespace - titles which are all punctuation/whitespace - titles with non-ASCII characters, e.g. ė, अ, 好, or 👍 - at least one simple title starting with a letter - Make at least one of the apps a favorite in the RCE (slider button in the apps list in the course/account settings) - Make sure the new default icons appear in all three locatons: - in the RCE favorite location - RCE dropdown - RCE "All Apps" listing (accessed from the dropdown) - Check that the default icons use the first number or letter-like (alphabetic, Chinese character, etc.) character in the tool editor button name, capitalized if applicable - Optional: Go to /lti/tool_default_icon?id=123&name=abc in Chrome, inspect element on the text, go to "Computed" and at the bottom "Rendered Fonts", and make sure "Inter Black" was rendered. - Optional: Install the same LTI 1.3 tool with no icon_url multiple times in one context and make sure both copies have identical icons. - rune 'rake doc:api' and check that the docs at doc/api/file.editor_button_placement.html have been updated to reflect the new icon_url behavior. - Turn the feature flag off - Edit an LTI 1.3 developer key 9that has at least one installation) to have an editor_button placement but not have any icon_url or canvas_icon_class in the editor_button placement configuration or top level configuration. - Run jobs and check that tool installations do not have an editor_button placement. Change-Id: I25f83c0995347ab0df887c844139ee74b814a571 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/340408 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Paul Gray <paul.gray@instructure.com> QA-Review: Paul Gray <paul.gray@instructure.com> Product-Review: Evan Battaglia <ebattaglia@instructure.com>
2024-02-13 17:06:09 +08:00
get "lti/tool_default_icon" => "lti/tool_default_icon#show"
ApiRouteSet.draw(self, "/api/lti/v1") do
post "tools/:tool_id/grade_passback", controller: :lti_api, action: :grade_passback, as: "lti_grade_passback_api"
post "tools/:tool_id/ext_grade_passback", controller: :lti_api, action: :legacy_grade_passback, as: "blti_legacy_grade_passback_api"
post "xapi/:token", controller: :lti_api, action: :xapi_service, as: "lti_xapi"
post "caliper/:token", controller: :lti_api, action: :caliper_service, as: "lti_caliper"
post "logout_service/:token", controller: :lti_api, action: :logout_service, as: "lti_logout_service"
post "turnitin/outcomes_placement/:tool_id", controller: :lti_api, action: :turnitin_outcomes_placement, as: "lti_turnitin_outcomes_placement"
end
ApiRouteSet.draw(self, "/api/lti") do
scope(controller: "lti/tool_configurations_api") do
put "developer_keys/:developer_key_id/tool_configuration", action: :update
post "accounts/:account_id/developer_keys/tool_configuration", action: :create
delete "developer_keys/:developer_key_id/tool_configuration", action: :destroy
%w[account course].each do |context|
get "#{context}s/:#{context}_id/developer_keys/:developer_key_id/tool_configuration", action: :show, as: "#{context}_show_tool_configuration"
end
end
LTI2 API webhook subscription service Fixes: PLAT-2129 PLAT-2126 Test Plan: - Verify you can create and retrieve a TCP with the new subscription service and capabilities. - Install an LTI2 tool using the split secret capability. The tool's security contract should use the new webhook service. Example security contract: "tp_half_shared_secret"=> "873f5...", "tool_service"=> [{"@type"=>"RestServiceProfile", "service"=>"vnd.Canvas.webhooksSubscription", "action"=>["GET", "POST"]}]} - Do a POST request to /api/lti/subscriptions with the following body: { "subscription":{ "EventTypes":[ "submission_created" ], "ContextType":"course", "ContextId":<valid course id here>, "Format":"live-event", "TransportType":"sqs", "TransportMetadata":{ "Url":"http://sqs.docker" } } } - Verify a 401 is returned - Using https://docs.google.com/document/d /12x6Peif-I-0zvl2uMv2JVbQdZumGGqMtspWKYTqlL9o/edit attempt to create each subscription type (in bold) and verify 401s are returned in each case. - Using the same document, verify that adding one of the capabilities listed under a subscription types allows you to create the subscription - Verify that using the vnd.instructure.webhooks.root_account.all capability allows you to create any subscription. - Install an LTI2 tool in a course - Attempt to create a subscription in another course and verify a 401 is given. Change-Id: I322e4bb2c49209afdc6f0a3c3a8b5c73e339996e Reviewed-on: https://gerrit.instructure.com/102272 Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2017-02-14 23:55:06 +08:00
scope(controller: "lti/subscriptions_api") do
post "subscriptions", action: :create
delete "subscriptions/:id", action: :destroy
get "subscriptions/:id", action: :show
put "subscriptions/:id", action: :update
get "subscriptions", action: :index
LTI2 API webhook subscription service Fixes: PLAT-2129 PLAT-2126 Test Plan: - Verify you can create and retrieve a TCP with the new subscription service and capabilities. - Install an LTI2 tool using the split secret capability. The tool's security contract should use the new webhook service. Example security contract: "tp_half_shared_secret"=> "873f5...", "tool_service"=> [{"@type"=>"RestServiceProfile", "service"=>"vnd.Canvas.webhooksSubscription", "action"=>["GET", "POST"]}]} - Do a POST request to /api/lti/subscriptions with the following body: { "subscription":{ "EventTypes":[ "submission_created" ], "ContextType":"course", "ContextId":<valid course id here>, "Format":"live-event", "TransportType":"sqs", "TransportMetadata":{ "Url":"http://sqs.docker" } } } - Verify a 401 is returned - Using https://docs.google.com/document/d /12x6Peif-I-0zvl2uMv2JVbQdZumGGqMtspWKYTqlL9o/edit attempt to create each subscription type (in bold) and verify 401s are returned in each case. - Using the same document, verify that adding one of the capabilities listed under a subscription types allows you to create the subscription - Verify that using the vnd.instructure.webhooks.root_account.all capability allows you to create any subscription. - Install an LTI2 tool in a course - Attempt to create a subscription in another course and verify a 401 is given. Change-Id: I322e4bb2c49209afdc6f0a3c3a8b5c73e339996e Reviewed-on: https://gerrit.instructure.com/102272 Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2017-02-14 23:55:06 +08:00
end
scope(controller: "lti/users_api") do
get "users/:id", action: :show
get "groups/:group_id/users", action: :group_index, as: "lti_user_group_index"
end
scope(controller: "lti/plagiarism_assignments_api") do
get "assignments/:assignment_id", action: :show
end
scope(controller: "lti/ims/authentication") do
post "authorize_redirect", action: :authorize_redirect
get "authorize_redirect", action: :authorize_redirect, as: "lti_authorize_redirect"
get "authorize", action: :authorize, as: :lti_1_3_authorization
end
2015-06-26 03:35:25 +08:00
%w[course account].each do |context|
prefix = "#{context}s/:#{context}_id"
post "#{prefix}/authorize", controller: "lti/ims/authorization", action: :authorize, as: "#{context}_lti_oauth2_authorize"
get "#{prefix}/tool_consumer_profile(/:tool_consumer_profile_id)",
controller: "lti/ims/tool_consumer_profile",
action: "show",
as: "#{context}_tool_consumer_profile"
post "#{prefix}/tool_proxy",
controller: "lti/ims/tool_proxy",
action: :re_reg,
as: "re_reg_#{context}_lti_tool_proxy",
constraints: Lti::ReRegConstraint.new
post "#{prefix}/tool_proxy",
controller: "lti/ims/tool_proxy",
action: :create,
as: "create_#{context}_lti_tool_proxy"
get "#{prefix}/jwt_token", controller: "external_tools", action: :jwt_token
get "tool_proxy/:tool_proxy_guid/#{prefix}/tool_setting", controller: "lti/ims/tool_setting", action: :show, as: "show_#{context}_tool_setting"
get "tool_proxy/:tool_proxy_guid/#{prefix}/resource_link_id/:resource_link_id/tool_setting", controller: "lti/ims/tool_setting", action: :show, as: "show_#{context}_resource_link_id_tool_setting"
put "tool_proxy/:tool_proxy_guid/#{prefix}/tool_setting", controller: "lti/ims/tool_setting", action: :update, as: "update_#{context}_tool_setting"
put "tool_proxy/:tool_proxy_guid/#{prefix}/resource_link_id/:resource_link_id/tool_setting", controller: "lti/ims/tool_setting", action: :update, as: "update_#{context}_update_resource_link_id_tool_setting"
end
# Tool Setting Services
get "tool_settings/:tool_setting_id", controller: "lti/ims/tool_setting", action: :show, as: :show_lti_tool_settings
get "tool_proxy/:tool_proxy_guid/tool_setting", controller: "lti/ims/tool_setting", action: :show, as: :show_tool_proxy_lti_tool_settings
put "tool_settings/:tool_setting_id", controller: "lti/ims/tool_setting", action: :update, as: :update_lti_tool_settings
put "tool_proxy/:tool_proxy_guid/tool_setting", controller: "lti/ims/tool_setting", action: :update, as: :update_tool_proxy_lti_tool_settings
# Tool Proxy Services
get "tool_proxy/:tool_proxy_guid", controller: "lti/ims/tool_proxy", action: :show, as: "show_lti_tool_proxy"
# Membership Service
get "courses/:course_id/membership_service", controller: "lti/membership_service", action: :course_index, as: :course_membership_service
get "groups/:group_id/membership_service", controller: "lti/membership_service", action: :group_index, as: :group_membership_service
# Submissions Service
scope(controller: "lti/submissions_api") do
get "assignments/:assignment_id/submissions/:submission_id", action: :show
get "assignments/:assignment_id/submissions/:submission_id/history", action: :history
get "assignments/:assignment_id/submissions/:submission_id/attachment/:attachment_id", action: :attachment, as: :lti_submission_attachment_download
end
# Originality Report Service
scope(controller: "lti/originality_reports_api") do
post "assignments/:assignment_id/submissions/:submission_id/originality_report", action: :create
put "assignments/:assignment_id/submissions/:submission_id/originality_report/:id", action: :update
put "assignments/:assignment_id/files/:file_id/originality_report", action: :update
get "assignments/:assignment_id/submissions/:submission_id/originality_report/:id", action: :show
get "assignments/:assignment_id/files/:file_id/originality_report", action: :show
end
# Line Item Service (LTI AGS)
Line Item Controller (sans index) Closes PLAT-3004 Test Plan: CREATE - Attempt to create a new Line Item using the create endpont. Verify the following params are required: - scoreMaximum - label - Verify a new line item is returned and properly serialized. example: { "id" : <line item show/update endpoint> "scoreMaximum" : 60, "label" : "Chapter 5 Test", "resourceId" : "quiz-231", "tag" : "grade" } - Verify the create endpoint allows setting the following optional params: - resourceId - tag - ltiLinkId (Must be the `resource_link_id` of an Lti::ResourceLink. This resource link must already have one line item associated with it.) - Verify a Line Item cannot be created for an Lti::ResourceLink that does not already have at least one Line Item associated with it already. - Verify a Line Item may be created for an Lti::ResourceLink if it already has at least one Line Item associated with it. - Verify that creating a Line Item _without_ specifying an `ltiLinkId` creates a line item and a new assignment specified with the line item. The new assignment should have the following: - context: context of the new line item - name: label of the new line item - point_possible: the score maximum of the new line item - submission_types: none UPDATE - Verify the following attributes may be updated: - scoreMaximum - label - resourceId - tag - Verify that the ltiLinkId may not be updated - Verify that updating the Line Item label also updates the assignment title in the following cases: - when the line item has no associate Lti::ResourceLink - when the Lti::ResourceLink associated with the Line Item only has one line item (the one being updated) - Verify the update response is properly serialized (see example in CREATE). SHOW - Verify the show endpoint allows retrieving the Line Item. - Verify the endpoint responds with 404 if the Line Item does not exist. - Verify the endpoint responds with a 404 if the Line Item exists but is in a different course than the one specified as a parameter. DESTROY - Verify the endpoint responds with 404s in the same instances as the show endpoint. - Verify the endpoint does not allow destroying a Line Item when it is the first line item created chronologically for its associate Lti::ResourceLink - Verify the endpoint allows destroying line items. Change-Id: Iaf26e6addd1e3fe38c5fb76db33fed41a069e7c9 Reviewed-on: https://gerrit.instructure.com/138831 Tested-by: Jenkins Reviewed-by: Marc Alan Phillips <mphillips@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2018-01-24 01:03:35 +08:00
scope(controller: "lti/ims/line_items") do
post "courses/:course_id/line_items", action: :create, as: :lti_line_item_create
get "courses/:course_id/line_items/:id", action: :show, as: :lti_line_item_show
get "courses/:course_id/line_items", action: :index, as: :lti_line_item_index
Line Item Controller (sans index) Closes PLAT-3004 Test Plan: CREATE - Attempt to create a new Line Item using the create endpont. Verify the following params are required: - scoreMaximum - label - Verify a new line item is returned and properly serialized. example: { "id" : <line item show/update endpoint> "scoreMaximum" : 60, "label" : "Chapter 5 Test", "resourceId" : "quiz-231", "tag" : "grade" } - Verify the create endpoint allows setting the following optional params: - resourceId - tag - ltiLinkId (Must be the `resource_link_id` of an Lti::ResourceLink. This resource link must already have one line item associated with it.) - Verify a Line Item cannot be created for an Lti::ResourceLink that does not already have at least one Line Item associated with it already. - Verify a Line Item may be created for an Lti::ResourceLink if it already has at least one Line Item associated with it. - Verify that creating a Line Item _without_ specifying an `ltiLinkId` creates a line item and a new assignment specified with the line item. The new assignment should have the following: - context: context of the new line item - name: label of the new line item - point_possible: the score maximum of the new line item - submission_types: none UPDATE - Verify the following attributes may be updated: - scoreMaximum - label - resourceId - tag - Verify that the ltiLinkId may not be updated - Verify that updating the Line Item label also updates the assignment title in the following cases: - when the line item has no associate Lti::ResourceLink - when the Lti::ResourceLink associated with the Line Item only has one line item (the one being updated) - Verify the update response is properly serialized (see example in CREATE). SHOW - Verify the show endpoint allows retrieving the Line Item. - Verify the endpoint responds with 404 if the Line Item does not exist. - Verify the endpoint responds with a 404 if the Line Item exists but is in a different course than the one specified as a parameter. DESTROY - Verify the endpoint responds with 404s in the same instances as the show endpoint. - Verify the endpoint does not allow destroying a Line Item when it is the first line item created chronologically for its associate Lti::ResourceLink - Verify the endpoint allows destroying line items. Change-Id: Iaf26e6addd1e3fe38c5fb76db33fed41a069e7c9 Reviewed-on: https://gerrit.instructure.com/138831 Tested-by: Jenkins Reviewed-by: Marc Alan Phillips <mphillips@instructure.com> QA-Review: August Thornton <august@instructure.com> Product-Review: Weston Dransfield <wdransfield@instructure.com>
2018-01-24 01:03:35 +08:00
put "courses/:course_id/line_items/:id", action: :update, as: :lti_line_item_edit
delete "courses/:course_id/line_items/:id", action: :destroy, as: :lti_line_item_delete
end
# Scores Service (LTI AGS)
scope(controller: "lti/ims/scores") do
post "courses/:course_id/line_items/:line_item_id/scores", action: :create, as: :lti_result_create
end
# Result Service (LTI AGS)
scope(controller: "lti/ims/results") do
get "courses/:course_id/line_items/:line_item_id/results/:id", action: :show, as: :lti_result_show
get "courses/:course_id/line_items/:line_item_id/results", action: :index
end
# Progress Service (LTI AGS)
scope(controller: "lti/ims/progress") do
get "courses/:course_id/progress/:id", action: :show, as: :lti_progress_show
end
# Dynamic Registration Service
scope(controller: "lti/ims/dynamic_registration") do
get "accounts/:account_id/registration_token", action: :registration_token
get "accounts/:account_id/registrations/uuid/:registration_uuid", action: :registration_by_uuid
put "accounts/:account_id/registrations/:registration_id/overlay", action: :update_registration_overlay
get "registrations/:registration_id/view", action: :registration_view, as: :lti_registration_config
post "registrations", action: :create, as: :create_lti_registration
end
# Public JWK Service
scope(controller: "lti/public_jwk") do
put "/developer_key/update_public_jwk", action: :update, as: :public_jwk_update
end
# Context External Tools Service
scope(controller: "lti/account_external_tools") do
post "/accounts/:account_id/external_tools", action: :create, as: :account_external_tools_create
get "/accounts/:account_id/external_tools/:external_tool_id", action: :show, as: :account_external_tools_show
get "/accounts/:account_id/external_tools", action: :index, as: :account_external_tools_index
delete "/accounts/:account_id/external_tools/:external_tool_id", action: :destroy, as: :account_external_tools_destroy
end
# Data Services Service
scope(controller: "lti/data_services") do
post "/accounts/:account_id/data_services", action: :create, as: :data_services_create
get "/accounts/:account_id/data_services/:id", action: :show, as: :data_services_show
put "/accounts/:account_id/data_services/:id", action: :update, as: :data_services_update
get "/accounts/:account_id/data_services", action: :index, as: :data_services_index
get "/accounts/:account_id/event_types", action: :event_types_index, as: :data_services_event_types
delete "/accounts/:account_id/data_services/:id", action: :destroy, as: :data_services_destroy
end
Account lookup endpoint for CDC Event Transformer Endpoint needed by CDC Event Tranformer to look up UUIDs for root accounts it hasn't seen. closes PLAT-5515 flag=none Test plan: - get an LTI Advantage token for a site admin dev key with the new scope. This can be done by adding logging to the live-events-lti tool (I think in app/services/access_token_service.rb#16) or using my cdc-event-transformer test in CanvasClientTest.java and printing out cc.getToken(). - hit the new endpoint with header "Authorization: Bearer MYACCESSTOKEN" web.canvas-lms.docker/api/lti/accounts/123 with varying values of account ID, including global IDs, accounts that do not exist, global IDs where the shard does not exist... - ideally we'd like to test that a dev key only available for one shard cannot access account info for another shard. This could be done by creating two dev keys that have the same ID but are on different shards, and use a token for one dev key to try to access an account on the other shard. This is probably hard to do locally though. I did test on prod that DeveloperKey#account_binding_for will return nil for an account in another shard even if there is a dev key with the same local ID in the account's shard that has access to it. Change-Id: I1299ebce9b94ce00d7cb62db01891b81908915ff Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/229580 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Weston Dransfield <wdransfield@instructure.com> QA-Review: Xander Moffatt <xmoffatt@instructure.com> Product-Review: Evan Battaglia <ebattaglia@instructure.com>
2020-03-11 07:11:46 +08:00
# Account Lookup service
scope(controller: "lti/account_lookup") do
get "/accounts/:account_id", action: :show
end
Add LTI NRPS v2 Course and Group membership list API - No-frills support for LTI Advantage Names and Roles Provisioning Service version 2. I.e. no query param support, no pagination. - Similar to other LTI Adv services, this API is disabled in prod env due to incompleteness, esp lack of authN/authZ. - URL scheme: `/api/lti/[courses|groups]/:context_id/names_and_roles` Closes LTIA-11 Test Plan * Create course with several participating (i.e. invite-accepted) and pending enrollments. Add several of those enrolled users to one or more groups in that course. * Ensure participating enrollments are spread across all base roles and several custom roles. * GET `/api/lti/[courses|groups]/:context_id/names_and_roles` for the course and group, respectively. * Verify all participating users returned with correct attribute mappings, all non-participating users not returned. * See LTIA-11 for additional attribute mapping details, esp role mappings. * Create another course with no enrollments and an empty group. * Verify GET `/api/lti/[courses|groups]/:context_id/names_and_roles` returns 200 with an empty `members` array for the course and group, respectively. * Verify GET `/api/lti/[courses|groups]/:context_id/names_and_roles` for non-existent contexts returns 404. Change-Id: Ib8d174a3d583435423ce41f2488c80ae6d66cb72 Reviewed-on: https://gerrit.instructure.com/165275 Reviewed-by: Marc Alan Phillips <mphillips@instructure.com> Product-Review: Karl Lloyd <karl@instructure.com> Tested-by: Jenkins QA-Review: Pedro Fajardo <pfajardo@instructure.com>
2018-09-18 08:08:52 +08:00
# Names and Roles Provisioning (NRPS) v2 Service
scope(controller: "lti/ims/names_and_roles") do
get "courses/:course_id/names_and_roles", controller: "lti/ims/names_and_roles", action: :course_index, as: :course_names_and_roles
get "groups/:group_id/names_and_roles", controller: "lti/ims/names_and_roles", action: :group_index, as: :group_names_and_roles
end
# Security
Add asymmetric encryption for service tokens refs FOO-2410 test plan: - in dynamic_settings.yml, add the following block: ``` store: canvas: services-jwt: # these are all the same JWK but with different kid # to generate a new key, run the following in a Canvas console: # # key = OpenSSL::PKey::RSA.generate(2048) # key.public_key.to_jwk(kid: Time.now.utc.iso8601).to_json jwk-past.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-05-18T22:33:20Z_a\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" jwk-present.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-06-18T22:33:20Z_b\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" jwk-future.json: "{\"kty\":\"RSA\",\"e\":\"AQAB\",\"n\":\"uX1MpfEMQCBUMcj0sBYI-iFaG5Nodp3C6OlN8uY60fa5zSBd83-iIL3n_qzZ8VCluuTLfB7rrV_tiX727XIEqQ\",\"kid\":\"2018-07-18T22:33:20Z_c\",\"d\":\"pYwR64x-LYFtA13iHIIeEvfPTws50ZutyGfpHN-kIZz3k-xVpun2Hgu0hVKZMxcZJ9DkG8UZPqD-zTDbCmCyLQ\",\"p\":\"6OQ2bi_oY5fE9KfQOcxkmNhxDnIKObKb6TVYqOOz2JM\",\"q\":\"y-UBef95njOrqMAxJH1QPds3ltYWr8QgGgccmcATH1M\",\"dp\":\"Ol_xkL7rZgNFt_lURRiJYpJmDDPjgkDVuafIeFTS4Ic\",\"dq\":\"RtzDY5wXr5TzrwWEztLCpYzfyAuF_PZj1cfs976apsM\",\"qi\":\"XA5wnwIrwe5MwXpaBijZsGhKJoypZProt47aVCtWtPE\"}" ``` - Ensure /internal/services/jwks loads correctly - In console, ensure `CanvasSecurity::ServicesJwt.decrypt(Base64.decode64(CanvasSecurity::ServicesJwt.for_user('localhost', User.first)))` and `CanvasSecurity::ServicesJwt.decrypt(Base64.decode64(CanvasSecurity::ServicesJwt.for_user('localhost', User.first, symmetric: true)))` both work and produce sensible looking output Change-Id: I13c6c35cc92ed12d03bf97e89e590614e11c6d47 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275160 QA-Review: August Thornton <august@instructure.com> Product-Review: August Thornton <august@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Ethan Vizitei <evizitei@instructure.com> Reviewed-by: Evan Battaglia <ebattaglia@instructure.com>
2021-10-05 03:20:31 +08:00
scope(controller: "security") do
get "security/jwks", action: :jwks, as: :lti_jwks
get "security/openid-configuration", action: :openid_configuration, as: :openid_configuration
end
# Feature Flags
scope(controller: "lti/feature_flags") do
%w[course account].each do |context|
prefix = "#{context}s/:#{context}_id"
get "/#{prefix}/feature_flags/:feature", action: :show
end
end
allow site admin to get LTI token for any 1.3 tool why: * getting an LTI access token currently requires installing the LTI 1.3 test tool and configuring it then requesting a token, or otherwise hacking other tools to make a request to the token endpoint * it can be very helpful for troubleshooting to have an LTI access token for any needed tool * note that 1.1 tools don't have DeveloperKeys, and 2.0 tools use their own access tokens. this main use case is for 1.3 tools and for the AGS. test plan: * choose a 1.3 ContextExternalTool * navigate to canvas.docker/api/lti/advantage_token?tool_id=<tool's id> * it should return an access token in the form of a JWT * choose a DeveloperKey that is an LTI 1.3 key * navigate to canvas.docker/api/lti/advantage_token?client_id=<key's id> * it should return an access token * choose a DeveloperKey that isn't for an LTI tool * this url should return 400 and say it must be a 1.3 key * choose a ContextExternalTool that isn't 1.3 * this url should return 400 and say it must be a 1.3 tool * sign out of Canvas * this url should return unauthorized * sign in as a non-site-admin user * this url should return unauthorized Change-Id: Ie599fe3c4a8413ad0a65515837360c439ddb3b9c Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/269109 Reviewed-by: Mysti Lilla <mysti@instructure.com> QA-Review: Mysti Lilla <mysti@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Xander Moffatt <xmoffatt@instructure.com>
2021-07-15 01:21:49 +08:00
# LTI Access Tokens (Site Admin only)
get "lti_2_token", controller: "lti/token", action: :lti_2_token, as: :lti_2_token_site_admin
allow site admin to get LTI token for any 1.3 tool why: * getting an LTI access token currently requires installing the LTI 1.3 test tool and configuring it then requesting a token, or otherwise hacking other tools to make a request to the token endpoint * it can be very helpful for troubleshooting to have an LTI access token for any needed tool * note that 1.1 tools don't have DeveloperKeys, and 2.0 tools use their own access tokens. this main use case is for 1.3 tools and for the AGS. test plan: * choose a 1.3 ContextExternalTool * navigate to canvas.docker/api/lti/advantage_token?tool_id=<tool's id> * it should return an access token in the form of a JWT * choose a DeveloperKey that is an LTI 1.3 key * navigate to canvas.docker/api/lti/advantage_token?client_id=<key's id> * it should return an access token * choose a DeveloperKey that isn't for an LTI tool * this url should return 400 and say it must be a 1.3 key * choose a ContextExternalTool that isn't 1.3 * this url should return 400 and say it must be a 1.3 tool * sign out of Canvas * this url should return unauthorized * sign in as a non-site-admin user * this url should return unauthorized Change-Id: Ie599fe3c4a8413ad0a65515837360c439ddb3b9c Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/269109 Reviewed-by: Mysti Lilla <mysti@instructure.com> QA-Review: Mysti Lilla <mysti@instructure.com> Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Xander Moffatt <xmoffatt@instructure.com>
2021-07-15 01:21:49 +08:00
get "advantage_token", controller: "lti/token", action: :advantage_access_token, as: :lti_advantage_token_site_admin
end
ApiRouteSet.draw(self, "/api/sis") do
scope(controller: :sis_api) do
get "accounts/:account_id/assignments", action: "sis_assignments", as: :sis_account_assignments
get "courses/:course_id/assignments", action: "sis_assignments", as: :sis_course_assignments
end
scope(controller: :disable_post_to_sis_api) do
put "courses/:course_id/disable_post_to_sis", action: "disable_post_to_sis", as: :disable_post_to_sis_course_assignments
end
end
2011-02-01 09:57:29 +08:00
end