diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..39e5ada2ba2a1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [support@code.org](mailto:support@code.org). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 001f7140e167f..57d5dfb102562 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,9 @@ We'd love to have you join our group of contributors! Please e-mail your areas of interest and your availability to contributing@code.org, and we’ll be happy to match you with a project. -This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code. +This project adheres to the [Contributor Covenant][code-of-conduct]. By participating, you are expected to honor this code. -[code-of-conduct]: https://www.contributor-covenant.org/ +[code-of-conduct]: CODE_OF_CONDUCT.md You can start setting up with these next steps: diff --git a/apps/i18n/common/en_us.json b/apps/i18n/common/en_us.json index 8c32c5f70bb3d..e0f55762e4a99 100644 --- a/apps/i18n/common/en_us.json +++ b/apps/i18n/common/en_us.json @@ -49,7 +49,6 @@ "answerOptionF": "F", "answerOptionG": "G", "answersVisible": "Answers visible (read-only)", - "archiveSection": "Archive Section", "applabMarketingButton": "Learn more", "applabMarketingDesc": "See sample projects, watch demos, and learn more about what you can do with App Lab.", "applabMarketingTitle": "Learn about App Lab", @@ -59,6 +58,7 @@ "applabTutorialButton": "Start", "applabTutorialDesc": "Ready to try JavaScript? Design an app, code in JavaScript with either blocks or text, then share your app in seconds. For Ages 13+.", "applabTutorialTitle": "App Lab Hour of Code", + "archiveSection": "Archive Section", "assessmentSteps": "Steps to give assessment for", "assessmentSettings": "Assessment Settings", "assign": "Assign", @@ -610,6 +610,7 @@ "hiddenSections": "Hidden Sections", "hiddenScriptTooltip": "Please select a section before trying to toggle whether or not the unit is visible to your students.", "hide": "Hide", + "hideArchivedSections": "Hide archived sections", "hideFullList": "Hide full list", "hideGeneratedCode": "Hide Code", "hideHiddenSections": "Hide hidden sections", @@ -1013,6 +1014,7 @@ "resetPassword": "Reset password", "resources": "Resources", "response": "Response", + "restoreSection": "Restore Section", "restoreThisVersion": "Restore this Version", "review": "Review", "reviewCode": "Review Code", @@ -1255,6 +1257,7 @@ "viewAllAnnouncements": "View all announcements", "viewAllCourses": "View all courses", "viewAllSections": "View all sections", + "viewArchivedSections": "View archived sections", "viewCode": "View code", "viewCourse": "View course", "viewCourses": "View courses", diff --git a/apps/i18n/common/it_it.json b/apps/i18n/common/it_it.json index e6fd7c3ff7d4c..002c15d69d50c 100644 --- a/apps/i18n/common/it_it.json +++ b/apps/i18n/common/it_it.json @@ -67,7 +67,7 @@ "assignConfirm": "Sei sicuro di voler assegnare \"{assignmentName}\" a \"{sectionName}\"?", "assignedTo": "Assegnato a", "assignUnit": "Assegna Unità", - "authorizeGoogleClassrooms": "Clicca qui per autorizzare Google Classrom.", + "authorizeGoogleClassrooms": "Clicca qui per autorizzare Google Classroom.", "authorizeGoogleClassroomsText": "Prima di poter sincronizzare Google Classroom, devi dare a Code.org i permessi per accedere al tuo account Google Classroom.", "autoGenerated": "Auto-generata", "autolock": "Nota: blocco automatico del livello dopo 24 ore.", @@ -607,7 +607,7 @@ "iconSearchPlaceholder": "Cerca un'icona...", "iDontKnow": "Non lo so", "ignore": "Ignora", - "importFromGoogleClassroom": "Importa classe da Google Classrom", + "importFromGoogleClassroom": "Importa classe da Google Classroom", "importFromClever": "Importa la classe da Clever", "incorrectAnswer": "Risposta non corretta", "incorrectAnswerBody": "La risposta che hai scelto non è corretta. Per favore riprova!", diff --git a/apps/src/sites/code.org/pages/public/teacher-dashboard/index.js b/apps/src/sites/code.org/pages/public/teacher-dashboard/index.js index a6be960f1db3a..ed5358c4b245d 100644 --- a/apps/src/sites/code.org/pages/public/teacher-dashboard/index.js +++ b/apps/src/sites/code.org/pages/public/teacher-dashboard/index.js @@ -596,132 +596,12 @@ function main() { $scope.script_list = sectionsService.validScripts(); - if (experiments.isEnabled(experiments.PROGRESS_TAB)) { - $scope.react_progress = true; - $scope.$on('section-progress-rendered', () => { - $scope.section.$promise.then(script => - renderSectionProgress(script, $scope.script_list) - ); - }); - return; - } - - // The below is not run if our experiments.PROGRESS_TAB experiment is not enabled - - const paginatedPromise = paginatedSectionProgressService.get($routeParams.id) - .then(result => { - $scope.progress = result; - }) - .catch($scope.genericError); - - $scope.progressLoadedFirst = false; - $scope.progressLoaded = false; - $scope.progress_disabled_scripts = disabled_scripts; - - // wait until we have both the students and the student progress - $q.all([paginatedPromise, $scope.section.$promise]).then(function () { - $scope.mergeProgress(); - $scope.progressLoadedFirst = true; - $scope.progressLoaded = true; + $scope.react_progress = true; + $scope.$on('section-progress-rendered', () => { + $scope.section.$promise.then(script => + renderSectionProgress(script, $scope.script_list) + ); }); - - $scope.changeProgress = function (scriptId) { - $scope.progressLoadedFirst = false; - // $scope.progressLoaded = false; - - // TODO: The hide/show behavior that uses progressLoaded is - // broken on Chrome 45. I am not sure why, but the hide/show - // behavior that uses progressLoadedFirst works fine, so switching - // to using that is a good rough fix. This changes the behavior so - // that the entire table disappears and reappears instead of just - // the progress bar when using the course dropdown. - - paginatedSectionProgressService.get($routeParams.id, scriptId) - .then(result => { - $scope.progress = result; - $scope.mergeProgress(); - $scope.progressLoadedFirst = true; - $scope.progressLoaded = true; - }) - .catch($scope.genericError); - }; - - $scope.progressWidth = function () { - return $scope.page.zoom ? Math.max(34 * $scope.progress.script.levels_count, 770) : 770; - }; - - $scope.scrollToStage = function ($event) { - var doScroll = function () { - var element = $( $event.currentTarget ); - var wrapper = $('.table-wrapper'); - var LEFT_COLUMN_WIDTH = 200; // scrolling the entire table not just this col, so we have to know about the left col width - var LEFT_OFFSET = 20; // a little offset so we can see the previous stage - wrapper.animate({scrollLeft: (element.position().left - wrapper.position().left + wrapper.scrollLeft() - LEFT_COLUMN_WIDTH - LEFT_OFFSET)}, 500); - }; - - if ($scope.page.zoom) { - doScroll(); - } else { - // if we weren't already zoomed we need to zoom and then wait for the zoom to finish - $scope.page.zoom = true; - $timeout(doScroll, 500); - } - }; - - var isInCategory = function (script_list, script_id, categoryName) { - for (var i = 0; i < script_list.length; i++) { - if (script_list[i].id === script_id) { - return categoryName === script_list[i].category; - } - } - return false; - }; - - // merge the data returned by progress api into the data returned by the section students api - $scope.mergeProgress = function () { - $scope.script_id = $scope.progress.script.id; - $scope.progress_disabled = $scope.progress_disabled_scripts.indexOf($scope.script_id) !== -1; - var hocCategoryName = i18n.hoc_category_name; - $scope.is_hoc_course = isInCategory($scope.script_list, $scope.script_id, hocCategoryName); - // calculate width of each level in the progress bar assuming the overall width is 780 px - - // Takes the level's position in the script, and returns its level number in its stage - var getLevelNumberInStage = function (overallLevel) { - for (var i = 0; i < $scope.progress.script.stages.length; i++) { - var stage = $scope.progress.script.stages[i]; - if (overallLevel < stage.length) {return overallLevel + 1;} else {overallLevel -= stage.length;} - } - return 0; - }; - - // Put levels on the student object - for (var i = 0; i < $scope.section.students.length; i++) { - var student = $scope.section.students[i]; - - // default is no progress - student.levels = []; - student.highest_level = -1; // not started yet - student.highest_level_in_stage = 0; - - // if we have progress - var progress_student = $.grep($scope.progress.students, function (e) { return e.id == student.id; })[0]; - if (progress_student) { - student.levels = progress_student.levels; - - // find the last level attempted - for (var l = student.levels.length - 1; l >= 0; l--) { - if (student.levels[l] && student.levels[l].class != 'not_tried') { - var delayedSetHighestLevel = function (student, l) { - student.highest_level = l; - student.highest_level_in_stage = getLevelNumberInStage(l); - }; - $timeout(delayedSetHighestLevel.bind(this, student, l), 500); // add a delay so we get animation - break; - } - } - } - } - }; }]); app.controller('SectionResponsesController', ['$scope', '$routeParams', '$window', '$q', '$timeout', '$interval', '$sanitize', 'sectionsService', @@ -746,70 +626,10 @@ function main() { $scope.script_list = sectionsService.validScripts(); $scope.tab = 'responses'; - if (experiments.isEnabled(experiments.TEXT_RESPONSES_TAB)) { - $scope.react_text_responses = true; - $scope.$on('text-responses-table-rendered', () => { - $scope.section.$promise.then(section => renderTextResponsesTable(section, $scope.script_list)); - }); - return; - } - - $scope.responses = sectionsService.responses({id: $routeParams.id}); - // error handling - $scope.genericError = function (result) { - $window.alert("An unexpected error occurred, please try again. If this keeps happening, try reloading the page."); - }; - $scope.section.$promise.catch($scope.genericError); - $scope.sections.$promise.catch($scope.genericError); - $scope.responses.$promise.catch($scope.genericError); - - // fill in the course dropdown with the section's default course - $scope.section.$promise.then( - function (section) { - // TODO:(bjvanminnen) - also handle case where we have a course, but not - // a script assigned, likely by figuring out the first script in that course - if (section.script) { - $scope.script_id = section.script.id; - } - } - ); - - // the ng-select in the nav compares by reference not by value, so we can't just set - // selectedSection to section, we have to find it in sections. - $scope.sections.$promise.then( - function ( sections ) { - $scope.selectedSection = $.grep(sections, function (section) { return (section.id == $routeParams.id);})[0]; - } - ); - - $scope.responsesLoaded = false; - $scope.stages = []; - - // wait until we have both the students and the student progress - $q.all([$scope.section.$promise, $scope.responses.$promise]).then(function () { - $scope.responsesLoaded = true; - $scope.findStages(); + $scope.react_text_responses = true; + $scope.$on('text-responses-table-rendered', () => { + $scope.section.$promise.then(section => renderTextResponsesTable(section, $scope.script_list)); }); - - $scope.changeScript = function (scriptId) { - $scope.responsesLoaded = false; - $scope.stages = []; - - $scope.responses = sectionsService.responses({id: $routeParams.id, script_id: scriptId}); - - $scope.responses.$promise.then(function () { - $scope.responsesLoaded = true; - $scope.findStages(); - }); - }; - - $scope.findStages = function () { - $scope.stages = $.map($scope.responses, function (row) { - return row.stage; - }).filter(function (item, i, array) { // uniquify - return array.indexOf(item) == i; - }); - }; }]); @@ -858,213 +678,12 @@ function main() { $scope.surveyStages = []; $scope.surveys = sectionsService.surveys({id: $routeParams.id}); - if (experiments.isEnabled(experiments.ASSESSMENTS_TAB)) { - $scope.react_assessments = true; - $scope.$on('section-assessments-rendered', () => { - $scope.section.$promise.then(script => - renderSectionAssessments(script, $scope.script_list) - ); - }); - return; - } - - // Error handling. - $scope.genericError = function (result) { - $window.alert("An unexpected error occurred, please try again. If this keeps happening, try reloading the page."); - }; - $scope.section.$promise.catch($scope.genericError); - $scope.sections.$promise.catch($scope.genericError); - $scope.assessments.$promise.catch($scope.genericError); - - // Fill in the course dropdown with the section's default script. - $scope.section.$promise.then( - function (section) { - $scope.scriptid = section.script.id; - } - ); - - // The ng-select in the nav compares by reference not by value, so we can't just set - // selectedSection to section, we have to find it in sections. - $scope.sections.$promise.then( - function ( sections ) { - $scope.selectedSection = $.grep(sections, function (section) { return (section.id == $routeParams.id);})[0]; - } - ); - - // Wait until we have initial section, assessment, and survey data. - $q.all([$scope.section.$promise, $scope.assessments.$promise, $scope.surveys.$promise]).then(function () { - $scope.assessmentsLoaded = true; - $scope.surveysLoaded = true; - $scope.assessmentLevels = $scope.getAssessmentData($scope.assessments); - $scope.assessmentStages = $scope.findStages($scope.assessments); - $scope.surveyLevels = $scope.getSurveyData($scope.surveys); - $scope.surveyStages = $scope.findStages($scope.surveys); + $scope.react_assessments = true; + $scope.$on('section-assessments-rendered', () => { + $scope.section.$promise.then(script => + renderSectionAssessments(script, $scope.script_list) + ); }); - - // Re-retrieve assessment and survey data when the script is changed using the dropdown. - $scope.changeScript = function (scriptId) { - - // Load assessments. - $scope.assessmentsLoaded = false; - $scope.assessments = sectionsService.assessments({id: $routeParams.id, script_id: scriptId}); - $scope.assessments.$promise.then(function () { - $scope.assessmentsLoaded = true; - $scope.assessmentLevels = $scope.getAssessmentData($scope.assessments); - $scope.assessmentStages = $scope.findStages($scope.assessments); - }); - - // Load surveys. - $scope.surveysLoaded = false; - $scope.surveys = sectionsService.surveys({id: $routeParams.id, script_id: scriptId}); - $scope.surveys.$promise.then(function () { - $scope.surveysLoaded = true; - $scope.surveyStages = $scope.findStages($scope.surveys); - $scope.surveyLevels = $scope.getSurveyData($scope.surveys); - }); - }; - - $scope.findStages = function (source) { - return $.map(source, function (row) { - return row.stage; - }).filter(function (item, i, array) { // uniquify - return array.indexOf(item) == i; - }); - }; - - $scope.getAssessmentData = function (assessments) { - var results = []; - - $.each(assessments, function (index, assessment) { - - if (assessment.multi_count === 0) { - assessment.multi_correct_percent = 0; - } else { - assessment.multi_correct_percent = assessment.multi_correct / assessment.multi_count * 100; - } - assessment.status = assessment.submitted ? submission_list.submitted : submission_list.in_progress; - - // Don't show a timestamp for non-submittted assessments. - if (!assessment.submitted) { - assessment.timestamp = null; - } - - // Each LevelGroup's result has a list of the results for the levels in that order. - // Because angular's nested iterators are kind of funky when trying to generate a table, - // let's just generate a flat list of the level results to go into $scope. - $.each(assessment.level_results, function (index, level_result) { - var levelResult = { - stage: assessment.stage, - puzzle: assessment.puzzle, - question: index + 1, - student: assessment.student, - studentResult: level_result.student_result, - correct: correctness_list[level_result.correct] - }; - results.push(levelResult); - }); - }); - - return results; - }; - - $scope.getSurveyData = function (surveys) { - // The ASCII value of A. Used for rendering multiple choice captions. - var asciiForA = 65; - - var surveyResults = []; - - $.each($scope.surveys, function (surveyIndex, survey) { - - survey.status = survey.submitted ? submission_list.submitted : submission_list.in_progress; - - if (survey.levelgroup_results) { - - // Each LevelGroup's result has a list of the results for the levels in that order. - // Because angular's nested iterators are kind of funky when trying to generate a table, - // let's just generate a flat list of the level results to go into $scope. - $.each(survey.levelgroup_results, function (sublevelIndex, sublevelResults) { - var questionText = sublevelResults.question; - - // How many students answered this question? - var resultsLength = sublevelResults.results.length; - - if (sublevelResults.type == "free_response") { - // Free response: just add all of the responses. - $.each(sublevelResults.results, function (sublevelResultIndex, sublevelResult) { - // Disambiguate free responses that are unsubmitted and that are empty strings. - if (sublevelResult.result === undefined || sublevelResult.result === "") { - sublevelResult.result = null; - } - - var questionFieldText = (parseInt(sublevelIndex) + 1) + (questionText ? ". " + questionText : ""); - var resultFieldText = sublevelResult.result; - - // Only create separate rows for answers which have a result to show. - if (resultFieldText !== null) { - var levelResult = { - stage: survey.stage, - question: parseInt(sublevelIndex) + 1, - questionText: questionFieldText, - resultText: resultFieldText, - count: 1 - }; - - surveyResults.push(levelResult); - } - }); - - } else if (sublevelResults.type == "multi") { - // Multi: go through each answer and work out how many responses had that answer. - - // Store one result per possible answer. - var multiResults = []; - - // First, build a result entry for each possible answer. - $.each(sublevelResults.answer_texts, function (answerTextIndex, answerText) { - var questionFieldText = (parseInt(sublevelIndex) + 1) + (questionText ? ". " + questionText : ""); - var answerFieldText = String.fromCharCode(asciiForA + answerTextIndex) + ". " + answerText; - - var levelResult = { - stage: survey.stage, - question: parseInt(sublevelIndex) + 1, - questionText: questionFieldText, - resultText: answerFieldText, - count: 0, - percent: "0%" - }; - - multiResults[answerTextIndex] = levelResult; - }); - - // Second, go through each result and update the count for that result. - $.each(sublevelResults.results, function (sublevelResultIndex, sublevelResult) { - if ("answer_index" in sublevelResult) { - var answerIndex = sublevelResult.answer_index; - multiResults[answerIndex].count ++; - multiResults[answerIndex].percent = - (Math.round(multiResults[answerIndex].count / resultsLength * 100)) + "%"; - } - }); - - surveyResults = surveyResults.concat(multiResults); - } - }); - } - }); - - // Sort by stage, question, result text. - surveyResults.sort(function (a, b) { - if (a.stage !== b.stage) { - return a.stage.localeCompare(b.stage); - } else if (a.question !== b.question) { - return a.question - b.question; - } else { - return a.resultText.localeCompare(b.resultText); - } - }); - - return surveyResults; - }; }]); } diff --git a/apps/src/sites/studio/pages/init/loadApplab.js b/apps/src/sites/studio/pages/init/loadApplab.js index 8bc3ae363b182..3f671427b64be 100644 --- a/apps/src/sites/studio/pages/init/loadApplab.js +++ b/apps/src/sites/studio/pages/init/loadApplab.js @@ -9,5 +9,6 @@ import * as skins from "@cdo/apps/applab/skins"; export default function loadApplab(options) { options.skinsModule = skins; + options.blocksModule = {}; appMain(Applab, levels, options); } diff --git a/apps/src/templates/instructions/InstructionsDialogWrapper.jsx b/apps/src/templates/instructions/InstructionsDialogWrapper.jsx index e223b0d4c68ed..52c570bf5e330 100644 --- a/apps/src/templates/instructions/InstructionsDialogWrapper.jsx +++ b/apps/src/templates/instructions/InstructionsDialogWrapper.jsx @@ -10,25 +10,25 @@ import { connect } from 'react-redux'; * into this component, though we're moving towards getting rid of this dialog * anyways. */ -export class UnwrappedInstructionsDialogWrapper extends React.Component { - static propTypes = { +const InstructionsDialogWrapper = React.createClass({ + propTypes: { isOpen: PropTypes.bool.isRequired, autoClose: PropTypes.bool, showInstructionsDialog: PropTypes.func.isRequired - }; + }, componentWillReceiveProps(nextProps) { if (!this.props.isOpen && nextProps.isOpen) { this.props.showInstructionsDialog(nextProps.autoClose); } - } + }, render() { return null; } -} +}); export default connect(state => ({ isOpen: state.instructionsDialog.open, autoClose: state.instructionsDialog.autoClose, -}))(UnwrappedInstructionsDialogWrapper); +}))(InstructionsDialogWrapper); diff --git a/apps/src/templates/instructions/InstructionsWithWorkspace.jsx b/apps/src/templates/instructions/InstructionsWithWorkspace.jsx index 2404da1a5459f..ad441bc9f2eb4 100644 --- a/apps/src/templates/instructions/InstructionsWithWorkspace.jsx +++ b/apps/src/templates/instructions/InstructionsWithWorkspace.jsx @@ -1,9 +1,9 @@ import $ from 'jquery'; import React, {PropTypes} from 'react'; import {connect} from 'react-redux'; -import CodeWorkspaceContainer from '../CodeWorkspaceContainer'; +var CodeWorkspaceContainer = require('../CodeWorkspaceContainer'); import TopInstructions from './TopInstructions'; -import {setInstructionsMaxHeightAvailable} from '../../redux/instructions'; +var instructions = require('../../redux/instructions'); /** * A component representing the right side of the screen in our app. In particular @@ -12,40 +12,43 @@ import {setInstructionsMaxHeightAvailable} from '../../redux/instructions'; * Owns maxHeightAvailable for instructions, updating as appropriate on window * resize events */ -export class UnwrappedInstructionsWithWorkspace extends React.Component { - static propTypes = { - children: PropTypes.node, +var InstructionsWithWorkspace = React.createClass({ + propTypes: { // props provided via connect instructionsHeight: PropTypes.number.isRequired, + setInstructionsMaxHeightAvailable: PropTypes.func.isRequired, - }; + children: PropTypes.node, + }, - // only used so that we can rerender when resized - state = { - windowWidth: undefined, - windowHeight: undefined - }; + getInitialState() { + // only used so that we can rerender when resized + return { + windowWidth: undefined, + windowHeight: undefined + }; + }, /** * Called when the window resizes. Look to see if width/height changed, then * call adjustTopPaneHeight as our maxHeight may need adjusting. */ - onResize = () => { - const { - windowWidth: lastWindowWidth, - windowHeight: lastWindowHeight - } = this.state; + onResize() { const windowWidth = $(window).width(); const windowHeight = $(window).height(); // We fire window resize events when the grippy is dragged so that non-React // controlled components are able to rerender the editor. If width/height // didn't change, we don't need to do anything else here - if (windowWidth === lastWindowWidth && windowHeight === lastWindowHeight) { + if (windowWidth === this.state.windowWidth && + windowHeight === this.state.windowHeight) { return; } - this.setState({windowWidth, windowHeight}); + this.setState({ + windowWidth: $(window).width(), + windowHeight: $(window).height() + }); // Determine what the maximum size of our instructions is based off of the // size of the code workspace. @@ -59,8 +62,8 @@ export class UnwrappedInstructionsWithWorkspace extends React.Component { const DEBUGGER_RESERVE = 120; const INSTRUCTIONS_RESERVE = 150; - const {instructionsHeight, setInstructionsMaxHeightAvailable} = this.props; - const codeWorkspaceHeight = this.codeWorkspaceContainer + const instructionsHeight = this.props.instructionsHeight; + const codeWorkspaceHeight = this.refs.codeWorkspaceContainer .getWrappedInstance().getRenderedHeight(); if (codeWorkspaceHeight === 0) { // We haven't initialized the codeWorkspace yet. No need to change the @@ -76,23 +79,23 @@ export class UnwrappedInstructionsWithWorkspace extends React.Component { // we have to instructions, and the other 2/3 to the workspace maxInstructionsHeight = Math.round(totalHeight / 3); } - setInstructionsMaxHeightAvailable(maxInstructionsHeight); - }; + this.props.setInstructionsMaxHeightAvailable(maxInstructionsHeight); + }, componentDidMount() { window.addEventListener('resize', this.onResize); - } + }, componentWillUnmount() { window.removeEventListener('resize', this.onResize); - } + }, render() { return ( this.codeWorkspaceContainer = el} + ref="codeWorkspaceContainer" topMargin={this.props.instructionsHeight} > {this.props.children} @@ -100,16 +103,16 @@ export class UnwrappedInstructionsWithWorkspace extends React.Component { ); } -} +}); -export default connect(function propsFromStore(state) { +module.exports = connect(function propsFromStore(state) { return { instructionsHeight: state.instructions.renderedHeight }; }, function propsFromDispatch(dispatch) { return { setInstructionsMaxHeightAvailable(maxHeight) { - dispatch(setInstructionsMaxHeightAvailable(maxHeight)); + dispatch(instructions.setInstructionsMaxHeightAvailable(maxHeight)); } }; -})(UnwrappedInstructionsWithWorkspace); +})(InstructionsWithWorkspace); diff --git a/apps/src/templates/teacherDashboard/OwnedSections.jsx b/apps/src/templates/teacherDashboard/OwnedSections.jsx index 95fd6212528e4..1df937f866e49 100644 --- a/apps/src/templates/teacherDashboard/OwnedSections.jsx +++ b/apps/src/templates/teacherDashboard/OwnedSections.jsx @@ -120,7 +120,7 @@ class OwnedSections extends React.Component { className="ui-test-show-hide" onClick={this.toggleViewHidden} icon={viewHidden ? "caret-up" : "caret-down"} - text={viewHidden ? i18n.hideHiddenSections() : i18n.viewHiddenSections()} + text={viewHidden ? i18n.hideArchivedSections() : i18n.viewArchivedSections()} color={Button.ButtonColor.gray} /> )} diff --git a/apps/src/templates/teacherDashboard/SectionActionDropdown.jsx b/apps/src/templates/teacherDashboard/SectionActionDropdown.jsx index 31173a8a8104b..38b0df5a26803 100644 --- a/apps/src/templates/teacherDashboard/SectionActionDropdown.jsx +++ b/apps/src/templates/teacherDashboard/SectionActionDropdown.jsx @@ -141,7 +141,7 @@ class SectionActionDropdown extends Component { - {this.props.sectionData.hidden ? i18n.showSection() : i18n.hideSection()} + {this.props.sectionData.hidden ? i18n.restoreSection() : i18n.archiveSection()} {sectionData.studentCount === 0 && { .storiesOf('SectionActionDropdown', module) .addStoryTable([ { - name: 'Hidden Section', - description: 'Should have "Show Section" option', + name: 'Archived Section', + description: 'Should have "Restore Section" option', story: () => { const store = createStore(combineReducers({teacherSections})); store.dispatch(setSections([sectionDataHidden])); @@ -64,7 +64,7 @@ export default storybook => { }, { name: 'Shown Section', - description: 'Should have "Show Section" option', + description: 'Should have "Restore Section" option', story: () => { const store = createStore(combineReducers({teacherSections})); store.dispatch(setSections([sectionDataShown])); diff --git a/apps/src/util/experiments.js b/apps/src/util/experiments.js index 3e36fa8f6d9a4..f692ff5aae811 100644 --- a/apps/src/util/experiments.js +++ b/apps/src/util/experiments.js @@ -21,21 +21,14 @@ const EXPERIMENT_LIFESPAN_HOURS = 12; experiments.REDUX_LOGGING = 'reduxLogging'; experiments.COMMENT_BOX_TAB = 'commentBoxTab'; experiments.DEV_COMMENT_BOX_TAB = 'devCommentBoxTab'; -experiments.PROGRESS_TAB = 'sectionProgressRedesign'; -experiments.TEXT_RESPONSES_TAB = 'textResponsesRedesign'; -experiments.ASSESSMENTS_TAB = 'assessmentsTab'; experiments.SCHOOL_AUTOCOMPLETE_DROPDOWN_NEW_SEARCH = 'schoolAutocompleteDropdownNewSearch'; experiments.ACCOUNT_DELETION_NEW_FLOW = 'accountDeletionNewFlow'; // This is a per user experiment and is defined in experiments.rb -// On the front end we are treating it as an experiment group that contains -// PROGRESS_TAB. +// On the front end we are treating it as an experiment group. experiments.TEACHER_EXP_2018 = '2018-teacher-experience'; experiments.TEACHER_EXP_2018_LIST = [ - experiments.PROGRESS_TAB, experiments.COMMENT_BOX_TAB, - experiments.TEXT_RESPONSES_TAB, - experiments.ASSESSMENTS_TAB ]; /** diff --git a/apps/test/integration/levelSolutions/spritelab/sanity.js b/apps/test/integration/levelSolutions/spritelab/sanity.js new file mode 100644 index 0000000000000..f8bbbc832f924 --- /dev/null +++ b/apps/test/integration/levelSolutions/spritelab/sanity.js @@ -0,0 +1,65 @@ +import { TestResults } from '@cdo/apps/constants'; +import GameLabJr from '@cdo/apps/gamelab/GameLabJr.interpreted.js'; + +const levelDef = { + customHelperLibrary: GameLabJr, + sharedBlocks: [{ + name: "gamelab_setBackground", + config: { + color: [ + 240, + 0.45, + 0.65, + ], + func: "setBackground", + blockText: "set background color {COLOR}", + args: [ + { + name: "COLOR", + type: "Colour", + } + ] + } + }], + validationCode: 'if (World.background_color === "#ff0000") { levelSuccess(); } else { levelSuccess(3); }', +}; + +export default { + app: 'gamelab', + skinId: 'gamelab', + levelDefinition: levelDef, + tests: [ + { + description: 'Sprite Lab fail', + xml: ` + + + `, + expected: { + result: true, + testResult: TestResults.LEVEL_INCOMPLETE_FAIL, + }, + }, + { + description: 'Sprite Lab pass', + xml: ` + + + + + + + #ff0000 + + + + + + `, + expected: { + result: true, + testResult: TestResults.ALL_PASS, + }, + }, + ], +}; diff --git a/apps/test/integration/util/runLevelTest.js b/apps/test/integration/util/runLevelTest.js index bfeac8ca40852..6a447956efc22 100644 --- a/apps/test/integration/util/runLevelTest.js +++ b/apps/test/integration/util/runLevelTest.js @@ -113,7 +113,7 @@ function runLevel(app, skinId, level, onAttempt, finished, testData) { const unexpectedExecutionErrorMsg = 'Unexpected execution error. ' + 'Define onExecutionError() in your level test case to handle this.'; - loadApp({ + const options = { app, skinId: skinId, level: level, @@ -172,7 +172,19 @@ function runLevel(app, skinId, level, onAttempt, finished, testData) { // waitLong(); }, onAttempt: onAttempt - }); + }; + + loadApp(options); + + if (options.blocksModule.installCustomBlocks && level.sharedBlocks) { + options.blocksModule.installCustomBlocks( + Blockly, + null, + level.sharedBlocks, + options.level, + true, + ); + } } function setAppSpecificGlobals(app) { diff --git a/apps/test/unit/templates/instructions/InstructionsDialogWrapperTest.jsx b/apps/test/unit/templates/instructions/InstructionsDialogWrapperTest.jsx deleted file mode 100644 index 4549286072b14..0000000000000 --- a/apps/test/unit/templates/instructions/InstructionsDialogWrapperTest.jsx +++ /dev/null @@ -1,77 +0,0 @@ -import React from 'react'; -import {mount} from 'enzyme'; -import sinon from 'sinon'; -import {expect} from '../../../util/configuredChai'; -import { - UnwrappedInstructionsDialogWrapper as InstructionsDialogWrapper -} from '@cdo/apps/templates/instructions/InstructionsDialogWrapper'; - -describe('InstructionsDialogWrapper', () => { - let spy, wrapper; - - beforeEach(() => { - spy = sinon.spy(); - }); - - afterEach(() => { - if (wrapper) { - wrapper.unmount(); - } - }); - - it('renders nothing', () => { - wrapper = mount( - - ); - expect(wrapper).to.be.empty; - }); - - it('does not call showInstructionsDialog on first render', () => { - wrapper = mount( - - ); - expect(spy).not.to.have.been.called; - }); - - it('calls showInstructionsDialog every time props change to open', () => { - wrapper = mount( - - ); - expect(spy).not.to.have.been.called; - wrapper.setProps({isOpen: true}); - expect(spy).to.have.been.calledOnce; - wrapper.setProps({isOpen: true}); - expect(spy).to.have.been.calledOnce; - wrapper.setProps({isOpen: false}); - expect(spy).to.have.been.calledOnce; - wrapper.setProps({isOpen: false}); - expect(spy).to.have.been.calledOnce; - wrapper.setProps({isOpen: true}); - expect(spy).to.have.been.calledTwice; - }); - - it('passes optional autoClose prop to showInstructionsDialog', () => { - wrapper = mount( - - ); - expect(spy).not.to.have.been.called; - wrapper.setProps({isOpen: true, autoClose: true}); - expect(spy).to.have.been.calledOnce.and.calledWith(true); - wrapper.setProps({isOpen: false}); - expect(spy).to.have.been.calledOnce; - wrapper.setProps({isOpen: true, autoClose: false}); - expect(spy).to.have.been.calledTwice.and.calledWith(false); - }); -}); diff --git a/apps/test/unit/templates/instructions/InstructionsWithWorkspaceTest.jsx b/apps/test/unit/templates/instructions/InstructionsWithWorkspaceTest.jsx deleted file mode 100644 index 068a77fae4f59..0000000000000 --- a/apps/test/unit/templates/instructions/InstructionsWithWorkspaceTest.jsx +++ /dev/null @@ -1,123 +0,0 @@ -import $ from 'jquery'; -import React from 'react'; -import sinon from 'sinon'; -import {shallow} from 'enzyme'; -import {expect} from '../../../util/configuredChai'; -import { - UnwrappedInstructionsWithWorkspace as InstructionsWithWorkspace -} from '@cdo/apps/templates/instructions/InstructionsWithWorkspace'; - -describe('InstructionsWithWorkspace', () => { - it('renders instructions and code workspace', () => { - const wrapper = shallow( - {}} - /> - ); - expect(wrapper).to.have.descendants('Connect(TopInstructions)'); - expect(wrapper).to.have.descendants('Connect(CodeWorkspaceContainer)'); - }); - - it('initially does not know window width or height', () => { - const wrapper = shallow( - {}} - /> - ); - expect(wrapper.state()).to.deep.equal({ - windowWidth: undefined, - windowHeight: undefined - }); - }); - - describe('onResize', () => { - let setInstructionsMaxHeightAvailable; - - beforeEach(() => { - setInstructionsMaxHeightAvailable = sinon.spy(); - - sinon.stub($.fn, 'width').returns(1024); - sinon.stub($.fn, 'height').returns(768); - }); - - afterEach(() => { - $.fn.width.restore(); - $.fn.height.restore(); - }); - - function setupComponent({instructionsHeight = 400, codeWorkspaceHeight = 100} = {}) { - const wrapper = shallow( - - ); - - // Fake ref to inner object, since we're shallow rendering. - wrapper.instance().codeWorkspaceContainer = { - getWrappedInstance: () => ({ - getRenderedHeight: () => codeWorkspaceHeight - }) - }; - - return wrapper; - } - - it('does nothing if window size has not changed', () => { - const wrapper = setupComponent(); - - wrapper.setState({ - windowWidth: 640, - windowHeight: 480 - }); - $.fn.width.returns(640); - $.fn.height.returns(480); - sinon.spy(wrapper.instance(), 'setState'); - - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).not.to.have.been.called; - expect(wrapper.instance().setState).not.to.have.been.called; - }); - - it('handles resize', () => { - const wrapper = setupComponent(); - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).to.have.been.calledOnce - .and.calledWith(230); - }); - - it('breakpoint in behavior at total height of 420 (meets all reserves)', () => { - let wrapper; - - wrapper = setupComponent({instructionsHeight: 18, codeWorkspaceHeight: 400}); - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).to.have.been.calledWith(139); - - setInstructionsMaxHeightAvailable.reset(); - - wrapper = setupComponent({instructionsHeight: 19, codeWorkspaceHeight: 400}); - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).to.have.been.calledWith(140); - - setInstructionsMaxHeightAvailable.reset(); - - wrapper = setupComponent({instructionsHeight: 20, codeWorkspaceHeight: 400}); - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).to.have.been.calledWith(150); - - setInstructionsMaxHeightAvailable.reset(); - - wrapper = setupComponent({instructionsHeight: 21, codeWorkspaceHeight: 400}); - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).to.have.been.calledWith(151); - }); - - it('skips callback if codeWorkspaceContainer is not initialized', () => { - const wrapper = setupComponent({codeWorkspaceHeight: 0}); - wrapper.instance().onResize(); - expect(setInstructionsMaxHeightAvailable).not.to.have.been.called; - }); - }); -}); diff --git a/apps/test/unit/templates/teacherDashboard/OwnedSectionsTest.js b/apps/test/unit/templates/teacherDashboard/OwnedSectionsTest.js index 94679c157b0bf..2e73b0de210dc 100644 --- a/apps/test/unit/templates/teacherDashboard/OwnedSectionsTest.js +++ b/apps/test/unit/templates/teacherDashboard/OwnedSectionsTest.js @@ -38,7 +38,7 @@ describe('OwnedSections', () => { ); }); - it('renders a OwnedSectionsTable with no extra button if no hidden sections', () => { + it('renders a OwnedSectionsTable with no extra button if no archived sections', () => { const wrapper = shallow( { expect(wrapper.find('Button').length).to.equal(0); }); - it('renders a OwnedSectionsTable with view button if hidden sections', () => { + it('renders a OwnedSectionsTable with view button if archived sections', () => { const wrapper = shallow( { expect(wrapper.find('Connect(OwnedSectionsTable)').length).to.equal(1); // Button to view hidden (notification not counted) expect(wrapper.find('Button').length).to.equal(1); - expect(wrapper.find('Button').at(0).props().text, 'View hidden sections'); + expect(wrapper.find('Button').at(0).props().text, 'View archived sections'); }); - it('renders two OwnedSectionsTables if view hidden sections clicked', () => { + it('renders two OwnedSectionsTables if view archived sections clicked', () => { const wrapper = shallow( { expect(wrapper.find('Connect(OwnedSectionsTable)').length).to.equal(2); expect(wrapper.find('Connect(OwnedSectionsTable)').at(0).props().sectionIds).to.deep.equal([11,12]); expect(wrapper.find('Connect(OwnedSectionsTable)').at(1).props().sectionIds).to.deep.equal([13]); - expect(wrapper.find('Button').at(0).props().text).to.equal('Hide hidden sections'); + expect(wrapper.find('Button').at(0).props().text).to.equal('Hide archived sections'); }); it('renders just unhidden SectionsAsStudentTable if hide sections clicked', () => { diff --git a/apps/test/unit/templates/teacherDashboard/SectionActionDropdownTest.js b/apps/test/unit/templates/teacherDashboard/SectionActionDropdownTest.js index 91e72b5cb4af5..48a7ce9444099 100644 --- a/apps/test/unit/templates/teacherDashboard/SectionActionDropdownTest.js +++ b/apps/test/unit/templates/teacherDashboard/SectionActionDropdownTest.js @@ -132,23 +132,23 @@ describe('SectionActionDropdown', () => { expect(wrapper.find().length, 1); }); - it('renders the hide option for a un-hidden section', () => { + it('renders the archive option for an unarchived section', () => { const wrapper = shallow( ); - expect(wrapper).to.contain("Hide Section"); + expect(wrapper).to.contain("Archive Section"); }); - it('renders the show option for a hidden section', () => { + it('renders the restore option for an archived section', () => { const wrapper = shallow( ); - expect(wrapper).to.contain("Show Section"); + expect(wrapper).to.contain("Restore Section"); }); }); diff --git a/dashboard/app/controllers/api_controller.rb b/dashboard/app/controllers/api_controller.rb index 19988b043ae28..4132896e45a6f 100644 --- a/dashboard/app/controllers/api_controller.rb +++ b/dashboard/app/controllers/api_controller.rb @@ -1,4 +1,5 @@ require 'google/apis/classroom_v1' +require 'honeybadger' class ApiController < ApplicationController layout false @@ -432,6 +433,12 @@ def section_text_responses # is in :correct. # TODO(caleybrock): remove this and its tests once the assessments tab is in react def section_assessments + # Notify Honeybadger to determine if this endpoint is still used anywhere + Honeybadger.notify( + error_class: "DeprecatedEndpointWarning", + error_message: 'Deprecated endpoint GET /dashboardapi/section_assessments/:section_id called unexpectedly', + ) + section = load_section script = load_script(section) @@ -533,6 +540,12 @@ def section_assessments # At least five students in the section must have submitted answers. The answers for each contained # sublevel are shuffled randomly. def section_surveys + # Notify Honeybadger to determine if this endpoint is still used anywhere + Honeybadger.notify( + error_class: "DeprecatedEndpointWarning", + error_message: 'Deprecated endpoint GET /dashboardapi/section_surveys/:section_id called unexpectedly', + ) + section = load_section script = load_script(section) diff --git a/dashboard/app/models/census/other_curriculum_offering.rb b/dashboard/app/models/census/other_curriculum_offering.rb new file mode 100644 index 0000000000000..4312023826172 --- /dev/null +++ b/dashboard/app/models/census/other_curriculum_offering.rb @@ -0,0 +1,20 @@ +# == Schema Information +# +# Table name: other_curriculum_offerings +# +# id :integer not null, primary key +# curriculum_provider_name :string(255) not null +# school_id :string(12) not null +# course :string(255) not null +# school_year :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# fk_rails_5682e60354 (school_id) +# index_other_curriculum_offerings_unique (curriculum_provider_name,school_id,course,school_year) UNIQUE +# + +class Census::OtherCurriculumOffering < ApplicationRecord +end diff --git a/dashboard/config/environments/test.rb b/dashboard/config/environments/test.rb index 4ac1a969f04f8..caf896c94cc4c 100644 --- a/dashboard/config/environments/test.rb +++ b/dashboard/config/environments/test.rb @@ -95,4 +95,17 @@ # Whether or not to skip script preloading. Setting this to true # significantly speeds up server startup time. config.skip_script_preload = false + + # Overrides for Jotform Form Ids + CDO.jotform_forms = { + 'local' => { + 'day_0' => 1, + 'day_1' => 2, + 'day_2' => 3, + 'day_3' => 4, + 'day_4' => 5, + 'day_5' => 6, + 'facilitator' => 7 + } + } end diff --git a/dashboard/db/migrate/20180712175948_create_census_other_curriculum_offerings.rb b/dashboard/db/migrate/20180712175948_create_census_other_curriculum_offerings.rb new file mode 100644 index 0000000000000..af09b4fee4628 --- /dev/null +++ b/dashboard/db/migrate/20180712175948_create_census_other_curriculum_offerings.rb @@ -0,0 +1,19 @@ +class CreateCensusOtherCurriculumOfferings < ActiveRecord::Migration[5.0] + def change + create_table :other_curriculum_offerings do |t| + t.string :curriculum_provider_name, null: false + t.string :school_id, limit: 12, null: false + t.string :course, null: false + # limit on integers is number of bytes, not digits or display length + t.integer :school_year, limit: 2, null: false + + t.timestamps + end + + add_foreign_key :other_curriculum_offerings, :schools + add_index :other_curriculum_offerings, + [:curriculum_provider_name, :school_id, :course, :school_year], + unique: true, + name: 'index_other_curriculum_offerings_unique' + end +end diff --git a/dashboard/db/schema.rb b/dashboard/db/schema.rb index ac1a793e21fb4..59dbfc36bf39f 100644 --- a/dashboard/db/schema.rb +++ b/dashboard/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180704013020) do +ActiveRecord::Schema.define(version: 20180712175948) do create_table "activities", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci" do |t| t.integer "user_id" @@ -533,6 +533,17 @@ t.float "value", limit: 24, null: false end + create_table "other_curriculum_offerings", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci" do |t| + t.string "curriculum_provider_name", null: false + t.string "school_id", limit: 12, null: false + t.string "course", null: false + t.integer "school_year", limit: 2, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["curriculum_provider_name", "school_id", "course", "school_year"], name: "index_other_curriculum_offerings_unique", unique: true, using: :btree + t.index ["school_id"], name: "fk_rails_5682e60354", using: :btree + end + create_table "paired_user_levels", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci" do |t| t.integer "driver_user_level_id" t.integer "navigator_user_level_id" @@ -1583,6 +1594,7 @@ add_foreign_key "hint_view_requests", "users" add_foreign_key "ib_school_codes", "schools" add_foreign_key "level_concept_difficulties", "levels" + add_foreign_key "other_curriculum_offerings", "schools" add_foreign_key "pd_payment_terms", "regional_partners" add_foreign_key "pd_regional_partner_cohorts", "pd_workshops", column: "summer_workshop_id" add_foreign_key "pd_teachercon1819_registrations", "regional_partners" diff --git a/dashboard/db/schema_cache.dump b/dashboard/db/schema_cache.dump index ceac3fa9039cf..d36cc3fdae838 100644 Binary files a/dashboard/db/schema_cache.dump and b/dashboard/db/schema_cache.dump differ diff --git a/dashboard/test/ui/features/pd/daily_survey_results.feature b/dashboard/test/ui/features/pd/daily_survey_results.feature new file mode 100644 index 0000000000000..5299881c1e64f --- /dev/null +++ b/dashboard/test/ui/features/pd/daily_survey_results.feature @@ -0,0 +1,14 @@ +@dashboard_db_access +@eyes + +Feature: Basic appearance for Facilitator Survey UI + +Scenario: Results view for facilitator survey UI is as expected + Given I am a workshop administrator + When I open my eyes to test "Daily Survey Results View" + And I am viewing a workshop with fake survey results + And I see no difference for "Pre Workshop Results View" + And I click selector "#SurveyTab-tab-2" + And I wait for 1 second + And I see no difference for "Day 1 Results View" + And I close my eyes \ No newline at end of file diff --git a/dashboard/test/ui/features/step_definitions/pd.rb b/dashboard/test/ui/features/step_definitions/pd.rb index d465881882faf..43b577a97a86a 100644 --- a/dashboard/test/ui/features/step_definitions/pd.rb +++ b/dashboard/test/ui/features/step_definitions/pd.rb @@ -8,6 +8,14 @@ } end +Given(/^I am a workshop administrator$/) do + random_name = "TestWorkshopAdmin" + SecureRandom.hex(10) + steps %Q{ + And I create a teacher named "#{random_name}" + And I make the teacher named "#{random_name}" a workshop admin + } +end + Given /^I am a CSF facilitator named "([^"]*)" for regional partner "([^"]*)"$/ do |facilitator_name, partner_name| require_rails_env @@ -214,6 +222,240 @@ puts "Creating applications took #{time_end - time_start} seconds" end +And(/^I am viewing a workshop with fake survey results$/) do + require_rails_env + + workshop = FactoryGirl.create :pd_ended_workshop, :local_summer_workshop, + organizer: FactoryGirl.create(:workshop_organizer, email: "test_organizer#{SecureRandom.hex}@code.org"), + num_sessions: 5, enrolled_and_attending_users: 10, + facilitators: [ + (FactoryGirl.create :facilitator, email: "test_facilitator#{SecureRandom.hex}@code.org", name: 'F1'), + (FactoryGirl.create :facilitator, email: "test_facilitator#{SecureRandom.hex}@code.org", name: 'F2') + ] + create_fake_survey_questions workshop + create_fake_daily_survey_results workshop + + steps %Q{ + And I am on "http://studio.code.org/pd/workshop_dashboard/local_summer_workshop_daily_survey_results/#{workshop.id}" + } +end + +def create_fake_survey_questions(workshop) + Pd::SurveyQuestion.find_or_create_by!(form_id: CDO.jotform_forms['local']['day_0'], + questions: [ + { + id: 1, + name: 'matrix', + type: 'matrix', + text: 'How much do you agree / disagree with these statements on teaching CS?', + options: [ + 'Strongly Disagree', + 'Disagree', + 'Slightly Disagree', + 'Neutral', + 'Slightly Agree', + 'Agree', + 'Strongly Agree' + ], + sub_questions: [ + 'I like computer science', + 'People should learn computer science', + 'I feel like I can teach computer science' + ], + order: 1 + }, + { + id: 2, + name: 'scale', + type: 'scale', + text: 'How pumped are you to teach CS?', + options: ['Not at all pumped', 'Super pumped'], + values: (1..5).to_a, + order: 2 + }, + { + id: 3, + name: 'radio', + type: 'radio', + text: 'How much CS experience do you have?', + order: 3, + options: [ + 'None', + 'Some basic messing around', + 'Formal education', + 'I am l33t h4xx0r' + ] + }, + { + id: 4, + name: 'textarea', + type: 'textarea', + text: 'What inspired you to teach computer science?', + order: 4 + }, + { + id: 5, + name: 'userId', + text: 'userId', + type: 'textarea', + order: 5, + hidden: true + }, + { + id: 6, + name: 'workshopId', + text: 'workshopId', + type: 'textarea', + order: 6, + hidden: true + } + ].to_json + ) + + Pd::SurveyQuestion.find_or_create_by!(form_id: CDO.jotform_forms['local']['day_1'], + questions: [ + { + id: 1, + name: 'textarea', + type: 'textarea', + text: 'How was your day?', + order: 1 + }, + { + id: 2, + name: 'userId', + text: 'userId', + type: 'textarea', + order: 2, + hidden: true + }, + { + id: 3, + name: 'workshopId', + text: 'workshopId', + type: 'textarea', + order: 3, + hidden: true + }, + { + id: 4, + name: 'sessionId', + text: 'sessionId', + type: 'textarea', + order: 4, + hidden: true + } + ].to_json + ) + + Pd::SurveyQuestion.find_or_create_by!(form_id: CDO.jotform_forms['local']['facilitator'], + questions: [ + { + id: 1, + name: 'textarea', + type: 'textarea', + text: 'How was your facilitator?', + order: 1 + }, + { + id: 2, + name: 'userId', + text: 'userId', + type: 'textarea', + order: 2, + hidden: true + }, + { + id: 3, + name: 'workshopId', + text: 'workshopId', + type: 'textarea', + order: 3, + hidden: true + }, + { + id: 4, + name: 'sessionId', + text: 'sessionId', + type: 'textarea', + order: 4, + hidden: true + }, + { + id: 5, + name: 'facilitatorId', + text: 'facilitatorId', + type: 'textarea', + order: 5, + hidden: true + }, + { + id: 6, + name: 'day', + text: 'day', + type: 'textarea', + order: 6, + hidden: true + } + ].to_json + ) +rescue => e + puts "Unable to create SurveyQuestions. If you are running this locally, please make + sure that you have overridden jotform_forms in your locals.yml" + raise e +end + +def create_fake_daily_survey_results(workshop) + 10.times do |x| + user = workshop.enrollments[x].user + + Pd::WorkshopDailySurvey.create!( + form_id: CDO.jotform_forms['local']['day_0'], + submission_id: (Pd::WorkshopDailySurvey.maximum(:submission_id) || 0) + 1, + pd_session: nil, #No session for the first survey + answers: { + '1': { + 'I like computer science': ['Strongly Agree', 'Agree', 'Slightly Agree'][x % 3], + 'People should learn computer science': ['Strongly Agree', 'Agree'][x % 2], + 'I feel like I can teach computer science': ['Strongly Agree', 'Agree', 'Disagree'][x % 3] + }, + '2': (1..5).to_a[x % 5].to_s, + '3': ['None', 'Some basic messing around', 'Formal education', 'I am l33t h4xx0r'][x % 4], + '4': ['Bill Nye', 'Ada Lovelace', 'Hadi', 'Hour of Code', 'Dunno'][x % 5], + '5': user.id, + '6': workshop.id, + }.to_json + ) + + Pd::WorkshopDailySurvey.create!( + form_id: CDO.jotform_forms['local']['day_1'], + submission_id: (Pd::WorkshopDailySurvey.maximum(:submission_id) || 0) + 1, + user: workshop.enrollments[x].user, + pd_session: workshop.sessions.first, + pd_workshop: workshop, + answers: { + '1': %w(Amazing Brilliant Great Decent)[x % 4], + '2': user.id, + '3': workshop.id, + '4': workshop.sessions.first.id + }.to_json + ) + + Pd::WorkshopFacilitatorDailySurvey.create!( + form_id: CDO.jotform_forms['local']['facilitator'], + submission_id: (Pd::WorkshopFacilitatorDailySurvey.maximum(:submission_id) || 0) + 1, + answers: { + '1': %w(Helpful Hillarious Inspiring Brilliant)[x % 4], + '2': user.id, + '3': workshop.id, + '4': workshop.sessions.first.id, + '5': workshop.facilitators[x % 2].id, + '6': 1 + }.to_json + ) + end +end + def create_enrollment(workshop, name=nil) first_name = name.nil? ? "First - #{SecureRandom.hex}" : name last_name = name.nil? ? "Last - #{SecureRandom.hex}" : "Last" diff --git a/dashboard/test/ui/features/teacher_dashboard.feature b/dashboard/test/ui/features/teacher_dashboard.feature index d4aa7d976b1e0..09e199063ec9b 100644 --- a/dashboard/test/ui/features/teacher_dashboard.feature +++ b/dashboard/test/ui/features/teacher_dashboard.feature @@ -12,49 +12,6 @@ Feature: Using the teacher dashboard Then I click selector "div.title:contains('Student Accounts and Progress')" Then I wait until I am on "http://studio.code.org/home" - Scenario: Loading student progress - Given I create a teacher-associated student named "Sally" - And I give user "Teacher_Sally" hidden script access - And I complete the level on "http://studio.code.org/s/allthethings/stage/2/puzzle/1" - And I complete the free response on "http://studio.code.org/s/allthethings/stage/27/puzzle/1" - And I submit the assessment on "http://studio.code.org/s/allthethings/stage/33/puzzle/1" - And I sign out - - When I sign in as "Teacher_Sally" - And I am on "http://code.org/teacher-dashboard?no_home_redirect=1" - And I click selector "div.title:contains('Student Accounts and Progress')" once I see it - And I click selector "a:contains('New Section')" once I see it - And I click selector "a:contains('Sally')" once I see it - And I wait until element "#course-dropdown" is visible - And I select the "All the Things! *" option in dropdown "course-dropdown" - And I wait until I see selector "a[href*='/s/allthethings/stage/2/puzzle/1']" - Then selector "a[href*='/s/allthethings/stage/2/puzzle/1']" has class "perfect" - But selector "a[href*='/s/allthethings/stage/2/puzzle/2']" doesn't have class "perfect" - - When I click selector "a:contains('View New Section')" once I see it - And I click selector "#learn-tabs a:contains('Stats')" once I see it - And I wait until element "#uitest-stats-table" is visible - - When I click selector "#learn-tabs a:contains('Text Responses')" once I see it - And I wait until element "#uitest-course-dropdown" is visible - And I select the "All the Things! *" option in dropdown "uitest-course-dropdown" - And I wait until element "#uitest-responses-tab td:nth(0)" is visible - And element "#uitest-responses-tab td:nth(0)" contains text "Sally" - And element "#uitest-responses-tab td:nth(4)" contains text "hello world" - - When I click selector "#learn-tabs a:contains('Manage Students')" once I see it - And I wait until element "#uitest-manage-tab" is visible - And I wait until element "#uitest-privacy-link" is visible - And element "#uitest-privacy-link" contains text "privacy document" - - When I click selector "#learn-tabs a:contains('Assessments/Surveys')" once I see it - And I wait until element "#uitest-course-dropdown" is visible - And I select the "All the Things! *" option in dropdown "uitest-course-dropdown" - And I wait until element "#uitest-assessments-tab td:nth(0)" is visible - And element "#uitest-assessments-tab td:nth(0)" contains text "Sally" - And element "#uitest-assessments-tab td:nth(1)" contains text "Lesson 33: Single page assessment" - And element "#uitest-assessments-tab td:nth(4)" contains text "1" - Scenario: Loading section projects Given I create a teacher-associated student named "Sally" And I am on "http://studio.code.org/projects/applab" diff --git a/lib/rake/build.rake b/lib/rake/build.rake index ffc0bdc256152..52fb14c3e3309 100644 --- a/lib/rake/build.rake +++ b/lib/rake/build.rake @@ -97,13 +97,8 @@ namespace :build do # Skip asset precompile in development where `config.assets.digest = false`. # Also skip on Circle CI where we will precompile assets later, right before UI tests. unless rack_env?(:development) || ENV['CIRCLECI'] - # Skip cleaning assets in production, to be extra sure we don't break anything. - # Do clean assets in staging and test, to hopefully expose any bugs where we - # depend on outdated assets. - unless rack_env?(:production) - ChatClient.log 'Cleaning dashboard assets...' - RakeUtils.rake 'assets:clean' - end + ChatClient.log 'Cleaning dashboard assets...' + RakeUtils.rake 'assets:clean' ChatClient.log 'Precompiling dashboard assets...' RakeUtils.rake 'assets:precompile' end diff --git a/pegasus/data/cdo-state-promote.csv b/pegasus/data/cdo-state-promote.csv index 103b64c9b1984..e5d3e503c7751 100644 --- a/pegasus/data/cdo-state-promote.csv +++ b/pegasus/data/cdo-state-promote.csv @@ -1,53 +1,53 @@ -state_code_s!,state_name_s,cs_jobs_i,growth_vs_average_f,cs_graduates_i,count_schools_teach_cs_i,job_student_gap_i,state_plan_s,cs_counts_t,cs_teacher_cert_s,cs_standards_s,pd_funding_s,pre_service_s,state_position_s,require_hs_s,require_k12_s,higher_ed_entrance_s,text_t,petition_url_t,action_url_s,action_text_s,avg_sal_computing_i,sal_x_jobs_bi,avg_sal_all_i,preservice_prepared_i,percent_female_cs_grad_i,percent_cs_exams_f,ap_cs_exams_i,percent_ap_female_i,ap_hispanic_i,ap_black_i,ap_native_american_i,ap_hawaiian_i,total_ap_students_color_i,schools_ap_cs_i,percent_schools_ap_cs_i,number_additional_schools_i,ap_csa_exams_i,percent_ap_csa_female_i,ap_csa_hispanic_i,ap_csa_black_i,ap_csa_native_american_i,ap_csa_hawaiian_i,percent_schools_ap_csa_i,ap_csp_exams_i,percent_ap_csp_female_i,ap_csp_hispanic_i,ap_csp_black_i,ap_csp_native_american_i,ap_csp_hawaiian_i,percent_schools_ap_csp_i,principals_core_i,principals_barrier_s,website_url_s,school_district_partners_t,professional_learning_partners_t,other_partners_t,num_affiliates_i,num_elementary_trained_i,num_ecs_csd_i,num_csp_i,num_ms_trained_i,num_hs_trained_i,num_hoc_i,ap_calc_i,ap_bio_i,ap_phy_i,ap_stats_i,ap_chem_i,ap_env_sci_i,ap_cs_i,student_studio_acct_i,teacher_studio_acct_i,policy_0_t,policy_1_t,policy_2_t,policy_3_t,policy_4_t,policy_5_t,policy_6_t,policy_7_t,policy_8_t,pd_funding_exception_s,require_hs_exception_s,cs_standards_exception_s -AK,Alaska,759,3.7,25,5,-734,No,No,No,Other,No,No,No,No,No,No,,,,,84747,64322973,56710,0,16%,1.07%,68,25%,4,0,1,0,5,6,8%,3,26,19%,1,0,0,0,5%,42,29%,3,0,1,0,4%,0,No,www.code.org/promote/AK,no school districts in the state,Alaska Staff Development Network,none,0,0,0,1,0,0,147000,789,264,288,273,308,104,60,36228,1452,,Alaska is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress -AL,Alabama,5230,5.2,503,26,-4727,No,Yes,No,Yes,Yes,No,No,No,No,No,,,,,82893,433530390,42510,0,21%,0.59%,1520,30%,77,157,7,2,243,86,25%,58,271,20%,8,14,1,1,7%,1249,33%,69,143,6,1,23%,69%,Other,www.code.org/promote/AL,no school districts in the state,A+ College Ready,none,4,1557,18,60,0,31,779000,4065,4556,2144,1890,3189,1335,303,226638,6532,,,,,,,,,,,, -AR,Arkansas,2123,3.8,328,19,-1795,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,,,,,70458,149582334,39590,0,12%,0.64%,870,26%,121,90,5,5,221,50,16%,23,378,21%,59,41,1,3,8%,492,31%,62,49,4,2,12%,73%,No,www.code.org/promote/AR,no school districts in the state,none,none,2,2331,0,0,0,1,419000,2991,2884,1818,1859,1722,1025,304,261412,5519,,,,,,,,,,,, -AZ,Arizona,10434,3.3,546,33,-9888,No,Other,Yes,Other,Other,No,No,No,No,No,,,,,84866,885491844,46290,0,15%,0.65%,738,22%,138,12,3,0,153,52,16%,21,480,23%,67,7,1,0,13%,258,20%,71,5,2,0,8%,63%,Other,www.code.org/promote/AZ,Paradise Valley Unified School District and Phoenix Union High School District,Grand Canyon University and Science Foundation Arizona,none,5,2536,68,37,10,39,993000,6745,3239,4012,2082,2222,973,438,410706,10228,,Arizona is in the process of developing K-12 computer science standards.,Arizona has allocated funding for rigorous computer science professional development and course support (with an emphasis on Native American students).,,,,,"Arizona has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,"Dedicated state funding for CS PD, emphasis on Native American students",,K-12 CS standards in progress -CA,California,72972,3.8,4029,311,-68943,Other,Other,Yes,Yes,No,No,Other,No,No,Yes,,,,,110078,8032611816,56840,0,16%,1.38%,18828,29%,4146,345,26,48,4565,580,25%,210,10268,27%,1469,138,13,25,19%,8560,32%,2677,207,13,23,14%,70%,Other,www.code.org/promote/CA,"Alliance College Ready Public Schools, Anaheim Union High School District, Benicia Unified School District, Brentwood Union School District, Cajon Valley School District, Calistoga Joint Unified School District, Central Unified School District, Corona-Norco Unified School District, Covina Valley Unified School District, Fairfield-Suisun Unified School District, Fontana Unified School District, Granada Hills Charter High School, John Swett Unified School District, Jurupa Unified School District, Liberty Union High School District, Los Angeles Unified School District, Martinez Unified School District, Moraga Elementary School District, Mt. Diablo Unified School District, Oakland Unified Public Schools, Orange Unified School District, Perris Union High School District, Pittsburg Unified School District, Placentia-Yorba Linda Union School District, Riverside Unified School District, Saddleback Valley Unified School District, San Jacinto Unified School District, Temecula Valley Unified School District, Val Verde Unified School District, and Whittier Union High School District","9 Dots Community Learning Center, Alameda County Office of Education, Contra Costa County Office of Education, Elementary Institute of Science, Fresno County Office of the Superintendent, LAUSD, Riverside County Office of Education, Sacramento County Office of Education, and Silicon Valley Education Foundation",none,69,9472,258,203,121,247,11345000,74006,38045,32699,32145,21572,26444,10244,2238509,62718,California is in the process of developing a state plan for K-12 computer science.,California is in the process of developing K-12 computer science standards.,,,,California has a dedicated state board member focused on computer science education. California has an opportunity to make more progress in computer science education by creating a position at the state education authority and creating local leadership positions across the state.,,"California has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,,K-12 CS standards in progress -CO,Colorado,16285,3.3,785,69,-15500,No,Other,No,No,Yes,No,No,No,No,Yes,,,,,98597,1605652145,52710,1,15%,0.97%,1437,19%,219,30,7,3,259,96,26%,43,860,18%,114,12,3,0,16%,577,21%,105,18,4,3,15%,61%,Yes,www.code.org/promote/CO,Denver Public Schools and Douglas County Schools,mindSpark Learning,none,4,413,26,42,0,15,1881000,8517,4015,4766,3778,2818,2490,780,310802,5678,,,,,,,,"Colorado has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, -CT,Connecticut,7544,4,404,65,-7140,Other,No,No,Yes,No,No,Yes,No,No,No,,,,,96862,730726928,57960,0,15%,1.46%,1872,27%,146,83,3,0,232,96,37%,27,983,24%,61,32,1,0,30%,889,31%,85,51,2,0,20%,66%,Yes,www.code.org/promote/CT,no school districts in the state,none,none,2,559,0,4,0,2,941000,6314,3967,4492,3781,2552,2000,939,205373,3950,Connecticut is in the process of developing a state plan for K-12 computer science.,,,,,,,,,,, -DC,District of Columbia,10504,4.5,133,12,-10371,No,Other,Yes,No,No,No,No,No,No,No,,,,,108215,1136690360,82950,0,41%,1.51%,233,31%,35,59,1,1,96,15,29%,4,139,26%,21,28,1,1,21%,94,39%,14,31,0,0,17%,0,No,www.code.org/promote/DC,no school districts in the state,none,none,0,0,0,1,0,0,155000,911,567,587,424,378,509,176,36573,1034,,,,,,,,"District of Columbia allows computer science to count for a core graduation requirement. This policy is not written down and publicly accessible, but we are working with them to release public documentation.",,,, -DE,Delaware,2731,4.4,192,11,-2539,No,Yes,No,Yes,No,No,No,Yes,No,No,,,,,95926,261973906,50930,0,23%,1.38%,292,23%,10,20,0,0,30,14,20%,3,158,21%,4,10,0,0,13%,134,25%,6,10,0,0,14%,0,No,www.code.org/promote/DE,no school districts in the state,none,none,0,0,0,1,0,0,225000,1178,812,592,844,521,420,166,71247,1270,,,,,,,,,,,, -FL,Florida,22816,4,2486,125,-20330,No,Yes,Yes,Yes,No,No,Yes,Yes,No,No,,,,,78531,1791763296,44050,0,19%,0.71%,7233,25%,2199,598,17,9,2823,241,22%,95,2404,21%,717,139,5,4,13%,4829,27%,1482,459,12,5,16%,67%,No,www.code.org/promote/FL,"Broward County Schools, Duval County Public Schools, Miami-Dade County Public Schools, One Clay County School District, School District of Clay County, School District of Palm Beach County, and Florida International University School of Computing and Information Sciences ","Broward County Public Schools, Florida State College Jacksonville, Orlando Science Center, Florida International University School of Computing and Information Sciences, and Tampa Bay STEM Network",none,49,5253,194,154,140,259,3571000,20506,13774,12671,13261,7635,16625,2688,996792,28786,,,,,,,,,,,, -GA,Georgia,20137,4.4,1747,133,-18390,Other,Yes,Yes,No,Yes,No,Yes,No,No,Yes,,,,,90351,1819398087,46540,0,19%,1.19%,3856,24%,344,356,5,5,710,154,25%,27,1914,22%,178,170,1,1,20%,1942,25%,166,186,4,4,15%,71%,Yes,www.code.org/promote/GA,"Fayette County Public Schools, Forsyth County Schools, Fulton County Schools, and Gwinnett County Public Schools","Georgia Tech Center for Education Integrating Science, Mathematics, and Computing",none,16,3351,48,84,38,73,2211000,11781,8298,8379,7671,4528,7380,2033,684713,15985,Georgia is in the process of developing a state plan for K-12 computer science. ,,,,,,,,,,, -HI,Hawaii,1577,5.2,155,8,-1422,Yes,No,No,Yes,Yes,No,Yes,Yes,No,No,,,,,80734,127317518,49430,0,17%,1.32%,290,32%,43,1,0,12,56,16,19%,4,88,30%,14,0,0,8,5%,202,33%,29,1,0,4,16%,0,No,www.code.org/promote/HI,no school districts in the state,MEDB's Women in Technology,none,1,693,1,0,0,0,254000,1481,1069,1288,729,523,627,188,113743,2598,,,,,,,,,,,, -IA,Iowa,4424,3.5,364,33,-4060,No,No,Yes,Yes,Yes,No,No,Other,No,No,,,,,79062,349770288,43540,0,14%,1.00%,340,17%,21,9,0,0,30,31,15%,14,233,16%,11,5,0,0,10%,107,20%,10,4,0,0,8%,67%,Yes,www.code.org/promote/IA,no school districts in the state,New Bohemian Innovation Collaborative,none,4,1394,10,23,0,2,904000,1958,1056,787,988,1004,533,211,278179,5495,,,,,,,Iowa is working towards bringing computer science to all secondary schools.,,,,Working towards all high schools to offer CS, -ID,Idaho,1593,3.4,333,7,-1260,No,Yes,Yes,Yes,Yes,Yes,Yes,Yes,No,Yes,,,,,71648,114135264,41910,0,13%,0.52%,315,29%,39,0,0,0,39,19,19%,12,123,24%,8,0,0,0,8%,192,33%,31,0,0,0,16%,66%,Other,www.code.org/promote/ID,no school districts in the state,Idaho Digital Learning Academy,none,11,602,34,20,64,37,434000,1143,631,745,457,322,310,59,98165,2361,,,,,,,,,,,, -IL,Illinois,27187,3.9,1768,132,-25419,No,Yes,Yes,No,No,No,No,No,No,Yes,,,,,89465,2432284955,51500,1,13%,1.41%,4909,23%,714,127,4,3,848,157,22%,34,3135,22%,330,63,4,2,21%,1774,25%,384,64,0,1,11%,65%,No,www.code.org/promote/IL,"Chicago Public Schools, Community High School District 117, Community Unit School District 300, Elmhurst Community Unit School District 205, Lake Zurich Community Unit School District 95, New Trier Township District 203, Northern Suburban Special Education District 804, Ridgewood High School District 234, Township High School District 113, and Warren Township High School District 121",Lumity,none,27,1087,202,84,215,230,2592000,19211,9116,14990,7430,6647,4339,2938,678235,13085,,,,,,,,,,,, -IN,Indiana,4888,3.3,1578,54,-3310,No,No,No,Yes,No,Yes,Yes,Yes,Yes,No,,,,,74459,363955592,42940,1,17%,0.95%,1343,20%,107,44,1,0,152,77,18%,29,789,20%,66,30,1,0,14%,554,20%,41,14,0,0,10%,60%,Other,www.code.org/promote/IN,no school districts in the state,Nextech,none,6,2364,69,40,22,25,1191000,9013,4930,5001,3657,3529,3389,782,327546,7940,,,,,,,,,,,, -KS,Kansas,2951,2.9,338,43,-2613,No,No,No,Other,No,No,No,No,No,No,,,,,74957,221198107,43950,0,14%,0.34%,58,16%,1,1,0,0,2,13,10%,1,46,13%,1,1,0,0,9%,12,25%,0,0,0,0,2%,62%,No,www.code.org/promote/KS,no school districts in the state,Union Station Science City,none,2,524,0,2,0,0,695000,1833,528,1178,703,751,132,57,147096,3879,,Kansas is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress -KY,Kentucky,2614,3.5,434,34,-2180,Other,Other,Yes,Other,No,No,No,No,No,Yes,,,,,72202,188736028,41760,0,18%,0.96%,941,28%,45,30,7,0,82,61,23%,22,485,23%,24,9,3,0,14%,456,33%,21,21,4,0,16%,61%,Yes,www.code.org/promote/KY,Greenup County Schools (K-5),Advance KY,none,3,195,14,40,0,0,787000,4149,3327,2170,2342,1543,1503,538,209380,3260,Kentucky is in the process of developing a state plan for K-12 computer science. ,Kentucky is in the process of developing K-12 computer science standards.,,,,,,"Kentucky has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,,K-12 CS standards in progress -LA,Louisiana,2371,5.4,365,26,-2006,No,Yes,Yes,No,No,No,No,No,No,Yes,,,,,67604,160289084,41260,0,18%,0.46%,383,31%,32,93,1,0,126,37,13%,21,147,24%,11,28,1,0,7%,236,35%,21,65,0,0,7%,65%,No,www.code.org/promote/LA,no school districts in the state,none,none,3,475,0,2,0,1,373000,2050,1949,924,587,955,961,150,120422,3738,,,,,,,,,,,, -MA,Massachusetts,18048,3.1,1953,120,-16095,Other,Other,No,Yes,Yes,No,Yes,No,No,Yes,,,,,103237,1863221376,60840,0,23%,2.00%,3407,24%,316,231,2,3,552,168,37%,17,2165,22%,146,80,1,1,32%,1242,28%,170,151,1,2,16%,70%,Other,www.code.org/promote/MA,"Arlington Public Schools, Chelmsford School District, Littleton Public Schools, Milton Public Schools, Needham Public Schools, Newton Public Schools, Waltham Public Schools, and Wellesley Public Schools",BATEC,none,10,740,65,20,0,34,1736000,12508,8405,8389,7998,5064,3657,2279,294190,6305,Massachusetts is in the process of developing a state plan for K-12 computer science.,,,,,,,"Massachusetts has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, -MD,Maryland,21488,4.9,2923,122,-18565,Other,Yes,Yes,Other,Yes,Yes,Other,Yes,No,Yes,,,,,100812,2166248256,56120,0,20%,1.55%,4443,31%,345,578,0,3,926,150,42%,35,1927,24%,148,218,0,0,35%,2516,35%,197,360,0,3,31%,76%,Yes,www.code.org/promote/MD,"Baltimore City Public Schools, Calvert County Public Schools, Charles County Public Schools, Frederick County Public Schools, Howard County Public Schools, Montgomery County Public Schools, and Prince Georges County Public Schools",Maryland Codes,none,25,517,164,73,56,181,1607000,12485,5595,6738,6189,3452,4741,1935,391993,10032,Maryland is in the process of developing a state plan for K-12 computer science. ,Maryland is in the process of developing K-12 computer science standards.,,,,Maryland has dedicated computer science positions in local education authorities. The state should consider creating a statewide computer science leadership position within the state education authority to expand state-level implementation of computer science education initiatives.,,,,,,K-12 CS standards in progress -ME,Maine,1095,3.2,112,24,-983,No,No,No,No,No,No,No,No,No,No,,,,,76323,83573685,44180,0,16%,1.08%,246,20%,8,4,1,0,13,23,16%,0,151,17%,6,4,0,0,13%,95,24%,2,0,1,0,6%,73%,Yes,www.code.org/promote/ME,no school districts in the state,Educate Maine and the Maine Mathematics and Science Alliance,none,2,263,15,20,0,2,404000,1835,1002,1028,1019,557,352,165,69395,1964,,,,,,,,,,,, -MI,Michigan,14443,4.3,1793,78,-12650,No,Yes,Yes,Other,No,Yes,No,No,No,No,,,,https://www.votervoice.net/Code/campaigns/59886/respond,80478,1162343754,47350,6,16%,0.93%,1685,24%,56,30,0,1,87,85,13%,14,1025,23%,32,19,0,0,12%,660,25%,24,11,0,1,6%,61%,Yes,www.code.org/promote/MI,Utica Community Schools,Mason-Lake Oceana Mathematics and Science Center at West Shore ESD,none,8,464,14,85,29,4,2316000,11163,6698,4806,5708,5193,2430,962,483666,8070,,Michigan is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress -MN,Minnesota,13366,2.9,895,39,-12471,No,Yes,No,No,No,No,No,No,No,No,,,,,90134,1204731044,51330,0,15%,0.98%,1201,20%,56,27,3,1,87,59,18%,20,745,17%,24,11,2,0,15%,456,25%,32,16,1,1,8%,64%,Other,www.code.org/promote/MN,no school districts in the state,Twin Cities Public Television,none,5,1294,1,5,0,2,1563000,9034,4128,3164,4704,2038,999,694,343987,7034,,,,,,,,,,,, -MO,Missouri,11090,4.3,1138,47,-9952,No,No,No,No,No,No,No,No,No,No,,,,,82050,909934500,44620,0,17%,0.95%,631,20%,29,34,1,0,64,69,21%,22,466,16%,21,19,1,0,18%,165,33%,8,15,0,0,10%,71%,Other,www.code.org/promote/MO,no school districts in the state,Union Station Science City and Washington University at St. Louis Institute for School Partnership,none,4,810,0,3,0,0,1357000,3606,2269,2547,1716,1567,942,399,327398,6863,,,,,,,,,,,, -MS,Mississippi,1228,4.6,155,14,-1073,No,No,Yes,Yes,No,No,No,No,No,Yes,,,,,69507,85354596,38300,0,12%,0.11%,105,23%,11,12,0,0,23,13,7%,10,19,5%,3,3,0,0,3%,86,27%,8,9,0,0,6%,78%,No,www.code.org/promote/MS,no school districts in the state,Mississippi State University,none,1,255,2,1,0,0,150000,1076,933,493,387,813,165,16,99631,2829,,,,,,,,,,,, -MT,Montana,652,2.3,75,10,-577,No,No,Yes,Other,No,Yes,No,No,No,No,,,,,64375,41972500,41440,0,11%,0.18%,13,15%,2,0,0,0,2,2,2%,2,13,15%,2,0,0,0,2%,0,0%,0,0,0,0,0%,57%,Other,www.code.org/promote/MT,no school districts in the state,Teachers Teaching Tech,none,0,0,12,20,0,0,185000,485,374,120,341,116,4,9,44291,1290,,Montana is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress -NC,North Carolina,20184,5.1,1284,71,-18900,Yes,Yes,Yes,No,Yes,No,No,No,No,No,,,,,88971,1795790664,45280,0,20%,0.98%,2411,24%,163,178,6,2,349,95,15%,0,1435,24%,89,106,5,1,9%,976,25%,74,72,1,1,10%,69%,Yes,www.code.org/promote/NC,"Alamance-Burlington School System, Chatham County Schools, Durham Public Schools, Franklin County School, Granville County Schools, Johnston County Schools, Orange County Schools, Rockingham County Schools, Warren County Schools, and Wilson County Schools",The Friday Institute,none,9,2299,54,28,0,38,2456000,11770,6626,4421,10183,3806,12482,1425,497021,12077,,,,,,,,,,,, -ND,North Dakota,673,2.5,117,5,-556,No,Yes,Yes,No,No,No,No,No,No,No,,,,,70311,47319303,47130,0,7%,1.27%,96,11%,4,1,1,0,6,10,19%,7,40,3%,1,0,0,0,13%,56,18%,3,1,1,0,6%,0,No,www.code.org/promote/ND,no school districts in the state,Teachers Teaching Tech,none,1,10,0,0,0,0,104000,354,151,170,1,95,6,35,35481,1195,,,,,,,,,,,, -NE,Nebraska,2612,3.2,438,36,-2174,No,No,No,No,No,No,No,No,No,No,,,,,76542,199927704,44170,0,15%,0.67%,157,10%,8,2,2,0,12,19,21%,4,110,9%,5,1,0,0,18%,47,11%,3,1,2,0,9%,63%,No,www.code.org/promote/NE,Lincoln Public School,University of Nebraska at Lincoln,none,1,221,2,3,0,1,686000,1203,447,713,602,394,110,88,190490,2784,,,,,,,,,,,, -NH,New Hampshire,1475,2.2,391,24,-1084,Yes,Other,Yes,Other,No,No,Yes,Other,No,No,,,,,92945,137093875,50180,2,20%,1.34%,237,18%,5,2,1,0,8,20,17%,0,199,19%,3,1,1,0,14%,38,13%,2,1,0,0,8%,66%,Yes,www.code.org/promote/NH,no school districts in the state,UNH STEM Teachers' Collaborative,none,1,135,0,0,0,0,320000,1791,740,928,852,693,267,167,57775,1351,,New Hampshire is in the process of developing K-12 computer science standards.,,,,,"New Hampshire requires that all school districts offer instruction in computer science. However, the state could consider increasing access by requiring each school to offer at least one course.","New Hampshire has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,Requires all school districts to offer CS,K-12 CS standards in progress -NJ,New Jersey,25431,4.7,1111,165,-24320,No,Yes,No,Yes,Yes,No,No,Yes,No,No,,,,,102535,2607567585,56030,3,15%,2.21%,5232,26%,568,187,6,5,766,219,39%,29,3591,24%,344,124,4,3,37%,1641,32%,224,63,2,2,18%,75%,Yes,www.code.org/promote/NJ,Cresskill Public Schools,the College of New Jersey Center for Excellence in STEM Education,none,5,3350,15,16,0,4,5503000,15222,8598,11207,7042,6211,4300,3056,487990,10082,,,,,,,,,,,, -NM,New Mexico,1886,4,141,40,-1745,No,Yes,No,No,No,No,No,No,No,No,,,,,79230,149427780,44160,0,18%,0.47%,169,29%,67,1,1,0,69,18,14%,8,74,26%,19,1,0,0,12%,95,32%,48,0,1,0,8%,70%,Other,www.code.org/promote/NM,no school districts in the state,Explora Science Center and Children's Museum,none,6,446,0,1,0,0,264000,1428,752,567,500,468,234,79,73011,1764,,,,,,,,,,,, -NV,Nevada,2471,4,96,17,-2375,No,Yes,Yes,Yes,Yes,No,Yes,Yes,Yes,Yes,,,,,78204,193242084,44030,0,23%,0.30%,489,26%,125,18,3,1,147,27,24%,18,160,17%,36,6,1,1,15%,329,30%,89,12,2,0,18%,0,No,www.code.org/promote/NV,Clark County School District,Southern Nevada Regional Professional Development Program,none,12,1663,32,37,0,31,650000,2672,1934,1900,1395,894,1058,104,198196,5622,,,,,,,,,,,, -NY,New York,33873,4.5,3801,186,-30072,No,Other,Yes,No,Yes,No,No,No,No,No,,,,,100813,3414838749,58910,0,18%,1.35%,8036,32%,1180,640,13,13,1846,339,23%,139,3734,26%,383,203,0,5,16%,4302,38%,797,437,13,8,14%,70%,Yes,www.code.org/promote/NY,NYC Department of Education,Code/Interactive and WNY STEM Hub,none,8,1412,122,82,50,122,3612000,26049,18163,17568,9364,8498,8086,3761,947712,19796,,,,,,,,"New York has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, -OH,Ohio,15515,3.8,1137,139,-14378,No,Yes,Yes,Other,No,Yes,No,No,No,No,,,,,83959,1302623885,45930,0,18%,0.95%,2202,24%,82,85,4,0,171,131,18%,49,1287,19%,49,39,3,0,12%,915,30%,33,46,1,0,9%,65%,No,www.code.org/promote/OH,"Blanchester Local Schools, Canal Winchester Local Schools, Columbus City School District, Metro Early College High School, New Albany Plain Local Schools, Newark City Schools, Oak Hills Local School District, Reynoldsburg City School District, Strongsville School District, and Vermilion Local School District",Battelle Education,none,6,2075,40,38,16,32,1786000,13211,6122,6894,6512,4846,2546,1149,619999,10897,,Ohio is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress -OK,Oklahoma,2633,3.6,446,49,-2187,No,Yes,Yes,Yes,No,No,Yes,No,No,No,,,,,72036,189670788,42760,4,15%,0.61%,363,22%,28,27,9,0,64,29,10%,6,180,26%,12,19,5,0,7%,183,18%,16,8,4,0,5%,67%,Other,www.code.org/promote/OK,no school districts in the state,Oklahoma Public School Resource Center,none,3,270,10,20,0,1,438000,2734,1636,1669,1097,1204,773,187,136107,3291,,,,,,,,,,,, -OR,Oregon,5793,2.9,537,26,-5256,No,Other,No,No,No,No,No,No,No,No,,,,,86352,500237136,49710,0,15%,0.88%,436,20%,29,2,3,0,34,25,11%,10,283,17%,21,2,1,0,7%,153,25%,8,0,2,0,6%,57%,Yes,www.code.org/promote/OR,Beaverton School District,George Fox University,none,2,656,0,1,0,0,943000,3172,1495,1372,1388,1173,1005,281,235467,5696,,,,,,,,"Oregon allows schools to count computer science for a core graduation requirement. The policy is not written down and publicly accessible, but we are working with the state to release public documentation.",,,, -PA,Pennsylvania,19752,3.7,2969,191,-16783,No,Yes,No,Yes,Yes,No,No,No,No,No,,,,,85654,1691837808,47540,0,20%,1.48%,3058,22%,146,84,2,0,232,206,26%,37,1952,18%,91,48,1,0,23%,1106,28%,55,36,1,0,11%,71%,Other,www.code.org/promote/PA,no school districts in the state,Delaware County Intermediate Unit and Allegheny Intermediate Unit 3,none,4,2687,14,26,0,5,2512000,14524,7550,8611,7187,6102,3048,1891,733178,13335,,,,,,,,"Pennsylvania has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, -RI,Rhode Island,1690,3.8,348,13,-1342,Yes,Other,No,Yes,Yes,No,No,Other,No,No,,,,,90037,152162530,51920,0,17%,0.79%,337,23%,26,5,0,1,32,29,41%,15,146,21%,14,2,0,0,17%,191,24%,12,3,0,1,29%,0,No,www.code.org/promote/RI,no school districts in the state,University of Rhode Island,the State of Rhode Island,4,1062,0,2,0,0,366000,1265,877,884,569,485,438,94,94443,2669,,,,,,,Rhode Island is working towards bringing computer science to all secondary schools.,"Rhode Island allows computer science to count for a core graduation requirement. This policy is not written down and publicly accessible, but we are working with the state to release public documentation. ",,,Working towards all high schools to offer CS, -SC,South Carolina,4342,3.9,529,51,-3813,No,No,Yes,Yes,No,No,No,No,No,No,,,,,75259,326774578,41530,0,25%,0.76%,770,28%,58,69,3,0,130,48,16%,16,437,27%,37,46,1,0,12%,333,28%,21,23,2,0,8%,73%,Yes,www.code.org/promote/SC,no school districts in the state,the STEM Center of Excellence at the Citadel,none,4,381,10,16,0,0,1690000,4311,2940,1987,2425,1435,1119,374,217918,5869,,,,,,,,,,,, -SD,South Dakota,678,2.7,145,19,-533,No,No,No,No,No,No,No,No,No,No,,,,,65516,44419848,40070,0,18%,0.62%,35,9%,0,1,0,0,1,4,5%,0,16,19%,0,1,0,0,5%,19,0%,0,0,0,0,1%,52%,Other,www.code.org/promote/SD,no school districts in the state,Teachers Teaching Tech,none,4,1090,1,3,0,2,192000,515,300,231,177,276,118,26,76799,2273,,,,,,,,,,,, -TN,Tennessee,6444,4.6,625,30,-5819,No,Yes,Other,No,No,No,No,No,No,No,,,,,75784,488352096,42350,0,18%,0.71%,934,29%,54,133,1,0,188,50,14%,18,356,28%,13,17,1,0,8%,578,30%,41,116,0,0,9%,63%,Other,www.code.org/promote/TN,no school districts in the state,Tennessee Department of Education,none,5,1303,11,20,0,3,864000,4185,2754,2683,2285,2128,1431,395,291524,6434,,,,Tennessee is in the process of developing clear certification pathways for computer science teachers.,,,,,,,, -TX,Texas,42725,4.4,2714,376,-40011,No,Yes,Yes,No,No,Yes,No,Yes,No,Yes,,,,,91000,3887975000,47770,15,18%,1.12%,8925,27%,2362,327,23,10,2722,399,22%,63,6626,25%,1443,202,19,8,22%,2299,33%,919,125,4,2,9%,70%,No,www.code.org/promote/TX,"Aldine Independent School District, Dallas Independent School District, Grapevine-Colleyville ISD, and Houston Independent School District","Rice University, Center for STEM Education at the University of Texas at Austin, and the University of Texas at Dallas",none,21,7785,89,75,69,57,4361000,33394,19894,44795,16459,12610,14059,6060,1232189,34912,,,,,,,,,,,, -UT,Utah,5371,3.3,366,18,-5005,Other,Yes,Yes,No,Yes,Yes,No,No,No,No,,,,,81018,435147678,45490,1,10%,0.31%,405,17%,30,4,1,1,36,33,17%,19,233,17%,20,4,0,0,8%,172,17%,10,0,1,1,10%,65%,No,www.code.org/promote/UT,Canyons School District and Provo Public Schools,Utah STEM Action Center and Utah Board of Education,none,17,743,55,41,29,53,1142000,4441,1676,1923,2358,972,510,129,375203,6629,Utah is in the process of developing a state plan for K-12 computer science. ,,,,,,,,,,, -VA,Virginia,37525,4.9,1570,102,-35955,No,Yes,Yes,Yes,Yes,Yes,No,Yes,Yes,No,,,,,102773,3856556825,53090,0,18%,1.85%,4251,26%,314,277,4,5,600,134,29%,3,3117,25%,216,170,2,4,26%,1134,31%,98,107,2,1,12%,64%,No,www.code.org/promote/VA,no school districts in the state,CodeVA,none,13,1220,141,65,104,111,1747000,14172,6798,8143,6752,4142,6306,2856,442283,12721,,,,,,,,,,,, -VT,Vermont,660,2.6,163,10,-497,No,No,Yes,No,No,Yes,No,No,No,No,,,,,78681,51929460,47620,0,18%,1.09%,128,20%,4,0,0,0,4,12,16%,3,66,9%,1,0,0,0,15%,62,31%,3,0,0,0,10%,62%,Other,www.code.org/promote/VT,no school districts in the state,none,none,1,110,0,0,0,0,179000,825,591,320,395,308,134,70,23934,844,,,,,,,,,,,, -WA,Washington ,16258,2.5,1212,62,-15046,No,Yes,Yes,Yes,Yes,Yes,Yes,No,No,Yes,,,,,107853,1753474074,55810,0,21%,2.23%,2637,28%,199,43,8,9,259,135,31%,37,1900,29%,119,21,6,4,23%,737,26%,80,22,2,5,14%,65%,No,www.code.org/promote/WA,"Bainbridge Island School District, Bellevue School District, Bremerton School District, Central Valley School District, Cheney School District, Clover Park School District, East Valley School District, Eatonville School District, Enumclaw School District, Everett Public Schools, Franklin Pierce School District, Highline School District, Marysville School District, Shoreline School District, Spokane Public Schools, Tacoma Public Schools, Tukwila School District, and West Valley School District",NorthEast Washington Educational Service District 101 and Puget Sound Educational Service District,none,34,1782,137,78,117,129,5022000,9383,4384,4607,3543,3247,2946,1945,814429,27479,,,,,,,,,,,, -WI,Wisconsin,7673,2.9,918,67,-6755,No,Yes,Yes,Yes,No,Yes,No,No,No,No,,,,,75912,582472776,45240,2,15%,0.79%,1036,17%,47,7,1,0,55,68,13%,8,572,14%,26,5,0,0,11%,464,20%,21,2,1,0,8%,61%,Other,www.code.org/promote/WI,Janesville School District,Marquette University,none,4,1283,22,24,4,0,1402000,8246,4106,4116,3919,2755,1560,591,291450,7143,,,,,,,,,,,, -WV,West Virginia,1329,4.6,158,10,-1171,No,Yes,Yes,Yes,No,No,No,Yes,No,No,,,,,71150,94558350,40250,0,11%,0.73%,246,36%,7,2,1,0,10,15,12%,0,128,34%,2,0,1,0,7%,118,38%,5,2,0,0,7%,64%,Other,www.code.org/promote/WV,no school districts in the state,West Virginia University Center for Excellence in STEM Education,none,0,0,0,1,0,0,212000,1075,834,303,455,446,371,97,63731,1447,,,,,,,,,,,, -WY,Wyoming,360,4.6,25,3,-335,Yes,Yes,Yes,Other,Other,No,No,Yes,Yes,Yes,,,,,63223,22760280,46840,0,8%,0.21%,21,24%,0,0,0,0,0,5,13%,1,8,13%,0,0,0,0,10%,13,31%,0,0,0,0,5%,0,No,www.code.org/promote/WY,no school districts in the state,Teachers Teaching Tech,none,1,549,0,0,0,0,109000,376,177,186,130,85,80,6,48346,1536,,Wyoming is in the process of developing K-12 computer science standards.,Wyoming encourages the use of state funds for computer science or computer science professional development. Wyoming has an opportunity to expand computer science by designating state funds for computer science. ,,,,,,,No dedicated state funding for CS PD,,K-12 CS standards in progress -Sum_states,,557903,,49291,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +state_code_s!,state_name_s,cs_jobs_i,growth_vs_average_f,cs_graduates_i,count_schools_teach_cs_i,job_student_gap_i,state_plan_s,cs_counts_t,cs_teacher_cert_s,cs_standards_s,pd_funding_s,pre_service_s,state_position_s,require_hs_s,require_k12_s,higher_ed_entrance_s,text_t,petition_url_t,action_url_s,action_text_s,avg_sal_computing_i,sal_x_jobs_bi,avg_sal_all_i,preservice_prepared_i,percent_female_cs_grad_i,percent_cs_exams_f,ap_cs_exams_i,percent_ap_female_i,ap_hispanic_i,ap_black_i,ap_native_american_i,ap_hawaiian_i,total_ap_students_color_i,schools_ap_cs_i,percent_schools_ap_cs_i,number_additional_schools_i,ap_csa_exams_i,percent_ap_csa_female_i,ap_csa_hispanic_i,ap_csa_black_i,ap_csa_native_american_i,ap_csa_hawaiian_i,percent_schools_ap_csa_i,ap_csp_exams_i,percent_ap_csp_female_i,ap_csp_hispanic_i,ap_csp_black_i,ap_csp_native_american_i,ap_csp_hawaiian_i,percent_schools_ap_csp_i,principals_core_i,principals_barrier_s,website_url_s,school_district_partners_t,professional_learning_partners_t,other_partners_t,num_affiliates_i,num_elementary_trained_i,num_ecs_csd_i,num_csp_i,num_ms_trained_i,num_hs_trained_i,es_using_codeorg_i,ms_using_codeorg_i,hs_using_codeorg_i,female_codeorg_i,urm_codeorg_i,highneed_codeorg_i,rural_codeorg_i,num_hoc_i,ap_calc_i,ap_bio_i,ap_phy_i,ap_stats_i,ap_chem_i,ap_env_sci_i,ap_cs_i,student_studio_acct_i,teacher_studio_acct_i,policy_0_t,policy_1_t,policy_2_t,policy_3_t,policy_4_t,policy_5_t,policy_6_t,policy_7_t,policy_8_t,pd_funding_exception_s,require_hs_exception_s,cs_standards_exception_s +AK,Alaska,759,3.7,25,5,-734,No,No,No,Other,No,No,No,No,No,No,,,,,84747,64322973,56710,0,16%,1.07%,68,25%,4,0,1,0,5,6,8%,3,26,19%,1,0,0,0,5%,42,29%,3,0,1,0,4%,0,No,www.code.org/promote/AK,no school districts in the state,Alaska Staff Development Network,none,0,0,0,1,0,0,,,,,,,,147000,789,264,288,273,308,104,60,36228,1452,,Alaska is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress +AL,Alabama,5230,5.2,503,26,-4727,No,Yes,No,Yes,Yes,No,No,No,No,No,,,,,82893,433530390,42510,0,21%,0.59%,1520,30%,77,157,7,2,243,86,25%,58,271,20%,8,14,1,1,7%,1249,33%,69,143,6,1,23%,69%,Other,www.code.org/promote/AL,no school districts in the state,A+ College Ready,none,4,1557,18,60,0,31,,,,,,,,779000,4065,4556,2144,1890,3189,1335,303,226638,6532,,,,,,,,,,,, +AR,Arkansas,2123,3.8,328,19,-1795,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,,,,,70458,149582334,39590,0,12%,0.64%,870,26%,121,90,5,5,221,50,16%,23,378,21%,59,41,1,3,8%,492,31%,62,49,4,2,12%,73%,No,www.code.org/promote/AR,no school districts in the state,none,none,2,2331,0,0,0,1,,,,,,,,419000,2991,2884,1818,1859,1722,1025,304,261412,5519,,,,,,,,,,,, +AZ,Arizona,10434,3.3,546,33,-9888,No,Other,Yes,Other,Other,No,No,No,No,No,,,,,84866,885491844,46290,0,15%,0.65%,738,22%,138,12,3,0,153,52,16%,21,480,23%,67,7,1,0,13%,258,20%,71,5,2,0,8%,63%,Other,www.code.org/promote/AZ,Paradise Valley Unified School District and Phoenix Union High School District,Grand Canyon University and Science Foundation Arizona,none,5,2536,68,37,10,39,,,,,,,,993000,6745,3239,4012,2082,2222,973,438,410706,10228,,Arizona is in the process of developing K-12 computer science standards.,Arizona has allocated funding for rigorous computer science professional development and course support (with an emphasis on Native American students).,,,,,"Arizona has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,"Dedicated state funding for CS PD, emphasis on Native American students",,K-12 CS standards in progress +CA,California,72972,3.8,4029,311,-68943,Other,Other,Yes,Yes,No,No,Other,No,No,Yes,,,,,110078,8032611816,56840,0,16%,1.38%,18828,29%,4146,345,26,48,4565,580,25%,210,10268,27%,1469,138,13,25,19%,8560,32%,2677,207,13,23,14%,70%,Other,www.code.org/promote/CA,"Alliance College Ready Public Schools, Anaheim Union High School District, Benicia Unified School District, Brentwood Union School District, Cajon Valley School District, Calistoga Joint Unified School District, Central Unified School District, Corona-Norco Unified School District, Covina Valley Unified School District, Fairfield-Suisun Unified School District, Fontana Unified School District, Granada Hills Charter High School, John Swett Unified School District, Jurupa Unified School District, Liberty Union High School District, Los Angeles Unified School District, Martinez Unified School District, Moraga Elementary School District, Mt. Diablo Unified School District, Oakland Unified Public Schools, Orange Unified School District, Perris Union High School District, Pittsburg Unified School District, Placentia-Yorba Linda Union School District, Riverside Unified School District, Saddleback Valley Unified School District, San Jacinto Unified School District, Temecula Valley Unified School District, Val Verde Unified School District, and Whittier Union High School District","9 Dots Community Learning Center, Alameda County Office of Education, Contra Costa County Office of Education, Elementary Institute of Science, Fresno County Office of the Superintendent, LAUSD, Riverside County Office of Education, Sacramento County Office of Education, and Silicon Valley Education Foundation",none,69,9472,258,203,121,247,,,,,,,,11345000,74006,38045,32699,32145,21572,26444,10244,2238509,62718,California is in the process of developing a state plan for K-12 computer science.,California is in the process of developing K-12 computer science standards.,,,,California has a dedicated state board member focused on computer science education. California has an opportunity to make more progress in computer science education by creating a position at the state education authority and creating local leadership positions across the state.,,"California has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,,K-12 CS standards in progress +CO,Colorado,16285,3.3,785,69,-15500,No,Other,No,No,Yes,No,No,No,No,Yes,,,,,98597,1605652145,52710,1,15%,0.97%,1437,19%,219,30,7,3,259,96,26%,43,860,18%,114,12,3,0,16%,577,21%,105,18,4,3,15%,61%,Yes,www.code.org/promote/CO,Denver Public Schools and Douglas County Schools,mindSpark Learning,none,4,413,26,42,0,15,,,,,,,,1881000,8517,4015,4766,3778,2818,2490,780,310802,5678,,,,,,,,"Colorado has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, +CT,Connecticut,7544,4,404,65,-7140,Other,No,No,Yes,No,No,Yes,No,No,No,,,,,96862,730726928,57960,0,15%,1.46%,1872,27%,146,83,3,0,232,96,37%,27,983,24%,61,32,1,0,30%,889,31%,85,51,2,0,20%,66%,Yes,www.code.org/promote/CT,no school districts in the state,none,none,2,559,0,4,0,2,,,,,,,,941000,6314,3967,4492,3781,2552,2000,939,205373,3950,Connecticut is in the process of developing a state plan for K-12 computer science.,,,,,,,,,,, +DC,District of Columbia,10504,4.5,133,12,-10371,No,Other,Yes,No,No,No,No,No,No,No,,,,,108215,1136690360,82950,0,41%,1.51%,233,31%,35,59,1,1,96,15,29%,4,139,26%,21,28,1,1,21%,94,39%,14,31,0,0,17%,0,No,www.code.org/promote/DC,no school districts in the state,none,none,0,0,0,1,0,0,,,,,,,,155000,911,567,587,424,378,509,176,36573,1034,,,,,,,,"District of Columbia allows computer science to count for a core graduation requirement. This policy is not written down and publicly accessible, but we are working with them to release public documentation.",,,, +DE,Delaware,2731,4.4,192,11,-2539,No,Yes,No,Yes,No,No,No,Yes,No,No,,,,,95926,261973906,50930,0,23%,1.38%,292,23%,10,20,0,0,30,14,20%,3,158,21%,4,10,0,0,13%,134,25%,6,10,0,0,14%,0,No,www.code.org/promote/DE,no school districts in the state,none,none,0,0,0,1,0,0,,,,,,,,225000,1178,812,592,844,521,420,166,71247,1270,,,,,,,,,,,, +FL,Florida,22816,4,2486,125,-20330,No,Yes,Yes,Yes,No,No,Yes,Yes,No,No,,,,,78531,1791763296,44050,0,19%,0.71%,7233,25%,2199,598,17,9,2823,241,22%,95,2404,21%,717,139,5,4,13%,4829,27%,1482,459,12,5,16%,67%,No,www.code.org/promote/FL,"Broward County Schools, Duval County Public Schools, Miami-Dade County Public Schools, One Clay County School District, School District of Clay County, School District of Palm Beach County, and Florida International University School of Computing and Information Sciences ","Broward County Public Schools, Florida State College Jacksonville, Orlando Science Center, Florida International University School of Computing and Information Sciences, and Tampa Bay STEM Network",none,49,5253,194,154,140,259,,,,,,,,3571000,20506,13774,12671,13261,7635,16625,2688,996792,28786,,,,,,,,,,,, +GA,Georgia,20137,4.4,1747,133,-18390,Other,Yes,Yes,No,Yes,No,Yes,No,No,Yes,,,,,90351,1819398087,46540,0,19%,1.19%,3856,24%,344,356,5,5,710,154,25%,27,1914,22%,178,170,1,1,20%,1942,25%,166,186,4,4,15%,71%,Yes,www.code.org/promote/GA,"Fayette County Public Schools, Forsyth County Schools, Fulton County Schools, and Gwinnett County Public Schools","Georgia Tech Center for Education Integrating Science, Mathematics, and Computing",none,16,3351,48,84,38,73,,,,,,,,2211000,11781,8298,8379,7671,4528,7380,2033,684713,15985,Georgia is in the process of developing a state plan for K-12 computer science. ,,,,,,,,,,, +HI,Hawaii,1577,5.2,155,8,-1422,Yes,No,No,Yes,Yes,No,Yes,Yes,No,No,,,,,80734,127317518,49430,0,17%,1.32%,290,32%,43,1,0,12,56,16,19%,4,88,30%,14,0,0,8,5%,202,33%,29,1,0,4,16%,0,No,www.code.org/promote/HI,no school districts in the state,MEDB's Women in Technology,none,1,693,1,0,0,0,,,,,,,,254000,1481,1069,1288,729,523,627,188,113743,2598,,,,,,,,,,,, +IA,Iowa,4424,3.5,364,33,-4060,No,No,Yes,Yes,Yes,No,No,Other,No,No,,,,,79062,349770288,43540,0,14%,1.00%,340,17%,21,9,0,0,30,31,15%,14,233,16%,11,5,0,0,10%,107,20%,10,4,0,0,8%,67%,Yes,www.code.org/promote/IA,no school districts in the state,New Bohemian Innovation Collaborative,none,4,1394,10,23,0,2,,,,,,,,904000,1958,1056,787,988,1004,533,211,278179,5495,,,,,,,Iowa is working towards bringing computer science to all secondary schools.,,,,Working towards all high schools to offer CS, +ID,Idaho,1593,3.4,333,7,-1260,No,Yes,Yes,Yes,Yes,Yes,Yes,Yes,No,Yes,,,,,71648,114135264,41910,0,13%,0.52%,315,29%,39,0,0,0,39,19,19%,12,123,24%,8,0,0,0,8%,192,33%,31,0,0,0,16%,66%,Other,www.code.org/promote/ID,no school districts in the state,Idaho Digital Learning Academy,none,11,602,34,20,64,37,,,,,,,,434000,1143,631,745,457,322,310,59,98165,2361,,,,,,,,,,,, +IL,Illinois,27187,3.9,1768,132,-25419,No,Yes,Yes,No,No,No,No,No,No,Yes,,,,,89465,2432284955,51500,1,13%,1.41%,4909,23%,714,127,4,3,848,157,22%,34,3135,22%,330,63,4,2,21%,1774,25%,384,64,0,1,11%,65%,No,www.code.org/promote/IL,"Chicago Public Schools, Community High School District 117, Community Unit School District 300, Elmhurst Community Unit School District 205, Lake Zurich Community Unit School District 95, New Trier Township District 203, Northern Suburban Special Education District 804, Ridgewood High School District 234, Township High School District 113, and Warren Township High School District 121",Lumity,none,27,1087,202,84,215,230,,,,,,,,2592000,19211,9116,14990,7430,6647,4339,2938,678235,13085,,,,,,,,,,,, +IN,Indiana,4888,3.3,1578,54,-3310,No,No,No,Yes,No,Yes,Yes,Yes,Yes,No,,,,,74459,363955592,42940,1,17%,0.95%,1343,20%,107,44,1,0,152,77,18%,29,789,20%,66,30,1,0,14%,554,20%,41,14,0,0,10%,60%,Other,www.code.org/promote/IN,no school districts in the state,Nextech,none,6,2364,69,40,22,25,,,,,,,,1191000,9013,4930,5001,3657,3529,3389,782,327546,7940,,,,,,,,,,,, +KS,Kansas,2951,2.9,338,43,-2613,No,No,No,Other,No,No,No,No,No,No,,,,,74957,221198107,43950,0,14%,0.34%,58,16%,1,1,0,0,2,13,10%,1,46,13%,1,1,0,0,9%,12,25%,0,0,0,0,2%,62%,No,www.code.org/promote/KS,no school districts in the state,Union Station Science City,none,2,524,0,2,0,0,,,,,,,,695000,1833,528,1178,703,751,132,57,147096,3879,,Kansas is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress +KY,Kentucky,2614,3.5,434,34,-2180,Other,Other,Yes,Other,No,No,No,No,No,Yes,,,,,72202,188736028,41760,0,18%,0.96%,941,28%,45,30,7,0,82,61,23%,22,485,23%,24,9,3,0,14%,456,33%,21,21,4,0,16%,61%,Yes,www.code.org/promote/KY,Greenup County Schools (K-5),Advance KY,none,3,195,14,40,0,0,,,,,,,,787000,4149,3327,2170,2342,1543,1503,538,209380,3260,Kentucky is in the process of developing a state plan for K-12 computer science. ,Kentucky is in the process of developing K-12 computer science standards.,,,,,,"Kentucky has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,,K-12 CS standards in progress +LA,Louisiana,2371,5.4,365,26,-2006,No,Yes,Yes,No,No,No,No,No,No,Yes,,,,,67604,160289084,41260,0,18%,0.46%,383,31%,32,93,1,0,126,37,13%,21,147,24%,11,28,1,0,7%,236,35%,21,65,0,0,7%,65%,No,www.code.org/promote/LA,no school districts in the state,none,none,3,475,0,2,0,1,,,,,,,,373000,2050,1949,924,587,955,961,150,120422,3738,,,,,,,,,,,, +MA,Massachusetts,18048,3.1,1953,120,-16095,Other,Other,No,Yes,Yes,No,Yes,No,No,Yes,,,,,103237,1863221376,60840,0,23%,2.00%,3407,24%,316,231,2,3,552,168,37%,17,2165,22%,146,80,1,1,32%,1242,28%,170,151,1,2,16%,70%,Other,www.code.org/promote/MA,"Arlington Public Schools, Chelmsford School District, Littleton Public Schools, Milton Public Schools, Needham Public Schools, Newton Public Schools, Waltham Public Schools, and Wellesley Public Schools",BATEC,none,10,740,65,20,0,34,,,,,,,,1736000,12508,8405,8389,7998,5064,3657,2279,294190,6305,Massachusetts is in the process of developing a state plan for K-12 computer science.,,,,,,,"Massachusetts has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, +MD,Maryland,21488,4.9,2923,122,-18565,Other,Yes,Yes,Other,Yes,Yes,Other,Yes,No,Yes,,,,,100812,2166248256,56120,0,20%,1.55%,4443,31%,345,578,0,3,926,150,42%,35,1927,24%,148,218,0,0,35%,2516,35%,197,360,0,3,31%,76%,Yes,www.code.org/promote/MD,"Baltimore City Public Schools, Calvert County Public Schools, Charles County Public Schools, Frederick County Public Schools, Howard County Public Schools, Montgomery County Public Schools, and Prince Georges County Public Schools",Maryland Codes,none,25,517,164,73,56,181,,,,,,,,1607000,12485,5595,6738,6189,3452,4741,1935,391993,10032,Maryland is in the process of developing a state plan for K-12 computer science. ,Maryland is in the process of developing K-12 computer science standards.,,,,Maryland has dedicated computer science positions in local education authorities. The state should consider creating a statewide computer science leadership position within the state education authority to expand state-level implementation of computer science education initiatives.,,,,,,K-12 CS standards in progress +ME,Maine,1095,3.2,112,24,-983,No,No,No,No,No,No,No,No,No,No,,,,,76323,83573685,44180,0,16%,1.08%,246,20%,8,4,1,0,13,23,16%,0,151,17%,6,4,0,0,13%,95,24%,2,0,1,0,6%,73%,Yes,www.code.org/promote/ME,no school districts in the state,Educate Maine and the Maine Mathematics and Science Alliance,none,2,263,15,20,0,2,,,,,,,,404000,1835,1002,1028,1019,557,352,165,69395,1964,,,,,,,,,,,, +MI,Michigan,14443,4.3,1793,78,-12650,No,Yes,Yes,Other,No,Yes,No,No,No,No,,,,https://www.votervoice.net/Code/campaigns/59886/respond,80478,1162343754,47350,6,16%,0.93%,1685,24%,56,30,0,1,87,85,13%,14,1025,23%,32,19,0,0,12%,660,25%,24,11,0,1,6%,61%,Yes,www.code.org/promote/MI,Utica Community Schools,Mason-Lake Oceana Mathematics and Science Center at West Shore ESD,none,8,464,14,85,29,4,,,,,,,,2316000,11163,6698,4806,5708,5193,2430,962,483666,8070,,Michigan is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress +MN,Minnesota,13366,2.9,895,39,-12471,No,Yes,No,No,No,No,No,No,No,No,,,,,90134,1204731044,51330,0,15%,0.98%,1201,20%,56,27,3,1,87,59,18%,20,745,17%,24,11,2,0,15%,456,25%,32,16,1,1,8%,64%,Other,www.code.org/promote/MN,no school districts in the state,Twin Cities Public Television,none,5,1294,1,5,0,2,,,,,,,,1563000,9034,4128,3164,4704,2038,999,694,343987,7034,,,,,,,,,,,, +MO,Missouri,11090,4.3,1138,47,-9952,No,No,No,No,No,No,No,No,No,No,,,,,82050,909934500,44620,0,17%,0.95%,631,20%,29,34,1,0,64,69,21%,22,466,16%,21,19,1,0,18%,165,33%,8,15,0,0,10%,71%,Other,www.code.org/promote/MO,no school districts in the state,Union Station Science City and Washington University at St. Louis Institute for School Partnership,none,4,810,0,3,0,0,,,,,,,,1357000,3606,2269,2547,1716,1567,942,399,327398,6863,,,,,,,,,,,, +MS,Mississippi,1228,4.6,155,14,-1073,No,No,Yes,Yes,No,No,No,No,No,Yes,,,,,69507,85354596,38300,0,12%,0.11%,105,23%,11,12,0,0,23,13,7%,10,19,5%,3,3,0,0,3%,86,27%,8,9,0,0,6%,78%,No,www.code.org/promote/MS,no school districts in the state,Mississippi State University,none,1,255,2,1,0,0,,,,,,,,150000,1076,933,493,387,813,165,16,99631,2829,,,,,,,,,,,, +MT,Montana,652,2.3,75,10,-577,No,No,Yes,Other,No,Yes,No,No,No,No,,,,,64375,41972500,41440,0,11%,0.18%,13,15%,2,0,0,0,2,2,2%,2,13,15%,2,0,0,0,2%,0,0%,0,0,0,0,0%,57%,Other,www.code.org/promote/MT,no school districts in the state,Teachers Teaching Tech,none,0,0,12,20,0,0,,,,,,,,185000,485,374,120,341,116,4,9,44291,1290,,Montana is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress +NC,North Carolina,20184,5.1,1284,71,-18900,Yes,Yes,Yes,No,Yes,No,No,No,No,No,,,,,88971,1795790664,45280,0,20%,0.98%,2411,24%,163,178,6,2,349,95,15%,0,1435,24%,89,106,5,1,9%,976,25%,74,72,1,1,10%,69%,Yes,www.code.org/promote/NC,"Alamance-Burlington School System, Chatham County Schools, Durham Public Schools, Franklin County School, Granville County Schools, Johnston County Schools, Orange County Schools, Rockingham County Schools, Warren County Schools, and Wilson County Schools",The Friday Institute,none,9,2299,54,28,0,38,,,,,,,,2456000,11770,6626,4421,10183,3806,12482,1425,497021,12077,,,,,,,,,,,, +ND,North Dakota,673,2.5,117,5,-556,No,Yes,Yes,No,No,No,No,No,No,No,,,,,70311,47319303,47130,0,7%,1.27%,96,11%,4,1,1,0,6,10,19%,7,40,3%,1,0,0,0,13%,56,18%,3,1,1,0,6%,0,No,www.code.org/promote/ND,no school districts in the state,Teachers Teaching Tech,none,1,10,0,0,0,0,,,,,,,,104000,354,151,170,1,95,6,35,35481,1195,,,,,,,,,,,, +NE,Nebraska,2612,3.2,438,36,-2174,No,No,No,No,No,No,No,No,No,No,,,,,76542,199927704,44170,0,15%,0.67%,157,10%,8,2,2,0,12,19,21%,4,110,9%,5,1,0,0,18%,47,11%,3,1,2,0,9%,63%,No,www.code.org/promote/NE,Lincoln Public School,University of Nebraska at Lincoln,none,1,221,2,3,0,1,,,,,,,,686000,1203,447,713,602,394,110,88,190490,2784,,,,,,,,,,,, +NH,New Hampshire,1475,2.2,391,24,-1084,Yes,Other,Yes,Other,No,No,Yes,Other,No,No,,,,,92945,137093875,50180,2,20%,1.34%,237,18%,5,2,1,0,8,20,17%,0,199,19%,3,1,1,0,14%,38,13%,2,1,0,0,8%,66%,Yes,www.code.org/promote/NH,no school districts in the state,UNH STEM Teachers' Collaborative,none,1,135,0,0,0,0,,,,,,,,320000,1791,740,928,852,693,267,167,57775,1351,,New Hampshire is in the process of developing K-12 computer science standards.,,,,,"New Hampshire requires that all school districts offer instruction in computer science. However, the state could consider increasing access by requiring each school to offer at least one course.","New Hampshire has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,Requires all school districts to offer CS,K-12 CS standards in progress +NJ,New Jersey,25431,4.7,1111,165,-24320,No,Yes,No,Yes,Yes,No,No,Yes,No,No,,,,,102535,2607567585,56030,3,15%,2.21%,5232,26%,568,187,6,5,766,219,39%,29,3591,24%,344,124,4,3,37%,1641,32%,224,63,2,2,18%,75%,Yes,www.code.org/promote/NJ,Cresskill Public Schools,the College of New Jersey Center for Excellence in STEM Education,none,5,3350,15,16,0,4,,,,,,,,5503000,15222,8598,11207,7042,6211,4300,3056,487990,10082,,,,,,,,,,,, +NM,New Mexico,1886,4,141,40,-1745,No,Yes,No,No,No,No,No,No,No,No,,,,,79230,149427780,44160,0,18%,0.47%,169,29%,67,1,1,0,69,18,14%,8,74,26%,19,1,0,0,12%,95,32%,48,0,1,0,8%,70%,Other,www.code.org/promote/NM,no school districts in the state,Explora Science Center and Children's Museum,none,6,446,0,1,0,0,,,,,,,,264000,1428,752,567,500,468,234,79,73011,1764,,,,,,,,,,,, +NV,Nevada,2471,4,96,17,-2375,No,Yes,Yes,Yes,Yes,No,Yes,Yes,Yes,Yes,,,,,78204,193242084,44030,0,23%,0.30%,489,26%,125,18,3,1,147,27,24%,18,160,17%,36,6,1,1,15%,329,30%,89,12,2,0,18%,0,No,www.code.org/promote/NV,Clark County School District,Southern Nevada Regional Professional Development Program,none,12,1663,32,37,0,31,,,,,,,,650000,2672,1934,1900,1395,894,1058,104,198196,5622,,,,,,,,,,,, +NY,New York,33873,4.5,3801,186,-30072,No,Other,Yes,No,Yes,No,No,No,No,No,,,,,100813,3414838749,58910,0,18%,1.35%,8036,32%,1180,640,13,13,1846,339,23%,139,3734,26%,383,203,0,5,16%,4302,38%,797,437,13,8,14%,70%,Yes,www.code.org/promote/NY,NYC Department of Education,Code/Interactive and WNY STEM Hub,none,8,1412,122,82,50,122,,,,,,,,3612000,26049,18163,17568,9364,8498,8086,3761,947712,19796,,,,,,,,"New York has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, +OH,Ohio,15515,3.8,1137,139,-14378,No,Yes,Yes,Other,No,Yes,No,No,No,No,,,,,83959,1302623885,45930,0,18%,0.95%,2202,24%,82,85,4,0,171,131,18%,49,1287,19%,49,39,3,0,12%,915,30%,33,46,1,0,9%,65%,No,www.code.org/promote/OH,"Blanchester Local Schools, Canal Winchester Local Schools, Columbus City School District, Metro Early College High School, New Albany Plain Local Schools, Newark City Schools, Oak Hills Local School District, Reynoldsburg City School District, Strongsville School District, and Vermilion Local School District",Battelle Education,none,6,2075,40,38,16,32,,,,,,,,1786000,13211,6122,6894,6512,4846,2546,1149,619999,10897,,Ohio is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress +OK,Oklahoma,2633,3.6,446,49,-2187,No,Yes,Yes,Yes,No,No,Yes,No,No,No,,,,,72036,189670788,42760,4,15%,0.61%,363,22%,28,27,9,0,64,29,10%,6,180,26%,12,19,5,0,7%,183,18%,16,8,4,0,5%,67%,Other,www.code.org/promote/OK,no school districts in the state,Oklahoma Public School Resource Center,none,3,270,10,20,0,1,,,,,,,,438000,2734,1636,1669,1097,1204,773,187,136107,3291,,,,,,,,,,,, +OR,Oregon,5793,2.9,537,26,-5256,No,Other,No,No,No,No,No,No,No,No,,,,,86352,500237136,49710,0,15%,0.88%,436,20%,29,2,3,0,34,25,11%,10,283,17%,21,2,1,0,7%,153,25%,8,0,2,0,6%,57%,Yes,www.code.org/promote/OR,Beaverton School District,George Fox University,none,2,656,0,1,0,0,,,,,,,,943000,3172,1495,1372,1388,1173,1005,281,235467,5696,,,,,,,,"Oregon allows schools to count computer science for a core graduation requirement. The policy is not written down and publicly accessible, but we are working with the state to release public documentation.",,,, +PA,Pennsylvania,19752,3.7,2969,191,-16783,No,Yes,No,Yes,Yes,No,No,No,No,No,,,,,85654,1691837808,47540,0,20%,1.48%,3058,22%,146,84,2,0,232,206,26%,37,1952,18%,91,48,1,0,23%,1106,28%,55,36,1,0,11%,71%,Other,www.code.org/promote/PA,no school districts in the state,Delaware County Intermediate Unit and Allegheny Intermediate Unit 3,none,4,2687,14,26,0,5,,,,,,,,2512000,14524,7550,8611,7187,6102,3048,1891,733178,13335,,,,,,,,"Pennsylvania has passed policy that is permissive and encouraging for schools to allow computer science to count for a core graduation requirement, but it is not a requirement for schools.",,,, +RI,Rhode Island,1690,3.8,348,13,-1342,Yes,Other,No,Yes,Yes,No,No,Other,No,No,,,,,90037,152162530,51920,0,17%,0.79%,337,23%,26,5,0,1,32,29,41%,15,146,21%,14,2,0,0,17%,191,24%,12,3,0,1,29%,0,No,www.code.org/promote/RI,no school districts in the state,University of Rhode Island,the State of Rhode Island,4,1062,0,2,0,0,,,,,,,,366000,1265,877,884,569,485,438,94,94443,2669,,,,,,,Rhode Island is working towards bringing computer science to all secondary schools.,"Rhode Island allows computer science to count for a core graduation requirement. This policy is not written down and publicly accessible, but we are working with the state to release public documentation. ",,,Working towards all high schools to offer CS, +SC,South Carolina,4342,3.9,529,51,-3813,No,No,Yes,Yes,No,No,No,No,No,No,,,,,75259,326774578,41530,0,25%,0.76%,770,28%,58,69,3,0,130,48,16%,16,437,27%,37,46,1,0,12%,333,28%,21,23,2,0,8%,73%,Yes,www.code.org/promote/SC,no school districts in the state,the STEM Center of Excellence at the Citadel,none,4,381,10,16,0,0,,,,,,,,1690000,4311,2940,1987,2425,1435,1119,374,217918,5869,,,,,,,,,,,, +SD,South Dakota,678,2.7,145,19,-533,No,No,No,No,No,No,No,No,No,No,,,,,65516,44419848,40070,0,18%,0.62%,35,9%,0,1,0,0,1,4,5%,0,16,19%,0,1,0,0,5%,19,0%,0,0,0,0,1%,52%,Other,www.code.org/promote/SD,no school districts in the state,Teachers Teaching Tech,none,4,1090,1,3,0,2,,,,,,,,192000,515,300,231,177,276,118,26,76799,2273,,,,,,,,,,,, +TN,Tennessee,6444,4.6,625,30,-5819,No,Yes,Other,No,No,No,No,No,No,No,,,,,75784,488352096,42350,0,18%,0.71%,934,29%,54,133,1,0,188,50,14%,18,356,28%,13,17,1,0,8%,578,30%,41,116,0,0,9%,63%,Other,www.code.org/promote/TN,no school districts in the state,Tennessee Department of Education,none,5,1303,11,20,0,3,,,,,,,,864000,4185,2754,2683,2285,2128,1431,395,291524,6434,,,,Tennessee is in the process of developing clear certification pathways for computer science teachers.,,,,,,,, +TX,Texas,42725,4.4,2714,376,-40011,No,Yes,Yes,No,No,Yes,No,Yes,No,Yes,,,,,91000,3887975000,47770,15,18%,1.12%,8925,27%,2362,327,23,10,2722,399,22%,63,6626,25%,1443,202,19,8,22%,2299,33%,919,125,4,2,9%,70%,No,www.code.org/promote/TX,"Aldine Independent School District, Dallas Independent School District, Grapevine-Colleyville ISD, and Houston Independent School District","Rice University, Center for STEM Education at the University of Texas at Austin, and the University of Texas at Dallas",none,21,7785,89,75,69,57,,,,,,,,4361000,33394,19894,44795,16459,12610,14059,6060,1232189,34912,,,,,,,,,,,, +UT,Utah,5371,3.3,366,18,-5005,Other,Yes,Yes,No,Yes,Yes,No,No,No,No,,,,,81018,435147678,45490,1,10%,0.31%,405,17%,30,4,1,1,36,33,17%,19,233,17%,20,4,0,0,8%,172,17%,10,0,1,1,10%,65%,No,www.code.org/promote/UT,Canyons School District and Provo Public Schools,Utah STEM Action Center and Utah Board of Education,none,17,743,55,41,29,53,,,,,,,,1142000,4441,1676,1923,2358,972,510,129,375203,6629,Utah is in the process of developing a state plan for K-12 computer science. ,,,,,,,,,,, +VA,Virginia,37525,4.9,1570,102,-35955,No,Yes,Yes,Yes,Yes,Yes,No,Yes,Yes,No,,,,,102773,3856556825,53090,0,18%,1.85%,4251,26%,314,277,4,5,600,134,29%,3,3117,25%,216,170,2,4,26%,1134,31%,98,107,2,1,12%,64%,No,www.code.org/promote/VA,no school districts in the state,CodeVA,none,13,1220,141,65,104,111,,,,,,,,1747000,14172,6798,8143,6752,4142,6306,2856,442283,12721,,,,,,,,,,,, +VT,Vermont,660,2.6,163,10,-497,No,No,Yes,No,No,Yes,No,No,No,No,,,,,78681,51929460,47620,0,18%,1.09%,128,20%,4,0,0,0,4,12,16%,3,66,9%,1,0,0,0,15%,62,31%,3,0,0,0,10%,62%,Other,www.code.org/promote/VT,no school districts in the state,none,none,1,110,0,0,0,0,,,,,,,,179000,825,591,320,395,308,134,70,23934,844,,,,,,,,,,,, +WA,Washington ,16258,2.5,1212,62,-15046,No,Yes,Yes,Yes,Yes,Yes,Yes,No,No,Yes,,,,,107853,1753474074,55810,0,21%,2.23%,2637,28%,199,43,8,9,259,135,31%,37,1900,29%,119,21,6,4,23%,737,26%,80,22,2,5,14%,65%,No,www.code.org/promote/WA,"Bainbridge Island School District, Bellevue School District, Bremerton School District, Central Valley School District, Cheney School District, Clover Park School District, East Valley School District, Eatonville School District, Enumclaw School District, Everett Public Schools, Franklin Pierce School District, Highline School District, Marysville School District, Shoreline School District, Spokane Public Schools, Tacoma Public Schools, Tukwila School District, and West Valley School District",NorthEast Washington Educational Service District 101 and Puget Sound Educational Service District,none,34,1782,137,78,117,129,,,,,,,,5022000,9383,4384,4607,3543,3247,2946,1945,814429,27479,,,,,,,,,,,, +WI,Wisconsin,7673,2.9,918,67,-6755,No,Yes,Yes,Yes,No,Yes,No,No,No,No,,,,,75912,582472776,45240,2,15%,0.79%,1036,17%,47,7,1,0,55,68,13%,8,572,14%,26,5,0,0,11%,464,20%,21,2,1,0,8%,61%,Other,www.code.org/promote/WI,Janesville School District,Marquette University,none,4,1283,22,24,4,0,,,,,,,,1402000,8246,4106,4116,3919,2755,1560,591,291450,7143,,,,,,,,,,,, +WV,West Virginia,1329,4.6,158,10,-1171,No,Yes,Yes,Yes,No,No,No,Yes,No,No,,,,,71150,94558350,40250,0,11%,0.73%,246,36%,7,2,1,0,10,15,12%,0,128,34%,2,0,1,0,7%,118,38%,5,2,0,0,7%,64%,Other,www.code.org/promote/WV,no school districts in the state,West Virginia University Center for Excellence in STEM Education,none,0,0,0,1,0,0,,,,,,,,212000,1075,834,303,455,446,371,97,63731,1447,,,,,,,,,,,, +WY,Wyoming,360,4.6,25,3,-335,Yes,Yes,Yes,Other,Other,No,No,Yes,Yes,Yes,,,,,63223,22760280,46840,0,8%,0.21%,21,24%,0,0,0,0,0,5,13%,1,8,13%,0,0,0,0,10%,13,31%,0,0,0,0,5%,0,No,www.code.org/promote/WY,no school districts in the state,Teachers Teaching Tech,none,1,549,0,0,0,0,,,,,,,,109000,376,177,186,130,85,80,6,48346,1536,,Wyoming is in the process of developing K-12 computer science standards.,Wyoming encourages the use of state funds for computer science or computer science professional development. Wyoming has an opportunity to expand computer science by designating state funds for computer science. ,,,,,,,No dedicated state funding for CS PD,,K-12 CS standards in progress +Sum_states,,557903,,49291,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/pegasus/helpers/section_api_helpers.rb b/pegasus/helpers/section_api_helpers.rb index 7191d6042e57e..86161d91ebc44 100644 --- a/pegasus/helpers/section_api_helpers.rb +++ b/pegasus/helpers/section_api_helpers.rb @@ -487,49 +487,6 @@ def self.fetch_if_allowed(id, user_id) nil end - def self.fetch_if_teacher(id, user_id) - return nil unless row = Dashboard.db[:sections]. - select(*fields). - where(sections__id: id, sections__user_id: user_id, sections__deleted_at: nil). - first - section = new(row) - return section - end - - def self.fetch_user_sections(user_id) - return if user_id.nil? - - Dashboard.db[:sections]. - join(:users, id: :user_id). - select(*fields). - where(sections__user_id: user_id, sections__deleted_at: nil). - map {|row| new(row).to_owner_hash} - end - - def add_student(student) - student_id = student[:id] || DashboardStudent.create(student) - return nil unless student_id - return nil if student[:admin] - - time_now = DateTime.now - - existing_follower = Dashboard.db[:followers].where(section_id: @row[:id], student_user_id: student_id).first - if existing_follower - Dashboard.db[:followers].where(id: existing_follower[:id]).update(deleted_at: nil, updated_at: time_now) - return student_id - end - - Dashboard.db[:followers].insert( - { - section_id: @row[:id], - student_user_id: student_id, - created_at: time_now, - updated_at: time_now - } - ) - student_id - end - def member?(user_id) return teacher?(user_id) || student?(user_id) end diff --git a/pegasus/router.rb b/pegasus/router.rb index 58948991f014d..77456ded74708 100644 --- a/pegasus/router.rb +++ b/pegasus/router.rb @@ -342,24 +342,12 @@ def preprocess_markdown(markdown_content) markdown_content.gsub(/```/, "```\n") end - def log_drupal_link(dir, uri, path) - if dir == 'drupal.code.org' - Honeybadger.notify( - error_class: "Link to v3.sites/drupal.code.org", - error_message: "#{uri} fell through to the base config directory", - environment_name: "drupal_#{rack_env}", - context: {path: path} - ) - end - end - def resolve_static(subdir, uri) return nil if settings.non_static_extnames.include?(File.extname(uri)) @dirs.each do |dir| path = content_dir(dir, subdir, uri) if File.file?(path) - log_drupal_link(dir, uri, path) return path end end @@ -372,7 +360,6 @@ def resolve_template(subdir, extnames, uri, is_document = false) extnames.each do |extname| path = content_dir(dir, subdir, "#{uri}#{extname}") if File.file?(path) - log_drupal_link(dir, "#{uri}#{extname}", path) return path end end @@ -396,6 +383,7 @@ def all_documents dirs.map do |site| site_glob = site_sub = content_dir(site, 'public') + next if site == 'drupal.code.org' if site == 'hourofcode.com' # hourofcode.com has custom logic to include # optional `/i18n` folder in its file-search path. diff --git a/pegasus/routes/v2_section_routes.rb b/pegasus/routes/v2_section_routes.rb deleted file mode 100644 index 98aef71bc5ef8..0000000000000 --- a/pegasus/routes/v2_section_routes.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'honeybadger' -# -# DEPRECATED: Every route implemented in this file is deprecated. -# Please do not add to this file. -# See /dashboardapi/sections* routes instead. -# - -# Get the set of sections owned by the current user -# DEPRECATED: Use GET /dashboardapi/sections instead -get '/v2/sections' do - Honeybadger.notify( - error_class: "DeprecatedEndpointWarning", - error_message: 'Deprecated endpoint GET /v2/sections called unexpectedly', - ) - - only_for 'code.org' - dont_cache - content_type :json - sections = DashboardSection.fetch_user_sections(dashboard_user_id) - forbidden! unless sections - JSON.pretty_generate(sections) -end - -# DEPRECATED: Use GET /dashboardapi/sections/ instead -get '/v2/sections/:id' do |id| - Honeybadger.notify( - error_class: "DeprecatedEndpointWarning", - error_message: 'Deprecated endpoint GET /v2/sections/:id called unexpectedly', - ) - - only_for 'code.org' - dont_cache - forbidden! unless section = DashboardSection.fetch_if_teacher(id, dashboard_user_id) - content_type :json - JSON.pretty_generate(section.to_owner_hash) -end diff --git a/pegasus/sites.v3/code.org/config.json b/pegasus/sites.v3/code.org/config.json index 5bd694c992be7..73781efbc30f1 100644 --- a/pegasus/sites.v3/code.org/config.json +++ b/pegasus/sites.v3/code.org/config.json @@ -1,5 +1,4 @@ { - "base": "drupal.code.org", "page_default_title": "Anybody can learn", "page_default_tagline": "Code.org" } diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AK.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AK.pdf.fetch index a8a7caac0be2e..9e9de728cc7ef 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AK.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AK.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/0f6aa3d9e1f8e1c984ee5288bfad4a20-AK.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/fb9977046e6a742bb09fc1134f8f47da-AK.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AL.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AL.pdf.fetch index b616f43210c27..af9d85c2bc1d7 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AL.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AL.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/daaf11a8418c5b2ec823f24db1b92951-AL.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/79cf2c5732413c01f8a226a6a10148ff-AL.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AR.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AR.pdf.fetch index d51e640376ef1..191dd357706d3 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AR.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AR.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/acdee820ae4f80f99649daed4bb79130-AR.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/5d87001e5f4fde10c88ba3f3bab579ca-AR.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AZ.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AZ.pdf.fetch index bf400b585b546..19cfc5eef172c 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/AZ.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/AZ.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/10b23d475edfe8122a93b989c86eb3f2-AZ.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/3a564938e7ec25e9835d3b58d02b0059-AZ.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/CA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/CA.pdf.fetch index cea5d1ae44273..83d58cea1c061 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/CA.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/CA.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/8b3b8983762efb4d11ff1512b7e280c3-CA.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/9f916b45f29fe989a70a9f3341c7f8a8-CA.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/CO.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/CO.pdf.fetch index 897566aa52943..5fe8f724f81ac 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/CO.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/CO.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/06eed930dcd7170b1779aff21b36c8e7-CO.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/f7fda7413a06359969c0ebdd0f83ec5a-CO.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/CT.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/CT.pdf.fetch index fea99bf798f05..c15543db969f2 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/CT.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/CT.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/3041498fc109ab77212ff960c2d54c60-CT.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/47556bdc0ced144756590e1aa5a75952-CT.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/DC.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/DC.pdf.fetch index f649e7a195dcb..6d979046a2f88 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/DC.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/DC.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/ec58992ff72f6b6d9ef0ca3ea35c0378-DC.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/b6a51f3428eb378df9fb418da948967d-DC.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/DE.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/DE.pdf.fetch index 3422837e7ffb8..8c79bb89d1aa6 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/DE.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/DE.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/2d1c931aff74a9f8d75a83fad3695661-DE.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/7c8c4c60f7af45416a4a9655203d8b4c-DE.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/FL.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/FL.pdf.fetch index 27a57d0aeb30e..a7154f9811acc 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/FL.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/FL.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/66ee6177734b6e7e5f7e1f8c349d026c-FL.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/2c9f6c080d07a74c770f09a82ab0d138-FL.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/GA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/GA.pdf.fetch index decf6e5737c3d..a0dd128240f56 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/GA.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/GA.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/3aa3771ae03a3adc264659109e722801-GA.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/e7cbf87c8dfa859d4d10f80ceecec99f-GA.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/HI.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/HI.pdf.fetch index 8ca158e527fa4..7d3fac9afd680 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/HI.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/HI.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/9535b7f1e777a0e491ce80d6b0c023b2-HI.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/53315a29c8185c867c74652e4ffd73be-HI.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/IA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/IA.pdf.fetch index 559b14e3c1452..bebacb72420d7 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/IA.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/IA.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/421a2e8cef87de5ccf2d72839e5b3042-IA.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/4c80a7575d8f75f57e37eb03ef70419e-IA.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/ID.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/ID.pdf.fetch index 457f5a8ee9a2c..6353543eef40a 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/ID.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/ID.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/cd091b8446add508b16a3f6351c319ee-ID.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/914a5100ec9541b4008a0266c54fca3c-ID.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/IL.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/IL.pdf.fetch index 4128d12fc0dc7..9f0c6efe057ce 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/IL.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/IL.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/82fd6a8c85514a756f4afa3bfeaea23a-IL.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/ab6b979b64c467b618fa2a73d00b6808-IL.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/IN.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/IN.pdf.fetch index 8da0cf3f031dc..41e4a471e5a3e 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/IN.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/IN.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/40fef5703727732de4cc3f099563eb48-IN.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/e98523a7d84dbcc4042cec5cbb73a5b4-IN.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/KS.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/KS.pdf.fetch index 19f42fc6e42a1..a5cd82a7308a7 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/KS.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/KS.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/2e5ff973cc71990465c8dff6d303adf5-KS.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/97621b054479fd2f7553a53ad944dc76-KS.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/KY.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/KY.pdf.fetch index 62e88fefb8f67..e253dbcfba24b 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/KY.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/KY.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/f97407279541d4e56e1797666186c793-KY.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/750ed6854b29f390697e1071fa7870b8-KY.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/LA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/LA.pdf.fetch index 7599d8151f58b..d12a7b44f37f5 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/LA.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/LA.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/073d45e9e93b57e07dda044cff6bce94-LA.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/620ad920dfdee3922ccae95bb9dfa534-LA.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MA.pdf.fetch index 3a40fe28fa3f0..3961b07b73f1b 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MA.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MA.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/7d1ed1976f10effd35e67f97a6c12527-MA.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/25675627df50ab1244978c82edda8009-MA.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MD.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MD.pdf.fetch index 9e3c670257d05..1d52df24f28e8 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MD.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MD.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/177d5de67a4fe9a0d14bd5cd42fd7340-MD.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/688b5c5629b6f44b714d5e9908b74a4f-MD.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/ME.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/ME.pdf.fetch index fb55c1bd882e4..21f0f9214eb71 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/ME.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/ME.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/c1bcbfdea08b8b62ee4015e124c1563d-ME.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/2fdb69d6ecb147c29ab8928f5cb0f7eb-ME.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MI.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MI.pdf.fetch index 5a8a93ef9ff0e..b9a2d23ff8a4f 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MI.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MI.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/764e680d9870684049c4d1cf4f3b3696-MI.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/38128166e2a8de8a4828e6059f3197b1-MI.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MN.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MN.pdf.fetch index d8805de56dab6..418a5c2369332 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MN.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MN.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/f52e38876a1ba05c8de94930949af726-MN.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/ba871287b70fa525ea21cec4512c26a8-MN.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MO.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MO.pdf.fetch index e07cad578a598..c9e43279c876c 100644 --- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MO.pdf.fetch +++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MO.pdf.fetch @@ -1 +1 @@ -https://cdo-fetch.s3.amazonaws.com/4f21de884df58ebdda96e975c7c15302-MO.pdf \ No newline at end of file +https://cdo-fetch.s3.amazonaws.com/6ea81ef7767cfd882d83aa5664c0d0fc-MO.pdf \ No newline at end of file diff --git a/pegasus/sites.v3/code.org/public/educate/applab.haml b/pegasus/sites.v3/code.org/public/educate/applab.haml index 1bddd17fda954..9ac233cf21c2a 100644 --- a/pegasus/sites.v3/code.org/public/educate/applab.haml +++ b/pegasus/sites.v3/code.org/public/educate/applab.haml @@ -28,7 +28,7 @@ video_player: true .tutorial-tile = view :display_video_thumbnail, id: "app_lab_in_classroom", video_code: "e1St8LB4VJA", play_button: 'center', download_path: "//videos.code.org/applab/in-the-classroom.mp4", letterbox: 'false' .tutorial-info - %h3{style: "margin-top: 0px;"} App Lab in the classrom + %h3{style: "margin-top: 0px;"} App Lab in the classroom .smalltext This launch video introduces five reasons App Lab could be a great tool for students learning programming. .clear diff --git a/pegasus/sites.v3/code.org/public/international/2018summit.md b/pegasus/sites.v3/code.org/public/international/2018summit.md index fc9217b7e41a2..9cc64478b3c33 100644 --- a/pegasus/sites.v3/code.org/public/international/2018summit.md +++ b/pegasus/sites.v3/code.org/public/international/2018summit.md @@ -38,7 +38,7 @@ The International Summit will be most useful to organizations based outside of t ## **Registration Details** -* The registration deadline is **13 July 2018**. +* The registration deadline is **31 July 2018**. * Code.org will cover the cost of your registration fee when you register prior to 13 July 2018. Late registrations will be considered on a case-by-case basis. * Please note that we will not be able to accommodate you at the summit if you do not fill out the registration form. diff --git a/pegasus/sites.v3/code.org/public/learn/hoc-mud.moved b/pegasus/sites.v3/code.org/public/learn/hoc-mud.moved new file mode 100644 index 0000000000000..165d5a49aad9a --- /dev/null +++ b/pegasus/sites.v3/code.org/public/learn/hoc-mud.moved @@ -0,0 +1 @@ +/learn \ No newline at end of file diff --git a/pegasus/sites.v3/drupal.code.org/public/mobile/thanks.moved b/pegasus/sites.v3/code.org/public/mobile/thanks.moved similarity index 100% rename from pegasus/sites.v3/drupal.code.org/public/mobile/thanks.moved rename to pegasus/sites.v3/code.org/public/mobile/thanks.moved diff --git a/pegasus/sites.v3/code.org/public/teacher-dashboard/section_assessments.haml b/pegasus/sites.v3/code.org/public/teacher-dashboard/section_assessments.haml index 1cf3646abc532..1e76cafb3b8f6 100644 --- a/pegasus/sites.v3/code.org/public/teacher-dashboard/section_assessments.haml +++ b/pegasus/sites.v3/code.org/public/teacher-dashboard/section_assessments.haml @@ -5,189 +5,3 @@ content-type: text/ng-template --- #section-assessments-react{'ng-init' => '$emit("section-assessments-rendered");', 'ng-show' => 'react_assessments'} -#section-assessments-angular{'ng-hide' => 'react_assessments'} - %br/ - - .loading{'ng-hide' => 'assessmentsLoaded'} - = I18n.t('dashboard_landing_loading') - - %div{'ng-show' => 'assessmentsLoaded'} - = I18n.t('dashboard_assessments_view') - %select#uitest-course-dropdown{"ng-model" => "script_id", "ng-options"=>"script.id as script.name group by script.category for script in script_list | orderBy:['category_priority', 'category', 'position', 'name']", 'ng-change' => 'changeScript(script_id)'} - - :ruby - surveys_filtered = "surveyLevels | orderBy:orderSurveyAnswers | filter:(stageFilterSurveyAnswers && {stage: stageFilterSurveyAnswers}):true" - - %h1{'ng-show' => 'surveys.length'}= I18n.t('dashboard_surveys_answers') - - %div{style: "padding-left:20px", 'ng-show' => 'surveys.length'} - %table{style: "width:950px; table-layout:fixed;", 'ng-show' => 'surveys.length', "ng-form" => "allForm"} - %colgroup - %col{width: "250"}/ - %col{width: "300"}/ - %col{width: "225"}/ - %col{width: "100"}/ - - %tr - %th.manage-th{colspan: 4} - %div{'ng-show' => 'surveyStages && surveyStages.length > 1', style: 'float: left; line-height: 35px'} - = I18n.t('dashboard_filter_by_stage') - %select{'ng-model' => 'stageFilterSurveyAnswers', "ng-options" => "stage for stage in surveyStages", "ng-show" => 'surveyStages'} - %option{value: ""}= I18n.t('dashboard_filter_all') - %button.btn.btn-white{'ng-csv' => surveys_filtered, - filename: "survey_levels.csv", - 'csv-header' => "['Stage', 'Question', 'Response', 'Percent']", - 'csv-column-order' => "['stage', 'questionText', 'resultText', 'percent']", - style: 'float: right'} - %i.fa.fa-download - = I18n.t('dashboard_download_csv') - - %tr - %th.manage-th - %a{href: "", "ng-click" => "orderSurveyAnswers = 'stage'"}= I18n.t('dashboard_stage') - %th.manage-th - %a{href: "", "ng-click" => "orderSurveyAnswers = 'question'"}= I18n.t('dashboard_question') - %th.manage-th - %a{href: "", "ng-click" => "orderSurveyAnswers = ['!studentResult', 'studentResult']"}= I18n.t('dashboard_response') - %th.manage-th - %a{href: "", "ng-click" => "orderSurveyAnswers = 'count'"}= I18n.t('dashboard_percent') - - %tr{"ng-repeat" => "level in #{surveys_filtered}", "ng-form" => "form"} - %td - {{level.stage}} - %td - {{level.questionText}} - %td - {{level.resultText}} - %td - {{level.percent}} - - :ruby - assessments_filtered = "assessments | orderBy:orderSummaries | filter:(stageFilterSummaries && {stage: stageFilterSummaries}):true" - - %h1{'ng-show' => 'assessments.length'}= I18n.t('dashboard_assessments_summaries') - - %div{style: "padding-left:20px", 'ng-show' => '!assessments.length'} - %br - %br - = I18n.t('dashboard_assessments_none') - %br - %br - = I18n.t('dashboard_assessments_none_part2') - #uitest-assessments-tab{style: "padding-left:20px", 'ng-show' => 'assessments.length'} - %table{style: "width:950px; table-layout:fixed;", 'ng-show' => 'assessments.length', "ng-form" => "allForm"} - %colgroup - %col{width: "100"}/ - %col{width: "175"}/ - %col{width: "75"}/ - %col{width: "125"}/ - %col{width: "75"}/ - %col{width: "75"}/ - %col{width: "75"}/ - %col{width: "125"}/ - %tr - %th.manage-th{colspan: 8} - %div{'ng-show' => 'assessmentStages && assessmentStages.length > 1', style: 'float: left; line-height: 35px'} - = I18n.t('dashboard_filter_by_stage') - %select{'ng-model' => 'stageFilterSummaries', "ng-options" => "stage for stage in assessmentStages", "ng-show" => 'assessmentStages'} - %option{value: ""}= I18n.t('dashboard_filter_all') - %button.btn.btn-white{'ng-csv' => assessments_filtered, - filename: "assessments.csv", - 'csv-header' => "['Name', 'Stage', 'Puzzle', 'Status', 'Multi correct', 'Multi count', 'Multi correct percent', 'Submission timestamp']", - 'csv-column-order' => "['student.name', 'stage', 'puzzle', 'status' , 'multi_correct', 'multi_count', 'multi_correct_percent', 'timestamp']", - style: 'float: right'} - %i.fa.fa-download - = I18n.t('dashboard_download_csv') - - %tr - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'student.name'"}= I18n.t('dashboard_students_name') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'stage'"}= I18n.t('dashboard_stage') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'puzzle'"}= I18n.t('dashboard_puzzle') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'status'"}= I18n.t('dashboard_status') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'multi_correct'"}= I18n.t('dashboard_multi_correct') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'multi_count'"}= I18n.t('dashboard_multi_count') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'multi_correct_percent'"}= I18n.t('dashboard_multi_correct_percent') - %th.manage-th - %a{href: "", "ng-click" => "orderSummaries = 'submission_timestamp'"}= I18n.t('dashboard_submission_timestamp') - - %tr{"ng-repeat" => "assessment in #{assessments_filtered}", "ng-form" => "form"} - %td - %a{"ng-href" => "#/sections/{{section.id}}/student/{{assessment.student.id}}"} {{assessment.student.name}} - %td - {{assessment.stage}} - %td - {{assessment.puzzle}} - %td - {{assessment.status}} - %td - {{assessment.multi_correct}} - %td - {{assessment.multi_count}} - %td - {{assessment.multi_correct_percent}} - %td - {{assessment.timestamp}} - - :ruby - levels_filtered = "assessmentLevels | orderBy:orderAnswers | filter:(stageFilterAnswers && {stage: stageFilterAnswers}):true" - - %h1{'ng-show' => 'assessments.length'}= I18n.t('dashboard_assessments_answers') - - %div{style: "padding-left:20px", 'ng-show' => 'assessments.length'} - %table{style: "width:950px; table-layout:fixed;", 'ng-show' => 'assessments.length', "ng-form" => "allForm"} - %colgroup - %col{width: "100"}/ - %col{width: "175"}/ - %col{width: "75"}/ - %col{width: "75"}/ - %col{width: "275"}/ - %col{width: "125"}/ - - %tr - %th.manage-th{colspan: 6} - %div{'ng-show' => 'assessmentStages && assessmentStages.length > 1', style: 'float: left; line-height: 35px'} - = I18n.t('dashboard_filter_by_stage') - %select{'ng-model' => 'stageFilterAnswers', "ng-options" => "stage for stage in assessmentStages", "ng-show" => 'assessmentStages'} - %option{value: ""}= I18n.t('dashboard_filter_all') - %button.btn.btn-white{'ng-csv' => levels_filtered, - filename: "assessment_levels.csv", - 'csv-header' => "['Name', 'Stage', 'Puzzle', 'Question', 'Response', 'Correctness']", - 'csv-column-order' => "['student.name', 'stage', 'puzzle', 'question', 'studentResult', 'correct']", - style: 'float: right'} - %i.fa.fa-download - = I18n.t('dashboard_download_csv') - - %tr - %th.manage-th - %a{href: "", "ng-click" => "orderAnswers = 'student.name'"}= I18n.t('dashboard_students_name') - %th.manage-th - %a{href: "", "ng-click" => "orderAnswers = 'stage'"}= I18n.t('dashboard_stage') - %th.manage-th - %a{href: "", "ng-click" => "orderAnswers = 'puzzle'"}= I18n.t('dashboard_puzzle') - %th.manage-th - %a{href: "", "ng-click" => "orderAnswers = 'question'"}= I18n.t('dashboard_question') - %th.manage-th - %a{href: "", "ng-click" => "orderAnswers = ['!studentResult', 'studentResult']"}= I18n.t('dashboard_response') - %th.manage-th - %a{href: "", "ng-click" => "orderAnswers = 'correct'"}= I18n.t('dashboard_correctness') - - %tr{"ng-repeat" => "level in #{levels_filtered}", "ng-form" => "form"} - %td - %a{"ng-href" => "#/sections/{{section.id}}/student/{{level.student.id}}"} {{level.student.name}} - %td - {{level.stage}} - %td - {{level.puzzle}} - %td - {{level.question}} - %td - {{level.studentResult}} - %td - {{level.correct}} diff --git a/pegasus/sites.v3/code.org/public/teacher-dashboard/section_progress.haml b/pegasus/sites.v3/code.org/public/teacher-dashboard/section_progress.haml index 27550faf06385..8e3cf32ba71f7 100644 --- a/pegasus/sites.v3/code.org/public/teacher-dashboard/section_progress.haml +++ b/pegasus/sites.v3/code.org/public/teacher-dashboard/section_progress.haml @@ -6,89 +6,3 @@ content-type: text/ng-template %link{:rel => 'stylesheet', :type => 'text/css', :href => '/shared/css/teacher-announcement.css'} #section-progress-react{'ng-init' => '$emit("section-progress-rendered");', 'ng-show' => 'react_progress'} -#section-progress-angular{'ng-hide' => 'react_progress'} - %br/ - - .loading{'ng-hide' => 'progressLoadedFirst'} - = I18n.t('dashboard_landing_loading') - - %div{'ng-show' => 'progressLoadedFirst'} - = I18n.t('dashboard_progress_view') - %select{"ng-model" => "script_id", "ng-options"=>"script.id as script.name group by script.category for script in script_list | orderBy:['category_priority', 'category', 'position', 'name']", 'ng-change' => 'changeProgress(script_id)'} - - -# This is meant to alert users to progress being disabled for this script - %div{'ng-show' => 'progress_disabled'} - .teacher-announce - .announce-content{style: "min-height: 0px"} - = I18n.t('dashboard_announce_hoc_scaling_progress') - .announce-learn-more{style: "margin-top: 10px"} - %a{"ng-href" => "https://support.code.org/hc/en-us/articles/115002660852", target: '_blank'} - %button.primary - = I18n.t('dashboard_announce_learn_more_button') - - %h3 {{progress.script.name}} - - %br - - .loading{'ng-show' => 'progressLoadedFirst && !progressLoaded'} - = I18n.t('dashboard_landing_loading') - - .table-wrapper{'ng-show' => 'progressLoadedFirst'} - %table#progress{'ng-class' => "page.zoom ? 'zoomed-in' : 'zoomed-out'"} - %colgroup - %col{width: '200'} - %col{width: '{{progressWidth()}}'} - %tr.progressheader - %th.studentname - %a{href: "", "ng-click" => "order = 'name'"}= I18n.t('dashboard_students_name') -   - %th.studentprogress - %div{style: 'position: absolute'} - %a{href: "", "ng-click" => "order = 'highest_level'"}= I18n.t('dashboard_students_progress') - %a.zoom-control{href: "", "ng-click" => "progressDetailRequest()", 'ng-hide' => 'page.zoom'} - %i.fa.fa-search-plus - %a.zoom-control{href: "", "ng-click" => "progressSummaryRequest()", 'ng-show' => 'page.zoom'} - %i.fa.fa-search-minus -   - %tr.progressheader - %td.studentname - %td - .stage{"ng-repeat" => "stage in progress.script.stages", 'ng-style' => "{width: (99.9 * stage.length / progress.script.levels_count) + '%'}", title: '{{stage.title}}', 'ng-click' => 'scrollToStage($event)'} - {{stage.title}} - %tr.studentrow{"ng-repeat" => "student in section.students | orderBy:order"} - %td.studentname - %a{"ng-href" => "#/sections/{{section.id}}/student/{{student.id}}/script/{{script_id}}", title: '{{student.name}}'} {{student.name}} - %td.studentprogress{'ng-hide' => 'progressLoaded'}   - %td.studentprogress{'ng-show' => 'progressLoaded'} - .stage{"ng-repeat" => "stage in progress.script.stages", 'ng-style' => "{width: (99.9 * stage.length / progress.script.levels_count) + '%'}"} -   - .studentbar - %a.level_link{'ng-repeat' => 'level in student.levels track by $index', title: '{{level.title}}', class: '{{level.class}}', 'ng-style' => "{width: page.zoom ? '34px' : (99.9 / progress.script.levels_count) + '%'}", 'ng-href' => "{{level.url}}"} - {{level.title}} - .studentdot{'ng-style' => "{left: (99.9 * (student.highest_level + 0.5) / progress.script.levels_count) + '%'}"} - .dot{class: '{{student.levels[student.highest_level].class}}'} - {{student.highest_level_in_stage}} - - .clear - - .key{'ng-class' => "page.zoom ? 'zoomed-in' : 'zoomed-out'"} - .studentbar - %dl - %dt - %span.level_link.not_tried   - %dd= I18n.t('dashboard_progress_not_started') - %dt - %span.level_link.attempted   - %dd= I18n.t('dashboard_progress_in_progress') - %dt - %span.level_link.passed   - %dd= I18n.t('dashboard_progress_completed_too_many_blocks') - %dt - %span.level_link.perfect   - %dd= I18n.t('dashboard_progress_completed_perfect') - %dt - %span.level_link.submitted   - %dd= I18n.t('dashboard_progress_submitted') - %dt.studentdot - .dot 10 - %dd.studentdot= I18n.t('dashboard_progress_furthest_level_attempted') diff --git a/pegasus/sites.v3/code.org/public/teacher-dashboard/section_responses.haml b/pegasus/sites.v3/code.org/public/teacher-dashboard/section_responses.haml index 6ca03e3a95b2c..3bd02ae5de736 100644 --- a/pegasus/sites.v3/code.org/public/teacher-dashboard/section_responses.haml +++ b/pegasus/sites.v3/code.org/public/teacher-dashboard/section_responses.haml @@ -6,65 +6,3 @@ content-type: text/ng-template #text-responses-table-react{'ng-init' => '$emit("text-responses-table-rendered");'} -#text-responses-table-angular{'ng-hide' => 'react_text_responses'} - %br/ - - .loading{'ng-hide' => 'responsesLoaded'} - = I18n.t('dashboard_landing_loading') - - %div{'ng-show' => 'responsesLoaded'} - = I18n.t('dashboard_responses_view') - %select#uitest-course-dropdown{"ng-model" => "script_id", "ng-options"=>"script.id as script.name group by script.category for script in script_list | orderBy:['category_priority', 'category', 'position', 'name']", 'ng-change' => 'changeScript(script_id)'} - - %br/ - - :ruby - responses_filtered = "responses | orderBy:order | filter:(stageFilter && {stage: stageFilter}):true" - - %div{style: "padding-left:20px", 'ng-show' => '!responses.length'} - = I18n.t('dashboard_responses_none') - #uitest-responses-tab{style: "padding-left:20px", 'ng-show' => 'responses.length'} - %table{style: "width:950px; table-layout:fixed;", 'ng-show' => 'responses.length', "ng-form" => "allForm"} - %colgroup - %col{width: "200"}/ - %col{width: "175"}/ - %col{width: "75"}/ - %col{width: "175"}/ - %col{width: "300"}/ - %tr - %th.manage-th{colspan: 5} - %div{'ng-show' => 'stages && stages.length > 1', style: 'float: left; line-height: 35px'} - = I18n.t('dashboard_filter_by_stage') - %select{'ng-model' => 'stageFilter', "ng-options" => "stage for stage in stages", "ng-show" => 'stages'} - %option{value: ""}= I18n.t('dashboard_filter_all') - %button.btn.btn-white{'ng-csv' => responses_filtered, - filename: "responses.csv", - 'csv-header' => "['Name', 'Stage', 'Puzzle', 'Question', 'Response']", - 'csv-column-order' => "['student.name', 'stage', 'puzzle', 'question', 'response']", - style: 'float: right'} - %i.fa.fa-download - = I18n.t('dashboard_download_csv') - - %tr - %th.manage-th - %a{href: "", "ng-click" => "order = 'name'"}= I18n.t('dashboard_students_name') - %th.manage-th - %a{href: "", "ng-click" => "order = 'stage'"}= I18n.t('dashboard_stage') - %th.manage-th - %a{href: "", "ng-click" => "order = 'puzzle'"}= I18n.t('dashboard_puzzle') - %th.manage-th - %a{href: "", "ng-click" => "order = 'question'"}= I18n.t('dashboard_question') - %th.manage-th - %a{href: "", "ng-click" => "order = 'response'"}= I18n.t('dashboard_response') - %tr{"ng-repeat" => "response in #{responses_filtered}", "ng-form" => "form"} - %td - %a{"ng-href" => "#/sections/{{section.id}}/student/{{response.student.id}}"} {{response.student.name}} - %td - {{response.stage}} - %td - {{response.puzzle}} - %td - {{response.question}} - %td - {{response.response | limitTo:100}} - %a{'ng-href' => '{{response.url}}', 'ng-show' => 'response.response.length > 100'} ... see full answer diff --git a/pegasus/sites.v3/code.org/public/teacher-dashboard/signin_cards.haml b/pegasus/sites.v3/code.org/public/teacher-dashboard/signin_cards.haml index 5a1c1a356cf06..a191ccfe2628e 100644 --- a/pegasus/sites.v3/code.org/public/teacher-dashboard/signin_cards.haml +++ b/pegasus/sites.v3/code.org/public/teacher-dashboard/signin_cards.haml @@ -88,5 +88,5 @@ content-type: text/ng-template %br %img{"ng-src" => "/images/teacher-dashboard/syncGoogleClassroom.png", alt: "Google Classroom Sync Button", - title: "Google Classrom Sync Button", + title: "Google Classroom Sync Button", :style => "border-color: #d8d8d8; border-width: 10px; border-style: solid; width: 300px; height:auto;"} diff --git a/pegasus/sites.v3/drupal.code.org/public/learn/hoc-mud.302 b/pegasus/sites.v3/drupal.code.org/public/learn/hoc-mud.302 deleted file mode 100644 index 358b8e28e36ca..0000000000000 --- a/pegasus/sites.v3/drupal.code.org/public/learn/hoc-mud.302 +++ /dev/null @@ -1 +0,0 @@ -/learn/codecademy \ No newline at end of file diff --git a/pegasus/test/test_section_api_helpers.rb b/pegasus/test/test_section_api_helpers.rb index 72326ea5703a8..8ed345de8f6cd 100644 --- a/pegasus/test/test_section_api_helpers.rb +++ b/pegasus/test/test_section_api_helpers.rb @@ -373,221 +373,6 @@ class SectionApiHelperTest < SequelTestCase assert_equal expected, csp_course end end - - describe "fetch_user_sections" do - before do - DashboardSection.clear_caches - FakeDashboard.use_fake_database - end - - it 'returns all sections belonging to teacher' do - sections = DashboardSection.fetch_user_sections(FakeDashboard::TEACHER[:id]) - assert_equal 3, sections.length - end - - it 'specifies course_id for sections that have one assigned' do - sections = DashboardSection.fetch_user_sections(FakeDashboard::TEACHER[:id]) - sections.each do |section| - if section[:id] == FakeDashboard::SECTION_COURSE[:id] - assert_equal FakeDashboard::SECTION_COURSE[:course_id], section[:course_id] - else - assert_nil section[:course_id] - end - end - end - end - end - - # A set of tests that use our fake database - describe 'DashboardSectionMore' do - before do - DashboardSection.clear_caches - FakeDashboard.use_fake_database - end - - describe 'teachers' do - it 'returns an array of hashes of information' do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - teachers = pegasus_section.teachers - assert_equal( - [{id: FakeDashboard::TEACHER[:id], location: "/v2/users/#{FakeDashboard::TEACHER[:id]}"}], - teachers - ) - end - end - - describe 'teacher?' do - it 'returns false for a teacher of a different section' do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - refute pegasus_section.teacher?(FakeDashboard::TEACHER_SELF[:id]) - end - - it 'returns true for a teacher of the section' do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - assert pegasus_section.teacher?(FakeDashboard::TEACHER[:id]) - end - - it 'returns false for soft-deleted enrollments' do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_DELETED_FOLLOWER[:id], - FakeDashboard::TEACHER_DELETED_FOLLOWER[:id] - ) - refute pegasus_section.student?(FakeDashboard::STUDENT_DELETED_FOLLOWER[:id]) - end - end - - describe 'students' do - it 'returns hash for section with student without progress' do - Dashboard.db.transaction(rollback: :always) do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - students = pegasus_section.students - assert_equal( - [ - { - id: FakeDashboard::STUDENT[:id], - name: FakeDashboard::STUDENT[:name], - username: nil, - email: '', - hashed_email: nil, - user_type: 'student', - gender: nil, - birthday: nil, - total_lines: 0, - secret_words: nil, - secret_picture_name: nil, - secret_picture_path: nil, - location: "/v2/users/#{FakeDashboard::STUDENT[:id]}", - age: nil, - # completed_levels_count is deprecated and will always be 0 - completed_levels_count: 0 - } - ], - students - ) - end - end - - it 'returns hash for section with student with progress' do - Dashboard.db.transaction(rollback: :always) do - Dashboard.db[:user_levels].insert( - user_id: FakeDashboard::STUDENT[:id], - level_id: 1, - best_result: 100 - ) - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - students = pegasus_section.students - assert_equal( - [ - { - id: FakeDashboard::STUDENT[:id], - name: FakeDashboard::STUDENT[:name], - username: nil, - email: '', - hashed_email: nil, - user_type: 'student', - gender: nil, - birthday: nil, - total_lines: 0, - secret_words: nil, - secret_picture_name: nil, - secret_picture_path: nil, - location: "/v2/users/#{FakeDashboard::STUDENT[:id]}", - age: nil, - # completed_levels_count is deprecated and will always be 0 - completed_levels_count: 0 - } - ], - students - ) - end - end - - it 'ignores deleted followers' do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_DELETED_FOLLOWER[:id], - FakeDashboard::TEACHER_DELETED_FOLLOWER[:id] - ) - assert_equal [], pegasus_section.students - end - - it 'returns empty array for empty section' do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_EMPTY[:id], - FakeDashboard::TEACHER[:id] - ) - assert_equal [], pegasus_section.students - end - end - - describe 'add_student' do - it 'creates a follower for new student' do - Dashboard.db.transaction(rollback: :always) do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - - pegasus_section.add_student(FakeDashboard::STUDENT_SELF) - - assert_equal( - 1, - Dashboard.db[:followers].where(student_user_id: FakeDashboard::STUDENT_SELF[:id]).count - ) - end - end - - it 'restores deleted follower' do - Dashboard.db.transaction(rollback: :always) do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_DELETED_FOLLOWER[:id], - FakeDashboard::TEACHER_DELETED_FOLLOWER[:id] - ) - - pegasus_section.add_student(FakeDashboard::STUDENT_DELETED_FOLLOWER) - - assert_equal( - 1, - Dashboard.db[:followers]. - where(student_user_id: FakeDashboard::STUDENT_DELETED_FOLLOWER[:id]). - count - ) - assert_nil Dashboard.db[:followers]. - where(student_user_id: FakeDashboard::STUDENT_DELETED_FOLLOWER[:id]). - first[:deleted_at] - end - end - - it 'does not create follower for admin student' do - Dashboard.db.transaction(rollback: :always) do - pegasus_section = DashboardSection.fetch_if_teacher( - FakeDashboard::SECTION_NORMAL[:id], - FakeDashboard::TEACHER[:id] - ) - - pegasus_section.add_student(FakeDashboard::ADMIN) - - assert_equal( - 0, - Dashboard.db[:followers].where(student_user_id: FakeDashboard::ADMIN[:id]).count - ) - end - end - end end describe DashboardUserScript do diff --git a/pegasus/test/test_v2_section_routes.rb b/pegasus/test/test_v2_section_routes.rb deleted file mode 100644 index ee3a5bd7554a1..0000000000000 --- a/pegasus/test/test_v2_section_routes.rb +++ /dev/null @@ -1,153 +0,0 @@ -# Tests for the routes in v2_section_routes.rb - -require 'minitest/autorun' -require 'rack/test' -require 'mocha/mini_test' -require_relative 'fixtures/fake_dashboard' -require_relative 'fixtures/mock_pegasus' -require_relative 'sequel_test_case' - -class V2SectionRoutesTest < SequelTestCase - describe 'Section Routes' do - before do - DashboardSection.clear_caches - FakeDashboard.use_fake_database - $log.level = Logger::ERROR # Pegasus spams debug logging otherwise - @pegasus = Rack::Test::Session.new(Rack::MockSession.new(MockPegasus.new, "studio.code.org")) - end - - describe 'GET /v2/sections' do - it 'returns 403 "Forbidden" when not signed in' do - with_role nil - @pegasus.get '/v2/sections' - assert_equal 403, @pegasus.last_response.status - end - - it 'returns empty array when student' do - with_role FakeDashboard::STUDENT - @pegasus.get '/v2/sections' - assert_equal 200, @pegasus.last_response.status - assert_equal [], JSON.parse(@pegasus.last_response.body) - end - - # NOTE: These tests currently fail as the result of sqlite not supporting - # the `.distinct(:student_user_id)` syntax used in the `students()` method - # within `DashboardSection`. - # TODO(asher): Fix and reenable these tests. - #it 'returns sections when teacher' do - # with_role FakeDashboard::TEACHER - # @pegasus.get '/v2/sections' - # assert_equal 200, @pegasus.last_response.status - # assert_equal [ - # { - # "id"=>150001, - # "location"=>"/v2/sections/150001", - # "name"=>"Fake Section A", - # "login_type"=>"email", - # "grade"=>nil, - # "code"=>nil, - # "course"=>nil, - # "teachers"=>[{"id"=>2, "location"=>"/v2/users/2"}], - # "students"=>[{"student_user_id"=>1, "location"=>"/v2/users/", "age"=>nil, "completed_levels_count"=>0}] - # }, - # { - # "id"=>150002, - # "location"=>"/v2/sections/150002", - # "name"=>"Fake Section B", - # "login_type"=>"email", - # "grade"=>nil, - # "code"=>nil, - # "course"=>nil, - # "teachers"=>[{"id"=>2, "location"=>"/v2/users/2"}], - # "students"=>[] - # }], - # JSON.parse(@pegasus.last_response.body) - #end - - #it 'ignores deleted sections' do - # with_role FakeDashboard::TEACHER_WITH_DELETED - # @pegasus.get '/v2/sections' - # assert_equal 200, @pegasus.last_response.status - # assert_equal [ - # { - # "id"=>150004, - # "location"=>"/v2/sections/150004", - # "name"=>"Fake Section D", - # "login_type"=>"email", - # "grade"=>nil, - # "code"=>nil, - # "course"=>nil, - # "teachers"=>[{"id"=>7, "location"=>"/v2/users/7"}], - # "students"=>[{"student_user_id"=>5, "location"=>"/v2/users/", "age"=>nil, "completed_levels_count"=>0}] - # }], - # JSON.parse(@pegasus.last_response.body) - #end - end - - describe 'GET /v2/sections/:id' do - # NOTE: These tests currently fail as the result of sqlite not supporting - # the `.distinct(:student_user_id)` syntax used in the `students()` method - # within `DashboardSection`. - # TODO(asher): Fix and reenable these tests. - #it 'returns section for teacher' do - # with_role FakeDashboard::TEACHER - # @pegasus.get "/v2/sections/#{FakeDashboard::SECTION_NORMAL[:id]}" - # assert_equal 200, @pegasus.last_response.status - # assert_equal ({ - # "id"=>150001, - # "location"=>"/v2/sections/150001", - # "name"=>"Fake Section A", - # "login_type"=>"email", - # "grade"=>nil, - # "code"=>nil, - # "course"=>nil, - # "teachers"=>[{"id"=>2, "location"=>"/v2/users/2"}], - # "students"=>[{"student_user_id"=>1, "location"=>"/v2/users/", "age"=>nil, "completed_levels_count"=>0}] - # }), - # JSON.parse(@pegasus.last_response.body) - #end - - #it 'returns section for admin' do - # with_role FakeDashboard::ADMIN - # @pegasus.get "/v2/sections/#{FakeDashboard::SECTION_NORMAL[:id]}" - # assert_equal 200, @pegasus.last_response.status - # assert_equal ({ - # "id"=>150001, - # "location"=>"/v2/sections/150001", - # "name"=>"Fake Section A", - # "login_type"=>"email", - # "grade"=>nil, - # "code"=>nil, - # "course"=>nil, - # "teachers"=>[{"id"=>2, "location"=>"/v2/users/2"}], - # "students"=>[{"student_user_id"=>1, "location"=>"/v2/users/", "age"=>nil, "completed_levels_count"=>0}] - # }), - # JSON.parse(@pegasus.last_response.body) - #end - - it 'returns 403 "Forbidden" when not signed in' do - with_role nil - @pegasus.get "/v2/sections/#{FakeDashboard::SECTION_NORMAL[:id]}" - assert_equal 403, @pegasus.last_response.status - end - - it 'returns 403 "Forbidden" for unconnected teacher' do - with_role FakeDashboard::TEACHER_SELF - @pegasus.get "/v2/sections/#{FakeDashboard::SECTION_NORMAL[:id]}" - assert_equal 403, @pegasus.last_response.status - end - - it 'ignores deleted sections' do - # TODO(asher). - end - end - - # Stubs the user ID for the duration of the test to match the ID of the - # user hash given. The result should be pulled in through the mock database. - # @param [Hash] role - def with_role(role) - Documents.any_instance.stubs(:dashboard_user_id). - returns(role.nil? ? nil : role[:id]) - end - end -end diff --git a/shared/middleware/helpers/profanity_privacy_helper.rb b/shared/middleware/helpers/profanity_privacy_helper.rb index fb9e24df70694..c6d7af3c494f4 100644 --- a/shared/middleware/helpers/profanity_privacy_helper.rb +++ b/shared/middleware/helpers/profanity_privacy_helper.rb @@ -8,7 +8,49 @@ def profanity_privacy_violation?(filename, body) return false unless filename == BLOCKLY_SOURCE_FILENAME + share_failure = share_failure_from_body body, request.locale + !!share_failure +end + +def channel_policy_violation?(channel_id) + body = channel_main_json_body channel_id + return false unless body + profanity_privacy_violation?(BLOCKLY_SOURCE_FILENAME, body) +end +# +# This method is designed to be an easy way for support staff or a dev to +# figure out why sharing was automatically blocked for a particular project. +# It's designed for use from dashboard-console, which is why it has no usages +# within our repo. +# +# @example +# explain_share_failure 'kkbjvA8CUoWEAJ0inKpzTQ' +# +# @param [String] channel_id - the encrypted channel ID, as found in the +# project's share URL. +# @param [String] locale - optionally specify a custom locale string +# (two-character code) to check profanity in a different language. +# @returns [ShareFailure|false] if the project is blocked, this method should +# return a ShareFailure struct that reveals exactly which content caused the +# block and why. If not, this method returns false. +# +def explain_share_failure(channel_id, locale = 'en') + body = channel_main_json_body channel_id + share_failure_from_body body, locale +end + +# Effectively private +def channel_main_json_body(channel_id) + bucket = SourceBucket.new + filename = BLOCKLY_SOURCE_FILENAME + result = bucket.get(channel_id, filename) + (result && result[:body]) || false +end + +# Effectively private +def share_failure_from_body(body, locale) + return false unless body body_string = body.string begin @@ -21,17 +63,9 @@ def profanity_privacy_violation?(filename, body) return false unless blockly_source begin - return !ShareFiltering.find_share_failure(blockly_source, request.locale).nil? + ShareFiltering.find_share_failure(blockly_source, locale) rescue OpenURI::HTTPError, IO::EAGAINWaitReadable # If WebPurify or Geocoder are unavailable, default to viewable return false end end - -def channel_policy_violation?(channel_id) - bucket = SourceBucket.new - filename = 'main.json' - result = bucket.get(channel_id, filename) - return false unless result && result[:body] - profanity_privacy_violation?(filename, result[:body]) -end