// ==UserScript== // @name Canvas Experience (CX) Tools // @namespace https://siteadmin.instructure.com/ // @namespace https://instructure.my.salesforce.com/* // @version 2025032402 // @description Trying to take over the world! "Canvas Experience (CX) Tools" // @author Daniel Gilogley, Zoe Bogner and Christopher McAvaney // @match https://*.test.instructure.com/* // @match https://*.beta.instructure.com/* // @match https://*.instructure.com/* // @match https://*.security.instructure.com/* // @match https://s3.amazonaws.com/SSL_Assets/APAC/ticketpage.html* // @match https://instructure.my.salesforce.com/* // @exclude https://siteadmin*instructure.com/* // @exclude https://reports.instructure.com/* // @exclude https://gerrit.instructure.com/* // @exclude https://identity.instructure.com/* // @grant GM_getValue // @grant GM_setValue // @grant GM_getResourceText // @grant GM_addStyle // @run-at document-idle // @require https://gist.github.com/raw/2625891/waitForKeyElements.js // @resource customCSS https://raw.githubusercontent.com/clmcavaney/CX-Tools/master/canvasBetter.css // @icon https://www.google.com/s2/favicons?sz=64&domain=instructure.com // ==/UserScript== if (typeof jQuery == 'undefined' || typeof jQuery === undefined || typeof jQuery === null) { var headTag = document.getElementsByTagName("head")[0]; var jqTag = document.createElement('script'); jqTag.type = 'text/javascript'; jqTag.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'; headTag.appendChild(jqTag); jqTag.onload = myJQueryCode; } else { myJQueryCode(); } function myJQueryCode() { // global variables var domain = 'https://' + document.location.hostname; var userToken = getItem('token'); var token = userToken; var _cx_tools_on = false; var _cx_tools_version = '2025032402'; // If on an instructure page if (document.location.hostname.indexOf('instructure.com') >= 0) { $(document).ready(function() { var cssTxt = GM_getResourceText("customCSS"); GM_addStyle(cssTxt); //add the settings link $('#menu > li:last').after(''); //add the CX Tools link $('#menu > li:last').after(''); //remove the images if on the old UI remove the images if ($('#menu > li:contains("Dashboard")').length <= 0) { $('#cx_li_self img, #cx_li_settings img').hide(); $('#cx_link_self, #cx_link_settings').attr('class', 'menu-item-no-drop'); } // some regular expressions to match "users", "settings" and "permissions" pages const re_users=/accounts\/(\d+|self)\/users/; const re_settings=/\/accounts\/(\d+|self)\/settings/; const re_perms=/\/accounts\/[^\/]+\/permissions/; const re_auth_providers=/\/accounts\/[^\/]+\/authentication_providers/; const sa_setting_hl_colour='#fdf3f3'; const admin_shield_svg = ''; // if on the settings page if ( document.location.pathname.toLowerCase().match(re_settings) !== null ) { _cx_tools_on = true; //focus on the settings link $('li.ic-app-header__menu-list-item--active').attr('class', "menu-item ic-app-header__menu-list-item"); $('li#cx_li_settings').attr('class', "menu-item ic-app-header__menu-list-item ic-app-header__menu-list-item--active"); //Add a Salesforce link to the Account at the bottom of the page $('#account_external_integration_keys_salesforce_account_id').after(''); //---------On the main Settings page of 'Settings----------------- //create the button to do the default settings $('#account_settings > legend').after(''); //apply the action of clicking the default button $('#cx_button_applyDefaults_settings').click(function(e) { e.preventDefault(); if (confirm("Are you sure?")) { $('#cx_button_applyDefaults_settings').attr('disabled', 'disabled').css('cursor', 'default'); //Disable the button after click //apply the defaults on the settings page $('#account_default_locale').val($('#account_default_locale > option:contains("English (Australia)")').val()); //Default Language $('#account_default_time_zone').val($('#account_default_time_zone option:contains("Sydney (+10:00)")').val()); //Timezone //click some of the features if unchecked $('#account_settings_prevent_course_renaming_by_teachers:not(:checked)').click(); //Prevent teachers from renaming courses $('#account_settings_admins_can_change_passwords:not(:checked)').click(); $('#account_settings_admins_can_view_notifications:not(:checked)').click(); $('#account_allow_sis_import:not(:checked)').click(); $('#account_settings_global_includes:not(:checked)').click(); $('#account_settings_enable_profiles:not(:checked)').click(); $('#account_settings_sub_account_includes:not(:checked)').click(); $('#account_services_analytics:not(:checked)').click(); $('#account_services_avatars:not(:checked)').click(); $('#account_settings_prevent_course_renaming_by_teachers:not(:checked)').click(); //Enabled Web Services to none $('#account_settings > fieldset:contains("Enabled Web Services") > div:not(:last) input[type="checkbox"]:checked').click(); //---------On the main Feature page of 'Settings'----------------- //check to see if clicked, and if not click them! //LOR External Tools if ($('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.lor_for_account div.ic-Super-toggle__switch').css('background-color') === "rgb(57, 75, 88)") { $('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.lor_for_account > div.span5.text-right > label > div > div').click(); } //internation SMS if ($('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.international_sms div.ic-Super-toggle__switch').css('background-color') === "rgb(57, 75, 88)") { $('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.international_sms > div.span5.text-right > label > div > div').click(); } //Wrap Calendar titles if ($('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.wrap_calendar_event_titles div.ic-Super-toggle__switch').css('background-color') === "rgb(57, 75, 88)") { $('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.wrap_calendar_event_titles > div.span5.text-right > label > div > div').click(); } //Canvas Parent if ($('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.canvas_parent div.ic-Super-toggle__switch').css('background-color') === "rgb(57, 75, 88)") { $('#tab-features > div.account-feature-flags > ul div.row-fluid.feature.canvas_parent > div.span5.text-right > label > div > div').click(); } //focus on the submit button $('html,body').animate({ scrollTop: $('#account_settings > div.button-container > button').offset().top }, 'slow'); //Notification to user $('#account_settings > div.button-container').append('Yes, it`s even applied the Features too!'); //Dashboard images $('div.row-fluid.feature.course_card_images div.ff-background:contains("On") span.ui-button-text').click(); //Recurring Calendar Events $('div.row-fluid.feature.recurring_calendar_events div.ff-background:contains("Allow") span.ui-button-text').click(); // Multiple Grading Periods $('div.row-fluid.feature.multiple_grading_periods div.ff-background:contains("Allow") span.ui-button-text').click(); //Display Totals for "All Grading Periods" $('div.row-fluid.feature.all_grading_periods_totals div.ff-background:contains("Allow") span.ui-button-text').click(); //Apply the email display name to the account name $('#account_settings_outgoing_email_default_name_option_custom').click(); $('#account_settings_outgoing_email_default_name').val('Canvas @ ' + $('input[name="account[name]"]').val()); //Faculty Journel $('#account_enable_user_notes:not(:checked)').click(); //Turn on Scheduler $('#account_settings_show_scheduler:not(:checked)').click(); //Users cant edit their name $('#account_settings_users_can_edit_name:checked').click(); //Users cant delete their default email $('#account_settings_edit_institution_email:checked').click(); //features //LTI2 Registration $('#tab-features > div.account-feature-flags > ul > li:nth-child(8) > div.row-fluid.feature.lti2_rereg > div.span5.text-right > label > div > div > div.ic-Super-toggle__option--RIGHT').click(); //Use the new scheduler $('#tab-features > div.account-feature-flags > ul > li:nth-child(12) > div.row-fluid.feature.better_scheduler > div.span5.text-right > label > div > div > div.ic-Super-toggle__option--RIGHT').click(); //Student Context Card $('#tab-features > div.account-feature-flags > ul > li:nth-child(18) > div.row-fluid.feature.student_context_cards > div.span5.text-right > label > div > div > div.ic-Super-toggle__option--RIGHT').click(); //Toggle feature details for New User Tutorial $('#tab-features > div.account-feature-flags > ul > li:nth-child(19) > div.row-fluid.feature.new_user_tutorial > div.span5.text-right > label > div > div > div.ic-Super-toggle__option--RIGHT').click(); //Send Authorization URL in LTI2 Registration $('#tab-features > div.account-feature-flags > ul > li:nth-child(21) > div.row-fluid.feature.lti_2_auth_url_registration > div.span5.text-right > label > div > div > div.ic-Super-toggle__option--RIGHT').click(); //Add the show LTIs button on the settings page //users must first be on the page before pressing the button var settings_match = document.location.pathname.toLowerCase().match(re_settings); if ( settings_match !== null ) { $('nav#breadcrumbs').after('
'); $("#cx_listLti_ID").click(function(e){ e.preventDefault(); $("#cx_listLti_ID").attr('disabled','disabled'); listLtiID(settings_match[1]); return 0; }); } } else { return 0; } }); //----------End do the apply default button ----------------------- // Adding identifiers to items that only SiteAdmin users can change $('#account_settings tr td > label[for=account_settings_mfa_settings]').parent().prepend(admin_shield_svg); $('#account_settings tr td > label[for=account_settings_mfa_settings]').parent().parent().css('border', '1px dashed red').css('background-color', sa_setting_hl_colour); $('#account_settings tr td > label[for=account_settings_mfa_settings]').parent().next().append('
setting definition
'); $('#account_settings tr td > label[for=account_settings_include_students_in_global_survey]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > div > label[for=account_settings_increase_calendar_limit]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset.account_domains > legend:contains(Canvas Cloud Information)').css('align-items', 'center').css('display', 'flex').append(admin_shield_svg).css('background-color', sa_setting_hl_colour).next().append('
setting definition
'); $('#account_settings > fieldset.account_domains > legend:contains(Canvas Cloud Information)').next().append(admin_shield_svg).css('background-color', sa_setting_hl_colour); $('#account_settings > fieldset.account_domains > select').after(admin_shield_svg).css('background-color', sa_setting_hl_colour); $('#account_settings > fieldset.account_domains > ul li.new_domain button.add_domain_button').after(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour); $('#account_settings > fieldset.account_domains > div').append(admin_shield_svg).css('background-color', sa_setting_hl_colour); $('#account_settings > fieldset > legend:contains(Acceptable Use Policy)').css('align-items', 'center').css('display', 'flex').append(admin_shield_svg).css('background-color', sa_setting_hl_colour).after('
setting definition
'); // Canvas for Elementary is available to an account admin, removing this one // // Features - group the ones that are Site Admin specific // // comment for "Canvas for Elementary" // var _site_admin_div = $('#account_settings > fieldset > legend:contains(Features)').parent('fieldset').find('div').slice(1,3).wrapAll('
').parent(); // _site_admin_div.prepend(admin_shield_svg).css('background-color', sa_setting_hl_colour).prepend('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_admins_can_change_passwords]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_admins_can_view_notifications]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_enable_eportfolios]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_allow_sis_import]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_include_integration_ids_in_gradebook_exports]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_allow_invitation_previews]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_enable_alerts]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_global_includes]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).prepend('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_show_scheduler]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_enable_profiles]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_limit_parent_app_web_access]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=enable_equella]').parent().append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_settings_enable_turnitin]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_services_account_survey_notifications]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset > legend:contains(Features)').parent().find('div > label[for=account_services_beta_for_students]').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).append('
setting definition
'); $('#account_settings > fieldset#add_sis_app_token > legend:contains(SIS Agent Token Authentication)').css('align-items', 'center').css('display', 'flex').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).prepend('
setting definition
'); $('#account_settings > fieldset#external_integration_keys > legend:contains(External Integration Keys)').css('align-items', 'center').css('display', 'flex').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour).prepend('
setting definition
'); $('nav ul#section-tabs > li > a:contains(Domain Lookups)').css('align-items', 'center').css('display', 'flex').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour); $('nav ul#section-tabs > li > a:contains(SFTP User)').css('align-items', 'center').css('display', 'flex').append(admin_shield_svg).parent().css('background-color', sa_setting_hl_colour); // reference to the Canvas Feature Option Summary waitForKeyElements("#tab-features > div > span", append_feature_details); // 20231006 - can't get the correct trigger for this to work correctly // waitForKeyElements('#tab-features > div > table > tbody', append_feature_account_details); // END - adding SiteAdmin user shield // 20230824 - I think this code below no longer works - may remove it on a future release //Changes to the 'Apps' tab - only if you click on my settings link, and did not navigate there natuarally $('#account_settings_tabs > ul > li:contains("Apps"):first > a:first').click(function(a) { a.preventDefault(); setTimeout(function() { $('#external_tools > div > div > div.Header > h2 > div > span.AddExternalToolButton > a.btn.btn-primary.add_tool_link.lm').click(function(b) { b.preventDefault(); setTimeout(function() { $('body > div.ReactModalPortal > div > div > div > div > div.ReactModal__Header-Title > h4').after(''); var name = "Commons Setup"; var consumerKey = "1"; var sharedSecret = "c9b6c488-4750-48ce-897c-b919ff3cb0f1"; var configURL = "https://lor.instructure.com/api/account-setup/tool-config"; $('#cx_button_canvasCommons').click(function(c) { c.preventDefault(); $('#cx_button_canvasCommons').attr('disabled', 'disabled').css('cursor', 'default'); //Disable the button after click //select URL $('#configuration_type_selector-bs > ul > li:nth-child(2) > a').click(); //apply the values to the fields $('body > div.ReactModalPortal > div > div > div > form > div.ReactModal__Body > div.formFields > div > div:nth-child(1) > label > input[placeholder="Name"]:first').val(name); $('body > div.ReactModalPortal > div > div > div > form > div.ReactModal__Body > div.formFields > div > div:nth-child(2) > div:nth-child(1) > div > label > input[placeholder="Consumer key"]').val(consumerKey); $('body > div.ReactModalPortal > div > div > div > form > div.ReactModal__Body > div.formFields > div > div:nth-child(2) > div:nth-child(2) > div > label > input[placeholder="Shared Secret"]').val(sharedSecret); $('body > div.ReactModalPortal > div > div > div > form > div.ReactModal__Body > div.formFields > div > div:nth-child(3) > label > input[placeholder="Config URL"]').val(configURL); //*/ //focus on the submit $('body > div.ReactModalPortal > div > div > div > form > div.ReactModal__Footer > div > button.btn.btn-primary').focus(); }); }, 100); }); }, 100); }); } //Add Auth changer to users if ( document.location.pathname.toLowerCase().match(re_users) !== null ) { _cx_tools_on = true; //figure out how many logins there are and create a select list for them var optionCountHTML = ''; for (var i = 1; i <= $('fieldset#login_information > table.ic-Table > tbody > tr.login:not(:last)').length; i++) { optionCountHTML += ''; } optionCountHTML = ''; //Create the auth method select for Canvas, LDAP, SAML, Microsoft, and Google var changeAuthSelect = ''; var deleteAndGoButton = ' '; var td_details = changeAuthSelect + optionCountHTML + deleteAndGoButton; //Put in the option to the page for the auth method $('#name_and_email > table > tbody > tr:last').after(''); //put in the options dropdown $('#cx_changeAuth_tr').append('' + td_details + ''); //When you click the 'Go' button $('#cx_changeAuth_button').click(function(e) { e.preventDefault(); //disable the options $('#cx_changeAuth_button,#cx_changeAuth,#cx_deleteOldAuthMethod,#cx_changeAuthCount').attr('disabled', 'disabled'); //replace the 'Go' button with the spinny wheel $('#cx_changeAuth_button').html('
'); //check to see a proper value is selected if ($('#cx_changeAuth').val() === "null" || $('#cx_changeAuthCount').val() === "null") { alert('No Auth method or Number selected!'); return; } else { var currentUserID = ENV.USER_ID; var authMethodSelected = $('#cx_changeAuth').val(); var authMethodNumber = $('#cx_changeAuthCount').val(); var authDeleteOld = $('#cx_deleteOldAuthMethod:checked').length; var loginID = $('fieldset#login_information > table.ic-Table > tbody > tr.login:eq(' + (authMethodNumber - 1) + ') b.unique_id').text().trim(); var sisID = $('fieldset#login_information > table.ic-Table > tbody > tr.login:eq(' + (authMethodNumber - 1) + ') th[scope="row"] div:eq(0)').text().trim().split('SIS ID: ').join(''); //if no SIS id, then SIS id is login ID if (sisID === "SIS ID:") { sisID = loginID; } else { sisID += "_" + authMethodSelected; } var integrationID = $('fieldset#login_information > table.ic-Table > tbody > tr.login:eq(' + (authMethodNumber - 1) + ') th[scope="row"] div:last').text().trim().split('Integration ID: ').join(''); //if not Integration ID then it equalls null if (integrationID === "Integration ID:") integrationID = ''; //if deleted, then delete the old login method if (authDeleteOld >= 1) { $('fieldset#login_information > table.ic-Table > tbody > tr.login:eq(' + (authMethodNumber - 1) + ') a.delete_pseudonym_link').click(); } //build the string for the POST var postString = '/api/v1/accounts/self/logins?' + encodeURI('user[id]=' + currentUserID); //which users postString += encodeURI("&login[authentication_provider_id]=" + authMethodSelected); //login[authentication_provider_id] postString += encodeURI("&login[unique_id]=" + loginID); //login ID postString += encodeURI("&login[sis_user_id]=" + sisID); //login[sis_user_id] postString += encodeURI("&login[integration_id]=" + integrationID); //login[integration_id] console.log(decodeURI(postString)); //post the API call var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function() { if (this.readyState === 4) { console.log(this.responseText); alert(this.responseText); location.reload(); } }); xhr.open("POST", postString); xhr.setRequestHeader("authorization", "Bearer " + userToken); xhr.setRequestHeader("cache-control", "no-cache"); xhr.send(data); } }); } else if ( document.location.pathname.toLowerCase().match(re_settings) !== null ) { _cx_tools_on = true; //token storage and update var tokenInputHTML = '

'; $('#right-side').prepend(tokenInputHTML); $('#cx_apiTokenButton').click(function(e) { e.preventDefault(); if (confirm("Update token with: " + $('#cx_apiToken').val())) { storeItem('token', $('#cx_apiToken').val()); location.reload(); } return; }); } else if ( document.location.pathname.toLowerCase().match(re_auth_providers) !== null ) { _cx_tools_on = true; // new common identity box on the authentication page // ic-Form-control with a child input tag with name attribute of "authentication_provider[instructure_identity_login_percentage]" $('#application div.ic-Form-control > input[name="authentication_provider[instructure_identity_login_percentage]"]').parent().append(admin_shield_svg).css('background-color', sa_setting_hl_colour); } else if (document.location.pathname.toLowerCase() === "/cxtools1") { _cx_tools_on = true; //focus on the CX Tools links page $('li.ic-app-header__menu-list-item--active').attr('class', "menu-item ic-app-header__menu-list-item"); $('li#cx_li_self').attr('class', "menu-item ic-app-header__menu-list-item ic-app-header__menu-list-item--active"); document.title = "CX Tools - Update User SIS id from one to another"; $('#main').html('

Update User SIS id from one to another

Old SIS ID / Canvas ID New SIS ID Console Log



Useful links;
'); $('button#cx_updateGo').click(function(e) { e.preventDefault(); //disable fields and buttons $('button#cx_updateGo, #cx_old_sis_id, #cx_new_sis_id, #cx_canvasOrSIS').attr('disabled', 'disabled'); //get the arrays and confrim that they match var old_sis_ID = csvOrNot($('#cx_old_sis_id').val()); var new_sis_ID = csvOrNot($('#cx_new_sis_id').val()); //create new object array var newObjectArray = []; if (old_sis_ID.length === new_sis_ID.length) { $.each(old_sis_ID, function(i, e) { var tmp = { new: new_sis_ID[i].trim(), old: e.trim() }; newObjectArray.push(tmp); }); if (confirm("Are you sure?\nThis can't be undone?")) { update_sis_id(newObjectArray, $('#cx_canvasOrSIS').val()); } else { return 0; } } else { return alert('Array lengths do not match!'); } }); } else if(document.location.pathname.toLowerCase() === "/cxtools2") { _cx_tools_on = true; document.title = "CX Tools"; const _main_menu_html_tpl = `

Canvas Experience (CX) Tools

CX Tools are the best! Version: _VERSION_

Links

Tools

Acknowledgements:


`.trim(); var _subdomain = document.location.hostname.split('.')[0]; var _main_menu_html = _main_menu_html_tpl.replaceAll("_VERSION_", _cx_tools_version).replaceAll('_userToken_', userToken).replaceAll('_INSTANCE_URL_', document.location.hostname).replaceAll('_INSTANCE_SUBDOMAIN_', _subdomain); $('#main').html(_main_menu_html); // LTI Buttons Function $('li.cx_action_lti button').click(function(e){ e.preventDefault(); console.log("Installing this Tool: " + $(this).text()); console.log("Key: " + $(this).attr("key")); console.log("Secret: " + $(this).attr("secret")); console.log("URL: " + $(this).attr("url")); //Disable the button $(this).attr("disabled","disabled"); // show the user something is happening $('#cx_processing').show(); //Call the function to install LTI based on the paramters in the HTML Buttons installLTI($(this).text(), $(this).attr('key'), $(this).attr('secret'), $(this).attr('url'), "", $(this)); }); //Outcomes Install $('li.cx_action_outcome button').click(function(e){ e.preventDefault(); console.log('Installing outcomes: ' + $(this).text()); //Disable the button $("button", this).attr("disabled","disabled"); outcomesAPI($('button',this).attr('guid')); }); //External tool link (Office365 / GAFE) $('li.cx_action_externalTool button').click(function(e){ e.preventDefault(); $("button", this).attr("disabled","disabled"); window.open($('button',this).attr('destination') + "?canvasurl=" + document.location.hostname.split('.instructure.com').join(''), "_blank"); //Place to Generate tokens - //window.open($('button',this).attr('url'), "_blank"); //Config XML - Not needed in 2.1 //window.open("/accounts/self/settings/configurations#tab-tools", "_blank"); //Config Page - Not needed in 2.1 }); // Inherited LTI developer key $('li.cx_enable_inherited_lti_and_app button').click(function(e){ e.preventDefault(); // need to get the specific button var id = $(this).prop('id'); // disable the button $('#'+id).attr("disabled","disabled"); // show the user something is happening $('#cx_processing').show(); // proposed function enableLTIKeyandInstallLTI($(this).attr('client_id'), $('#'+id)); }); $('li.cx_enable_inherited_lti_only button').click(function(e){ e.preventDefault(); // need to get the specific button var id = $(this).prop('id'); // disable the button $('#'+id).attr("disabled","disabled"); // show the user something is happening $('#cx_processing').show(); // proposed function enableLTIKeyandInstallLTI($(this).attr('client_id'), $('#'+id), false); }); $('li.cx_enable_credentials button').click(function(e){ e.preventDefault(); // need to get the specific button var id = $(this).prop('id'); // disable the button $('#'+id).attr("disabled","disabled"); // show the user something is happening $('#cx_processing').show(); // proposed function enableLTIKeyandInstallLTI($(this).attr('client_id_api'), $('#'+id), false, handle_credentials_api_key_enable); enableLTIKeyandInstallLTI($(this).attr('client_id_lti'), $('#'+id), false, handle_credentials_lti_key_enable); }); //Update Token function $('#cx_apiTokenButton').click(function(e) { e.preventDefault(); if (confirm("Update token with: " + $('#cx_apiToken').val())) { storeItem('token', $('#cx_apiToken').val()); location.reload(); } return; }); }else if(document.location.pathname.toLowerCase() === "/cxtools3") { _cx_tools_on = true; //Create users page document.title="CX Tools - Create Users" $('#main').html('

Create Users

"User ID" and "Login ID" are the only required fields.

Multiple users can be specified and each users details can be comma separated or new line separated.

First Name Last Name User ID Login ID Email Address



Console Log

Useful links;


'); //getting the auto created users from SF var urlVars = getUrlVars(); if(urlVars.sfUsers == "true"){ var splitUsers = urlVars.userData.split('|'); $.each(splitUsers,function(){ var thisUser = this.split('~'); if(thisUser[0]!="undefined" && thisUser[0]!="" && thisUser[1]!="undefined" && thisUser[1]!="" && thisUser[2]!="undefined" && thisUser[2]!=""){ $('#cx_first_name').val($('#cx_first_name').val() + thisUser[0] + '\n'); $('#cx_last_name').val($('#cx_last_name').val() + thisUser[1] + '\n'); $('#cx_user_id').val($('#cx_user_id').val() + thisUser[2] + '\n'); $('#cx_login_id').val($('#cx_login_id').val() + thisUser[2] + '\n'); $('#cx_email').val($('#cx_email').val() + thisUser[2] + '\n'); } }); } $('button#cx_create_users').click(function(e) { e.preventDefault(); //disable fields and buttons $('#cx_create_users,#cx_set_auth,#cx_first_name,#cx_last_name,#cx_login_id,#cx_user_id,#cx_email,#cx_notifyUsers').attr('disabled', 'disabled'); //check the "Notify" flag var notifyCheck = $('#cx_notifyUsers').prop('checked'); //if its not null or canvas, then u can't notify if($('#cx_set_auth').val() == '' || $('#cx_set_auth').val() == 'canvas' || $('#cx_set_auth').val() == 'Null') notifyCheck = false; //get the arrays and confrim that they match var first_name = csvOrNot($('#cx_first_name').val()); var last_name = csvOrNot($('#cx_last_name').val()); var login_id = csvOrNot($('#cx_login_id').val()); var user_id = csvOrNot($('#cx_user_id').val()); var email = csvOrNot($('#cx_email').val()); var auth_id = $('#cx_set_auth').val(); //create new object array var createNewUserArray = []; if (user_id.length === first_name.length) { $.each(user_id, function(i, e) { var tmp = { first_name: user_id[i].trim(), last_name: last_name[i].trim(), full_name: first_name[i].trim() + ' ' + last_name[i].trim(), login_id: login_id[i].trim(), user_id: user_id[i].trim(), email: email[i].trim(), auth_id:auth_id }; createNewUserArray.push(tmp); }); if (confirm("Are you sure?\nThis can't be undone?")) { //main function //Main create users createUsers(createNewUserArray,notifyCheck); } else { return 0; } } else { return alert('Array lengths do not match!'); } }); }else if(document.location.pathname.toLowerCase() === "/cxtools4") { _cx_tools_on = true; document.title="CX Tools - Create Sandboxes"; const _create_sandboxes_html_tpl = `

Create Sandboxes

Actions

  • Create sandbox courses for each user below:

    User ID(s)

    You can choose to enrol these users into the "Canvas 101 (Growing with Canvas)" course too.

API token

Console Log

Useful links

`.trim(); var _create_sandboxes_html = _create_sandboxes_html_tpl.replaceAll('_userToken_', userToken); $('#main').html(_create_sandboxes_html); //Create Sandbox Account $('#cx_button_create_sandbox').click(function(){ $('#cx_button_create_sandbox').attr('disabled','disabled'); var createSandbox = createSandboxAccount(); }); //Create canavs101 Button $('#cx_button_create_canvas101').click(function(){ $('#cx_button_create_canvas101').attr('disabled','disabled'); var createCanvas101 = createCanvasCourse("Canvas 101","canvas101","sandbox","Growing With Canvas",null); }); //create Sandboxes function $('#cx_create_sandboxes').click(function(){ $('#cx_create_sandboxes, #cx_user_id, #cx_canvas101').attr('disabled','disabled'); var userID_array = csvOrNot($('#cx_user_id').val()); var alsoCanvas101 = $('#cx_canvas101').val(); sandboxCreate(userID_array,alsoCanvas101); }); }else if(document.location.pathname.toLowerCase() === "/cxtools5") { _cx_tools_on = true; document.title="CX Tools - Create Trust"; $('#main').html('

Trust Account









Console Log

Useful links;


'); // When the user clicks "Create trust" $('#cx_createTrust').click(function(e){ e.preventDefault(); updateConsoleLog('Start creating trust...'); //disbaled the button and fields $('#cx_createTrust, #cx_trustID, #cx_shard').attr('disabled','disabled'); //action the function to create the trust var trustID = $('#cx_trustID').val(); var shardID = $('#cx_shard').val(); createTrust(trustID,shardID); return 0; }); //List trusts attached to the Canvas $('#cx_ListTrust').click(function(e){ e.preventDefault(); updateConsoleLog('Checking trusts...'); $('#cx_ListTrust').attr('disabled','disabled'); listTrusts(); }); } //link to the IC support page within the Canvas help $($('#global_nav_help_link').parent()).click(function() { //check to see if the link has been made, as the canvas help only renders on the help link click! if ($('#cx_icSupportLink').length === 0) { var buildIcLink = []; var linkURL = "https://s3.amazonaws.com/SSL_Assets/APAC/ticketpage.html"; //get the account object information var settings = { "async": true, "crossDomain": false, "url": "/api/v1/accounts/self", "method": "GET", "headers": { "cache-control": "no-cache", } }; $.ajax(settings).done(function(response) { buildIcLink = { cxtools: true, name: response.name, currentURL: document.location.toString(), DOMAIN_ROOT_ACCOUNT_ID: ENV.DOMAIN_ROOT_ACCOUNT_ID, CONTEXT_BASE_URL: ENV.CONTEXT_BASE_URL, TIMEZONE: ENV.TIMEZONE, //currentAccount: ENV.ACCOUNT.id, //looks like this doesnt always exist current_user_id: ENV.current_user_id, documentTitle: document.title, }; //build the support link URI linkURL = buildURI(buildIcLink, linkURL); console.log(linkURL); $('#help_tray > ul:first > li:first').before('
  • IC Support
  • '); }); } return; }); //if within a course if(document.location.pathname.toLowerCase().indexOf('/courses/') >= 0){ // Add button to take user back to courses list for root account $('div.ic-app-nav-toggle-and-crumbs > div.right-of-crumbs').append(' View all courses'); if(document.location.pathname.toLowerCase() === "/courses/" + ENV.course_id){ _cx_tools_on = true; //If on the homepage of the course //Settings link above the options on RHS $('#course_show_secondary > div.course-options > a.btn.button-sidebar-wide.course-home-sub-navigation-lti:last').before(' Course Settings'); //Undelete option $('#course_show_secondary > div.course-options > a.btn.button-sidebar-wide.course-home-sub-navigation-lti:last').before(' Undelete Course Content'); } } if ( document.location.pathname.match(re_perms) !== null ) { _cx_tools_on = true; // change each header to be no longer than 18 characters followed by an ellipses - but only call the function once the table has been loaded waitForKeyElements("table.ic-permissions__table", fix_permission_header); } // Turn on ribbon if a page has modification through the CX Tools if (_cx_tools_on == true) { // put the banner div after the body $('body').prepend('
    CX Tools ON
    '); } // Display a warning so that users know to configure their access token if (token === null || (typeof token === "string" && token.length === 0)) { $('body').prepend('
    NO ACCESS TOKEN CONFIGURED
    '); } }); // ELSE if on the IC request page } else if (document.location.hostname === "s3.amazonaws.com") { if (typeof jQuery == 'undefined' || typeof jQuery === undefined || typeof jQuery === null) { var headTag = document.getElementsByTagName("head")[0]; var jqTag = document.createElement('script'); jqTag.type = 'text/javascript'; jqTag.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'; headTag.appendChild(jqTag); jqTag.onload = myJQueryCode; }else{ myJQueryCode(); } function myJQueryCode() { $(document).ready(function() { //document title and favicon document.title="APAC IC Support"; (function() { var link = document.querySelector("link[rel*='icon']") || document.createElement('link'); link.type = 'image/x-icon'; link.rel = 'shortcut icon'; link.href = 'http://www.favicon.cc/logo3d/170779.png'; document.getElementsByTagName('head')[0].appendChild(link); })(); //fix up some formating $('.form-control:not(:last)').css({"display":"-webkit-inline-box","width":"inherit","max-width":"100%", "height": "inherit","padding":"inherit"}); $('.help-block, #other_details_chars_label').hide(); $('.form-horizontal, .form-group').css({'margin-right':'inherit','margin-left':'inherit'}); var icSupportObject = getUrlVars(); //if done via CX Tools if (icSupportObject.cxtools == "true") { console.log('gg'); //fill out the title field $('#school_name').val(icSupportObject.name); //fill the URL field $('#canvas_URL').val(icSupportObject.currentURL); //create the support details string var supportDetails = JSON.stringify(icSupportObject); supportDetails = supportDetails.split('","').join('\n').split('":"').join(' : ').split('"}').join('').split('{"').join('').trim(); $('#other_details').val('\n\n\n===================================\n' + supportDetails); } }); } }else if(window.location.hostname === "instructure.my.salesforce.com"){ //If in Salesforce, load some of the salesforce stuff if($('div.pbBody table:contains("Contact Status")').length > 0 || $('h2.mainTitle').text() === "Account Detail"){ buildTheContactsTableUI(); if($('h2.mainTitle').text() === "Account Detail"){ setTimeout( function() { console.log('here'); buildTheContactsTableUI(); }, 5000 ); } }else if(document.location.pathname.toLowerCase() === "/cxtools3") { //Once on the create users page var urlVars = getUrlVars(); if(urlVars.sfUsers == "true"){ var splitUsers = urlVars.userData.split('|'); $.each(splitUsers,function(){ var thisUser = this.split('~'); if(thisUser[0]!="undefined" && thisUser[0]!="" && thisUser[1]!="undefined" && thisUser[1]!="" && thisUser[2]!="undefined" && thisUser[2]!=""){ $('#cx_first_name').val($('#cx_first_name').val() + thisUser[0] + '\n'); $('#cx_last_name').val($('#cx_last_name').val() + thisUser[1] + '\n'); $('#cx_user_id').val($('#cx_user_id').val() + thisUser[2] + '\n'); $('#cx_login_id').val($('#cx_login_id').val() + thisUser[2] + '\n'); $('#cx_email').val($('#cx_email').val() + thisUser[2] + '\n'); } }); } } } // ============== My functions ===================== //get all the LTIs installed function listLtiID(canvas_account_id){ var form = new FormData(); var settings = { "url": "/api/v1/accounts/" + canvas_account_id + "/external_tools?per_page=100", "method": "GET", "timeout": 0, "headers": { "Authorization": "Bearer " + userToken }, "processData": false, "mimeType": "multipart/form-data", "contentType": false, "data": form }; $.ajax(settings).done(function (response) { console.log(response); var apiReply = JSON.parse(response); if(apiReply.length > 0){ $.each(apiReply,function(index,element){ console.log(element); $("td.external_tool.e-tool-table-data[title='"+ element.name.replace(/[']/g, '\\$&') + "']").append(' - LTI ID #' + element.id); }); //add the hide button too var buildHideButton = '
    '; $('div.Header > div > p:last').after(buildHideButton); $("#cx_hideLTI_submit").click(function(e){ e.preventDefault(); $("#cx_hideLTI_submit").attr('disabled','disabled'); if(confirm("Are you sure you want to do this?! It cannot be undone!") === true) hideElement(); }); } }); } //function to hide and rename an LTI based on the LTI's ID within the Canvas function hideElement(){ var data = new FormData(); var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function() { if(this.readyState === 4) { console.log(this.responseText); //refresh the page after success location.replace("/accounts/self/settings/configurations#tab-tools"); window.location.href = window.location.origin + "/accounts/self/settings/configurations#tab-tools"; } }); var xhrBuild = "/api/v1/accounts/1/external_tools/" + $('input#lti_id').val(); xhrBuild += "?course_navigation%5Benabled%5D=false&account_navigation%5Benabled%5D=false&user_navigation%5Benabled%5D=false&course_home_sub_navigation%5Benabled%5D=false&editor_button%5Benabled%5D=false&homework_submission%5Benabled%5D=false&link_selection%5Benabled%5D=false&migration_selection%5Benabled%5D=false&tool_configuration%5Benabled%5D=false&resource_selection%5Benabled%5D=false&global_navigation=false&assignment_selection=false&collaboration=false" if($('input#lti_id').val() !== null){ xhrBuild+= "&name="; xhrBuild+= encodeURI($('input#lti_name').val()); } xhr.open("PUT", xhrBuild); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.send(data); } //Add the show LTIs button on the settings page //users must first be on the page before pressing the button const re_settings=/\/accounts\/(\d+|self)\/settings/; var settings_match = document.location.pathname.toLowerCase().match(re_settings); if ( settings_match !== null ) { $('nav#breadcrumbs').after('
    '); $("#cx_listLti_ID").click(function(e){ e.preventDefault(); $("#cx_listLti_ID").attr('disabled','disabled'); listLtiID(settings_match[1]); return 0; }); } function storeItem(storeName, storeValue) { storeValue = btoa(storeValue); //localStorage.setItem(storeName, storeValue); GM_setValue(storeName, storeValue); //console.log("Encoded name: " + storeName + "\nEncoded Value: " + storeValue); return true; } function getItem(itemName) { //var retrievedObject = localStorage.getItem(itemName); var retrievedObject = GM_getValue(itemName, null); if (retrievedObject !== null) retrievedObject = atob(retrievedObject); //console.log("Decoded itme Name: " + itemName + "\nDecoded value: " + retrievedObject); return retrievedObject; } function update_sis_id(userArray, sisOrNot) { //itterate through the array of canvas IDs $.each(userArray, function(index, element) { var settingsGET = { "async": true, "url": "/api/v1/users/"+ sisOrNot + element.old + '/logins/', "method": "GET", "headers": { "authorization": "Bearer " + userToken, "cache-control": "no-cache" }, "error": function(jqXHR, textStatus, errorThrown) { if (jqXHR.status == 404 || errorThrown == 'Not Found') { console.log("Error: " + jqXHR.status + " - User not found: " + element.old); $('#cx_console_log').val("Error: " + jqXHR.status + " - User not found: " + element.old + " \n" + $('#cx_console_log').val()); } } }; $.ajax(settingsGET).done(function(response) { var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function() { if (this.readyState === 4) { console.log("Completed id update for: " + this.responseText); $('#cx_console_log').val("Completed id update for: " + element.new + " [" + element.old + "]\n" + $('#cx_console_log').val()); } }); xhr.open("PUT", "/api/v1/accounts/self/logins/" + response[0].id + encodeURI("?login[sis_user_id]=") + element.new); xhr.setRequestHeader("authorization", "Bearer " + userToken); xhr.setRequestHeader("cache-control", "no-cache"); xhr.send(data); console.log("Processing for: " + element.new + "[" + element.old + "]"); $('#cx_console_log').val("Processing for: " + element.new + "[" + element.old + "]\n" + $('#cx_console_log').val()); }); }); } //build the URI string from the object array function buildURI(passedObject, baseURL) { var str = "?" + Object.keys(passedObject).map(function(prop) { return [prop, passedObject[prop]].map(encodeURIComponent).join("="); }).join("&"); if (baseURL === null || baseURL === undefined || baseURL === '' || baseURL === 'undefined') return str; else return baseURL + str; } //Get parametrs from url function getUrlVars(url) { //if no variable, set it to the URL if (url === undefined) { url = window.location.href; } var vars = {}; var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) { vars[key] = decodeURIComponent(value); }); return vars; } //determine if the text area is new line or csv and return an array function csvOrNot(theTextArea){ var newArray = theTextArea.trim(); if(newArray.indexOf('\n') > newArray.indexOf(',')){ newArray = newArray.split(' \n').join('\n'); newArray = newArray.split('\n ').join('\n'); newArray = newArray.split('\n'); return newArray; }else { newArray = newArray.split(' ,').join(','); newArray = newArray.split(', ').join(','); newArray = newArray.split(','); return newArray; } } // Install LTIs that use URL Install function installLTI(name, consumer_key, shared_secret, config_url, canvas_lti_url, button_trigger) { var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; if(canvas_lti_url === null || canvas_lti_url === undefined){ canvas_lti_url = ""; } //Build the API Call var apiURL = canvas_lti_url + "/api/v1/accounts/self/external_tools?name="; apiURL += encodeURI(name) + "&privacy_level=public&consumer_key="; apiURL += encodeURI(consumer_key) + "&shared_secret=" + encodeURI(shared_secret); apiURL += "&tool_configuration[enabled]=true&config_type=by_url&config_url=" + encodeURI(config_url); console.log("API URL: " + apiURL + "\n"); xhr.open("POST", apiURL); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.send(data); xhr.onload = function() { if ( xhr.status != 200 ) { alert(`${xhr.status}: ${xhr.statusText}`); } $(button_trigger).removeAttr("disabled"); $('#cx_processing').hide(); // Show the user something $(button_trigger).parent().append(' LTI installed '); // LTI specific code can go here if required // If the LTI is Canvas Commons, there is one more step so present the link to head on over and complete that step if ( name.match('Canvas Commons') != null ) { $(button_trigger).parent().append(' — now complete configuration via root account settings/apps area'); } }; } // enable an inherited LTI developer key // Note: this will install the LTI, unless install_lti == false function enableLTIKeyandInstallLTI(client_id, button_trigger, install_lti = true, s_func = null) { // relative to the domain of the Canvas instance being browsed var apiURL = '/api/v1/accounts/self/developer_keys/' + client_id + '/developer_key_account_bindings'; // JSON body var payload = JSON.stringify({developer_key_account_binding:{workflow_state:'on'}}); // debugging // alert('enableLTIKey(): apiURL == ' + apiURL); // alert('enableLTIKey(): payload == ' + payload); $.ajax({ type: "POST", url: apiURL, headers: { "Authorization": "Bearer " + userToken, "Cache-Control": "no-cache", }, data: payload, contentType: "application/json; charset=utf-8", dataType: "json", success: function(response) { console.log('successfully enabled developer LTI key: ' + client_id); parsed_response = $.parseJSON(JSON.stringify(response)); console.log('developer LTI key: ' + parsed_response.workflow_state); if ( install_lti == true ) { // debugging // alert('at this point make a HTTP POST request to install the app/LTI'); installLTIviaClientID(client_id, button_trigger); } else { $(button_trigger).removeAttr("disabled"); $('#cx_processing').hide(); $(button_trigger).parent().append(' developer key (' + client_id + ') enabled'); // call additional "success function" if one supplied if ( s_func != null ) { s_func(button_trigger); } } }, error: function(e) { console.log(e); console.log(JSON.parse(e.responseText)); json_msg = $.parseJSON(e.responseText); var err_msg = json_msg['errors']['base']; console.log('Unable to enable developer LTI key: ' + err_msg); } }); } // install LTI via client_id function installLTIviaClientID(client_id, button_trigger) { // relative to the domain of the Canvas instance being browsed var apiURL = '/api/v1/accounts/1/external_tools/'; // debugging // alert('installLTIviaClientID(): client_id == ' + client_id); $.ajax({ type: "POST", url: apiURL + '?' + $.param({client_id: client_id}), headers: { "Authorization": "Bearer " + userToken, "Cache-Control": "no-cache", }, success: function(response) { console.log('successfully installed external tool (aka LTI)'); parsed_response = $.parseJSON(JSON.stringify(response)); console.log('name of installed LTI: ' + parsed_response.name); $(button_trigger).removeAttr("disabled"); $('#cx_processing').hide(); $(button_trigger).parent().append(' LTI "' + parsed_response.name + '" installed'); }, error: function(e) { console.log(e); console.log(JSON.parse(e.responseText)); json_msg = $.parseJSON(e.responseText); var err_msg = json_msg['errors']['base']; console.log('Unable to install external tool: ' + err_msg); } }); } // Note: this are very specific to the Credentials button function handle_credentials_api_key_enable(button_trigger) { var lti_span; lti_span=$(button_trigger).parent().find("span:nth-of-type(1)").css('padding', '0.25rem').css('background-color','lightgreen').css('color', 'white'); $(lti_span).find("input").prop('checked', true); } // Note: this are very specific to the Credentials button function handle_credentials_lti_key_enable(button_trigger) { var lti_span; lti_span=$(button_trigger).parent().find("span:nth-of-type(2)").css('padding', '0.25rem').css('background-color','lightgreen').css('color', 'white'); $(lti_span).find("input").prop('checked', true); } //Import Outcomes Function function outcomesAPI(guid){ var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { console.log(this.responseText); alert("The outcomes are being imported. This may take 24/48hrs to show up in the client's instance.\n" + this.responseText); } }); xhr.open("POST", "/api/v1/global/outcomes_import?guid=" + encodeURI(guid)); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.send(data); } function createUsers(newUserArray, notifyCheck){ updateConsoleLog('Start creating users'); //updateConsoleLog(newUserArray); $.each(newUserArray, function(i,e) { updateConsoleLog('Processing user: ' + e.full_name + ' [' + e.user_id + ']'); //API Call var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; //What do do upon call competion xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { //if there is an error if(this.responseText.toLowerCase().indexOf('error') >=0 ){ updateConsoleLog("Failed to create user: " + e.full_name + ' [' + e.user_id + '] with error message\n' + this.responseText); }else{ //No errors (One hopes!) updateConsoleLog("Completed user: " + e.full_name + ' [' + e.user_id + '] ');//& Canvas ID = ' + this.responseText.id); } console.log(this.responseText); return this.responseText; }/*else if(this.readyState === 404){ updateConsoleLog("Error Message: " + this.responseText); console.log(this.responseText); }*/ }); //Build Post Call var postCall = "/api/v1/accounts/self/users?user[name]=" + encodeURIComponent(e.full_name); postCall += "&user[skip_registration]="+!notifyCheck; postCall += "&pseudonym[send_confirmation]="+notifyCheck; //postCall += "&pseudonym[force_self_registration]=" + notifyCheck; postCall += "&pseudonym[unique_id]=" + encodeURIComponent(e.login_id); postCall += "&pseudonym[sis_user_id]=" + encodeURIComponent(e.user_id); if(e.auth_id != "") postCall += "&pseudonym[authentication_provider_id]=" + encodeURIComponent(e.auth_id); if(!notifyCheck)postCall += "&communication_channel[skip_confirmation]=true"; postCall += "&communication_channel[type]=email&communication_channel[address]=" + encodeURIComponent(e.email); postCall += "&enable_sis_reactivation=true"; console.log("Create user PostCall: " + postCall); xhr.open("POST", postCall); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.send(data); }); } function updateConsoleLog(newVal){ $('#cx_console_log').val(timeStamp() + " | " + newVal + "\n" + $('#cx_console_log').val()); } function timeStamp() { var now = new Date(); var currentMonth = now.getMonth() + 1; if (currentMonth < 10) currentMonth = "0" + currentMonth; var date = [ now.getDate(), currentMonth, now.getFullYear() ]; var time = [ now.getHours(), now.getMinutes(), now.getSeconds() ]; var suffix = ( time[0] < 12 ) ? "AM" : "PM"; time[0] = ( time[0] < 12 ) ? time[0] : time[0] - 12; time[0] = time[0] || 12; for ( var i = 1; i < 3; i++ ) { if ( time[i] < 10 ) { time[i] = "0" + time[i]; } } return date.join("/") + " " + time.join(":") + " " + suffix; } function createCanvasCourse(courseCode,courseID,accountID,longName,userID){ updateConsoleLog("Begin create "+longName+" ["+courseID+"]..."); var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { console.log(this.responseText); //If ther user ID is null, then it's for create Canvas101 if(this.responseText.toLowerCase().indexOf('error') >=0 ){ updateConsoleLog("Failed to course create: " + longName + " [" + courseID +"] with error message\n" + this.responseText); }else{ if(userID === null){ updateConsoleLog("Created Canvas101 with message: " + this.responseText); //alert(this.responseText); window.open("/courses/sis_course_id:canvas101/settings","_blank"); return this.responseText; }else{ //If user ID is not Null, then its for Enrollment updateConsoleLog("Completed course create: " + longName + " [" + courseID +"]"); enrollUser(userID,courseID,"TeacherEnrollment"); } } } }); var buildPost = "/api/v1/accounts/sis_account_id:" + encodeURIComponent(accountID); buildPost +="/courses?course[name]=" + encodeURIComponent(longName); buildPost += "&course[course_code]=" + encodeURIComponent(courseCode); buildPost += "&course[sis_course_id]=" + encodeURIComponent(courseID); xhr.open("POST", buildPost); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.send(data); } function createSandboxAccount(){ // /api/v1/accounts/:account_id/sub_accounts updateConsoleLog('Begin create Sandbox account...'); var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { if(this.responseText.toLowerCase().indexOf('error') >=0 ){ updateConsoleLog("Failed to create Sandbox Account with message: " + this.responseText); }else { //console.log(this.responseText); updateConsoleLog("Completed Sandbox Account with message: " + this.responseText); } return this.responseText } }); var buildPost = "/api/v1/accounts/1/sub_accounts?account[name]=" + encodeURIComponent('Sandbox'); buildPost += "&account[sis_account_id]=" + encodeURIComponent('sandbox'); xhr.open("POST", buildPost); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.send(data); } function sandboxCreate(sandboxUserArray,canvas101){ $.each(sandboxUserArray,function(user_index,user_element){ if(canvas101 == "true"){ enrollUser(user_element,"canvas101","StudentEnrollment"); } var sandboxCourseCode = "My Sandbox"; var sandboxCourseID = user_element+"_sandbox"; var sandboxAccountID = "sandbox"; var userDisplayName = getUsersFullName(user_element); //console.log('Display name: ' + userDisplayName); var sandboxLongName = userDisplayName + "'s Sandbox Course"; //console.log('Course long name: ' + sandboxLongName); createCanvasCourse(sandboxCourseCode,sandboxCourseID,sandboxAccountID,sandboxLongName,user_element); }); } function enrollUser(user_id,course_id,role){ updateConsoleLog('Begin enrolling user: ' + user_id + "; For course: " + course_id + "[" + role +"]"); var data = null; var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { //console.log(this.responseText); if(this.responseText.toLowerCase().indexOf('error') >=0 ){ updateConsoleLog('Failed enrolling user: ' + user_id + "; For course: " + course_id + "[" + role +"] with message\n" + this.responseText); }else{ updateConsoleLog('Completed enrolling user: ' + user_id + "; For course: " + course_id + "[" + role +"]"); } } }); var buildPost = "/api/v1/courses/sis_course_id:" + encodeURIComponent(course_id); buildPost += "/enrollments?enrollment[user_id]=sis_user_id:" + encodeURIComponent(user_id); buildPost += "&enrollment[type]=" + encodeURIComponent(role); buildPost += "&enrollment[enrollment_state]=active"; xhr.open("POST", buildPost); xhr.setRequestHeader("Authorization", "Bearer " + userToken); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.send(data); } // Create trust function function createTrust(targetID,shardID){ // build Post URL // Example post: "https://apaccs.instructure.com/api/v1/accounts/13677~1/trust_links?trust_link%5Bmanaging_account_id%5D=16292~1" var buildPost = "/api/v1/accounts/"; // add this accounts ID buildPost += ENV.DOMAIN_ROOT_ACCOUNT_ID; buildPost += "/trust_links"; $.ajaxSetup({ headers:{ "Authorization": "Bearer " + userToken, "Cache-Control": "no-cache", } }); var trust_data = 'trust_link[managing_account_id]=' + targetID + "~" + shardID; console.log(trust_data); $.ajax({ url: buildPost, type: 'POST', data: trust_data, success: function(response) { console.log("success"); console.log(response); updateConsoleLog('Success! Created Trust - ID:' + response['id']); }, error: function(e) { console.log(e); console.log(JSON.parse(e.responseText)); json_msg = jQuery.parseJSON(e.responseText); var err_attr = json_msg['errors']['managed_role_id'][0]['attribute']; var err_msg = json_msg['errors']['managed_role_id'][0]['message']; updateConsoleLog('Unable to create trust: ' + err_attr + ' - ' + err_msg); }, dataType: "json" }); } function listTrusts(){ var buildPost = "/api/v1/accounts/"; buildPost += ENV.DOMAIN_ROOT_ACCOUNT_ID; buildPost += '/trust_links'; $.ajaxSetup({ headers:{ "Authorization": "Bearer " + userToken, "Cache-Control": "no-cache", "Accept": "application/json+canvas-string-ids" } }); $.get( buildPost, function( data ) { console.log("success"); updateConsoleLog('API call success! Now listing IDs of trusted Canvi: (above - can take a little while)'); console.log("length of data is " + data.length); if ( data.length == 0 ) { updateConsoleLog('No trusts found') } else { // Get details (i.e. name of each trusted instance) // "/api/v1/accounts/"; // console.log(json_resp); $.each(data, function( key, value ) { // console.log(value); $.get( "/api/v1/accounts/" + value.managing_account_id, function( data ) { console.log("success"); updateConsoleLog(JSON.stringify(value)); updateConsoleLog('ID: ' + value.id + ' Name: ' + data.name); }, 'json') .fail(function() { console.log("error"); updateConsoleLog('Unable to get account name for "' + value.managing_account_id + '"'); }); }); } }, 'json') .fail(function() { console.log("error"); updateConsoleLog('Unable to get trusts: ' + data); }); } function getUsersFullName(sisUserId){ var returnName; // ===== AJAX === var settings = { url: "/api/v1/users/sis_user_id:" + encodeURI(sisUserId), method: "GET", timeout: 0, async: false, cache: false, headers: { Authorization: "Bearer " + userToken } }; $.ajax(settings).done(function (response) { returnName = response.name; //updateConsoleLog('Users name:' + returnName); }); return returnName; } //======== Begin Google / Office LTI Auto Install ======== //read the ? part and add to action form for URL //https://office365-syd-prod.instructure.com/lti_credentials/new // if(document.location.pathname === "/lti_credentials/new" || document.location.hostname.indexOf("office365")>=0){ $(document).ready(function(){ var getCanvasURL = getUrlVars(); // Get the Canvas URL from the paramters //Inster the Canvas as a paramter of the action to display on the next page with the key/secret information $('form').attr('action',$('form').attr('action') + "?canvasurl=" + getCanvasURL.canvasurl); }); } //create the function for the Office 365 and or Google LTI to auto install if(document.location.pathname === "/lti_credentials"){ var headTag = document.getElementsByTagName("head")[0]; var jqTag = document.createElement('script'); jqTag.type = 'text/javascript'; jqTag.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'; headTag.appendChild(jqTag); jqTag.onload = myJQueryCode; $(document).ready(function(){ var getCanvasURL = getUrlVars(); //Get the Canvas URL from the paramaters that have been passed above var canvasDestinationUrl = ""; //check to see if there are paramters, else set the value to null if(getCanvasURL.canvasurl === undefined || getCanvasURL.canvasurl === null){ canvasDestinationUrl = ""; }else{ canvasDestinationUrl = getCanvasURL.canvasurl; } //pull the key / secret / XML from the webpage var ltiKey = $('#lti-key').text(); var ltiSecret = $('#lti-secret').text(); var ltiXML = $('#lti-config').text(); //Get the display name of the LTI var ltiName = $('div.text-center.bold:first').text(); ltiName = ltiName.split('Your Key for ').join(''); ltiName = ltiName.split(' is').join(''); ltiName = ltiName.trim(); //console debug console.log("Name = " + ltiName); console.log("Key = " + ltiKey); console.log("Secret = " + ltiSecret); console.log("XML = " + ltiXML); // Add the button at the bottom of the page $('body').append('
    https://.instructure.com/

    API Token = ' + userToken + '...
    '); //Create the event tigger when the user clicks the Send LTI to Canvas Button $('#sendToCanvas_button').click(function(e){ //Prevent default action e.preventDefault(); //disable button and input field $('#sendToCanvas_button,#sendToCanvas_url').attr('disabled',true); $('#sendToCanvas_button,#sendToCanvas_url').attr('style','cursor: not-allowed;pointer-events: none;opacity: 0.5;'); //Calculate the destination URL var ltiDestination = $('#sendToCanvas_url').val(); if(ltiDestination === null || ltiDestination === undefined){ //If destiantion is not there - Tell user and exit function alert("No URL found!\nRefresh the page and try again..."); return; }else{ //If the URL is there, continue to calculate the URL ltiDestination = "https://" + ltiDestination + ".instructure.com"; console.log('Canvas Destination: ' + ltiDestination) //build the paramters URL ltiDestination += "/accounts/self/settings/configurations#tab-tools?cx_installLTI=true"; ltiDestination += "<iName=" + encodeURI(ltiName); ltiDestination += "<iKey=" + encodeURI(ltiKey); ltiDestination += "<iSecret=" + encodeURI(ltiSecret); ltiDestination += "<iXML=" + encodeURI(ltiXML); console.log('Canvas URL for LTI creation: '+ ltiDestination) //Head to the LTI install page to complete the installation var win = window.open(ltiDestination, '_blank'); } }); }); } //now on the LTI config Settings if(document.location.pathname === "/accounts/self/settings/configurations"){ var ltiURLvals = getUrlVars(); if(ltiURLvals.cx_installLTI === undefined || ltiURLvals.cx_installLTI === null){ console.log('No LTI to install'); }else{ alert("Installing LTI: " + ltiURLvals.ltiName + "\nClick 'OK' and the page will refresh with the LTI Installed"); //console log the LTI Values console.log("Name = " + ltiURLvals.ltiName); console.log("Key = " + ltiURLvals.ltiKey); console.log("Secret = " + ltiURLvals.ltiSecret); console.log("XML = " + ltiURLvals.ltiXML); //Call the Install LTI function installLTI(ltiURLvals.ltiName,ltiURLvals.ltiKey,ltiURLvals.ltiSecret,ltiURLvals.ltiXML); location.replace("https://" + window.location.hostname + "/accounts/self/settings/configurations#tab-tools"); } } //======== End Google / Office LTI Auto Install ======== var headTag = document.getElementsByTagName("head")[0]; var jqTag = document.createElement('script'); jqTag.type = 'text/javascript'; jqTag.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'; headTag.appendChild(jqTag); jqTag.onload = myJQueryCode; } function openInNewTab(url) { var win = window.open(url, '_blank'); win.focus(); } function getUsers(){ var contactTable = $('div.pbBody table:contains("Contact Status") tr:not(:first):has(:checkbox:checked)'); var contactArray = []; var userArrayString =""; for(var i=0; i < contactTable.length; i++){ var firstName; var lastName; var email; var checkEmail; checkEmail = $('td:eq(2)',contactTable[i]).text(); email = checkEmail.toString(); checkEmail = email.split('[Gmail]').join(''); email = checkEmail.trim(); if(email != ""){ var name = $('th',contactTable[i]).text(); //if the name doesnt have a "," to seperate the names if(name.indexOf(',')<0){ firstName = name; lastName = name; }else { var splitName = name.toString().split(', '); lastName = splitName[0]; lastName = lastName.trim(); firstName = splitName[1]; firstName = firstName.trim(); } var jsonPush = {"firstName":firstName, "lastName":lastName, "email":email} userArrayString = userArrayString + firstName + "~" + lastName + "~" + email + "|"; //contactArray.push(jsonPush); }//*/ } //console.log(userArrayString); return userArrayString; } function buildTheContactsTableUI(){ //Put the action box at the top if($('h2.mainTitle').text() === "Account Detail"){ $('div.listRelatedObject.contactBlock input[value="New Contact"]').after(''); }else{ $('div.pbHeader:first').after(''); } //put the checkboxes in $('#bodyCell div.pbBody table:contains("Contact Status") th.actionColumn').prepend(''); //Master checkbox //user array $('#bodyCell div.pbBody table:contains("Contact Status") td.actionColumn').prepend(''); //function to check, or uncheck all based on the master checkbox $('#cx_checkUsersMaster').change(function(e){ e.preventDefault(); //console.log('here'); var checkBoxes = $('input.cx_checkUsers:not(:first)'); checkBoxes.prop("checked", !checkBoxes.prop("checked")); }); $('#cx_userToCanvas').click(function(e){ $('#cx_canvasURL, #cx_userToCanvas, input.cx_checkUsers').attr('disabled','disabled'); e.preventDefault(); //sessionStorage.setItem('userArrayString',getUsers()); //Local storage doesnt seem to be working adding it to the link var userString = getUsers(); userString = userString.trim(); userString = encodeURI(userString); var buildCanvasURL = "https://" + $('#cx_canvasURL').val() + ".instructure.com/cxtools3?sfUsers=true&userData=" + userString; openInNewTab(buildCanvasURL); }); } // shorten some text to textLength long and add an ellipses function shorten(text, textLength){ if(text.length > textLength){ text = text.substring(0, textLength) + '…'; } return text; } function fix_permission_header() { var existing_label; var new_label; // very specific selector $('table.ic-permissions__table > thead > tr.ic-permissions__top-header > th.ic-permissions__top-header__col-wrapper-th > div > div > span > button > span').each(function(i, obj) { existing_label = $(this).text(); new_label = shorten(existing_label, 18); $(this).html(new_label); }); } function append_feature_details(node) { const admin_shield_svg = ''; node.append('
    ' + admin_shield_svg + ' Canvas Feature Option Summary
    '); } // 20231006 - can't get this to fire at the correct time - really needs to be supplied by the underling code /* function append_feature_account_details(node) { // attempting to append a feature $('#tab-features > div > table > tbody > tr > td > div > button > span > span:contains("Account and Course Level Outcome Mastery Scales")').closest('div').find('div > div > div').append('
    feature definition'); alert('in append_feature_account_details()') } */ // vim:expandtab ts=4 sw=4