}
);
};
+// The "add row" should always be pinned to the top when sorting.
+// This function takes into account having multiple "add rows"
+const sortRows = (data, columnIndexList, orderList) => {
+ let addRows = [];
+ let studentRows = [];
+ for (let i = 0; i
);
};
@@ -279,7 +298,7 @@ class ManageStudentsTable extends Component {
const sortedRows = sort.sorter({
columns,
sortingColumns,
- sort: orderBy,
+ sort: sortRows,
})(this.props.studentData);
return (
diff --git a/apps/src/templates/manageStudents/manageStudentsRedux.js b/apps/src/templates/manageStudents/manageStudentsRedux.js
index 1f3480ba9ac8c..4c8ad998ef4cd 100644
--- a/apps/src/templates/manageStudents/manageStudentsRedux.js
+++ b/apps/src/templates/manageStudents/manageStudentsRedux.js
@@ -1,4 +1,5 @@
import _ from 'lodash';
+import {SectionLoginType} from '@cdo/apps/util/sharedConstants';
const SET_LOGIN_TYPE = 'manageStudents/SET_LOGIN_TYPE';
const SET_STUDENTS = 'manageStudents/SET_STUDENTS';
@@ -11,6 +12,7 @@ const SET_SECRET_WORDS = 'manageStudents/SET_SECRET_WORDS';
const EDIT_STUDENT = 'manageStudents/EDIT_STUDENT';
const START_SAVING_STUDENT = 'manageStudents/START_SAVING_STUDENT';
const SAVE_STUDENT_SUCCESS = 'manageStudents/SAVE_STUDENT_SUCCESS';
+const ADD_STUDENT_SUCCESS = 'manageStudents/ADD_STUDENT_SUCCESS';
export const setLoginType = loginType => ({ type: SET_LOGIN_TYPE, loginType });
export const setSectionId = sectionId => ({ type: SET_SECTION_ID, sectionId});
@@ -23,6 +25,7 @@ export const setSecretWords = (studentId, words) => ({ type: SET_SECRET_WORDS, s
export const editStudent = (studentId, studentData) => ({ type: EDIT_STUDENT, studentId, studentData });
export const startSavingStudent = (studentId) => ({ type: START_SAVING_STUDENT, studentId });
export const saveStudentSuccess = (studentId) => ({ type: SAVE_STUDENT_SUCCESS, studentId });
+export const addStudentSuccess = (studentData) => ({ type: ADD_STUDENT_SUCCESS, studentData });
export const saveStudent = (studentId) => {
return (dispatch, getState) => {
@@ -37,6 +40,34 @@ export const saveStudent = (studentId) => {
};
};
+export const addStudent = (studentId) => {
+ return (dispatch, getState) => {
+ const state = getState().manageStudents;
+ dispatch(startSavingStudent(studentId));
+ addStudentOnServer(state.editingData[studentId], state.sectionId, (error, data) => {
+ if (error) {
+ console.error(error);
+ }
+ dispatch(addStudentSuccess(convertAddedStudent(data)));
+ });
+ };
+};
+
+// This doesn't get used to make a server call, but does
+// need to be unique from the rest of the ids.
+const addRowId = 0;
+
+const blankAddRow = {
+ id: addRowId,
+ name: '',
+ age: '',
+ gender: '',
+ username: '',
+ loginType: '',
+ isEditing: true,
+ isAddRow: true,
+};
+
const initialState = {
loginType: '',
studentData: {},
@@ -46,9 +77,28 @@ const initialState = {
export default function manageStudents(state=initialState, action) {
if (action.type === SET_LOGIN_TYPE) {
+ let addRowInitialization = {};
+ if (action.loginType === SectionLoginType.word || action.loginType === SectionLoginType.picture) {
+ addRowInitialization = {
+ studentData: {
+ [addRowId]: {
+ ...blankAddRow,
+ loginType: action.loginType,
+ }
+ },
+ editingData: {
+ [addRowId]: {
+ ...blankAddRow,
+ loginType: action.loginType,
+
+ }
+ }
+ };
+ }
return {
...state,
loginType: action.loginType,
+ ...addRowInitialization,
};
}
if (action.type === SET_SECTION_ID) {
@@ -60,7 +110,10 @@ export default function manageStudents(state=initialState, action) {
if (action.type === SET_STUDENTS) {
return {
...state,
- studentData: action.studentData,
+ studentData: {
+ ...state.studentData,
+ ...action.studentData
+ },
};
}
if (action.type === START_EDITING_STUDENT) {
@@ -122,6 +175,29 @@ export default function manageStudents(state=initialState, action) {
editingData: _.omit(state.editingData, action.studentId),
};
}
+ if (action.type === ADD_STUDENT_SUCCESS) {
+ return {
+ ...state,
+ studentData: {
+ [action.studentData.id]: {
+ ...action.studentData,
+ loginType: state.loginType
+ },
+ ...state.studentData,
+ [addRowId]: {
+ ...blankAddRow,
+ loginType: state.loginType
+ },
+ },
+ editingData: {
+ ...state.editingData,
+ [addRowId]: {
+ ...blankAddRow,
+ loginType: state.loginType
+ }
+ }
+ };
+ }
if (action.type === EDIT_STUDENT) {
return {
...state,
@@ -196,6 +272,25 @@ export const convertStudentServerData = (studentData, loginType, sectionId) => {
return studentLookup;
};
+// Converts added student from /v2/sections/sectionid/students to a key/value
+// object for the redux store
+export const convertAddedStudent = (studentData, loginType, sectionId) => {
+ let student = studentData[0];
+ const studentObject = {
+ id: student.id,
+ name: student.name,
+ username: student.username,
+ age: student.age,
+ gender: student.gender,
+ secretWords: student.secret_words,
+ secretPicturePath: student.secret_picture_path,
+ loginType: loginType,
+ sectionId: sectionId,
+ isEditing: false,
+ };
+ return studentObject;
+};
+
// Converts key/value id/student pairs to an array of student objects for the
// component to display
// TODO(caleybrock): memoize this - sections could be a few thousand students
@@ -222,3 +317,23 @@ const updateStudentOnServer = (updatedStudentInfo, onComplete) => {
onComplete(status, null);
});
};
+
+// Make a post request to add a student.
+const addStudentOnServer = (updatedStudentInfo, sectionId, onComplete) => {
+ const studentToAdd = [{
+ editing: true,
+ name: updatedStudentInfo.name,
+ age: updatedStudentInfo.age,
+ gender: updatedStudentInfo.gender,
+ }];
+ $.ajax({
+ url: `/v2/sections/${sectionId}/students`,
+ method: 'POST',
+ contentType: 'application/json;charset=UTF-8',
+ data: JSON.stringify(studentToAdd),
+ }).done((data) => {
+ onComplete(null, data);
+ }).fail((jqXhr, status) => {
+ onComplete(status, null);
+ });
+};
diff --git a/apps/test/unit/templates/manageStudents/manageStudentsReduxTest.js b/apps/test/unit/templates/manageStudents/manageStudentsReduxTest.js
index 9972bf3a338ae..d774d9630902d 100644
--- a/apps/test/unit/templates/manageStudents/manageStudentsReduxTest.js
+++ b/apps/test/unit/templates/manageStudents/manageStudentsReduxTest.js
@@ -12,6 +12,7 @@ import manageStudents, {
editStudent,
startSavingStudent,
saveStudentSuccess,
+ addStudentSuccess,
} from '@cdo/apps/templates/manageStudents/manageStudentsRedux';
const studentEmailData = {
@@ -272,4 +273,78 @@ describe('manageStudentsRedux', () => {
assert.equal(afterSaveState.studentData[1].name, "New name");
});
});
+
+ describe('add student', () => {
+ const expectedBlankRow = {
+ id: 0,
+ name: '',
+ age: '',
+ gender: '',
+ username: '',
+ loginType: '',
+ isEditing: true,
+ isAddRow: true,
+ };
+ it('setLoginType creates an add row for word login types', () => {
+ const action = setLoginType('word');
+ const nextState = manageStudents(initialState, action);
+ assert.deepEqual(nextState.studentData[0], {...expectedBlankRow, loginType: 'word'});
+ assert.deepEqual(nextState.editingData[0], {...expectedBlankRow, loginType: 'word'});
+ });
+
+ it('setLoginType creates an add row for picture login types', () => {
+ const action = setLoginType('picture');
+ const nextState = manageStudents(initialState, action);
+ assert.deepEqual(nextState.studentData[0], {...expectedBlankRow, loginType: 'picture'});
+ assert.deepEqual(nextState.editingData[0], {...expectedBlankRow, loginType: 'picture'});
+ });
+
+ it('addStudentSuccess updates studentData,removes editingData, and adds new blank row', () => {
+ // Initial state with blank row
+ const initialState = {
+ loginType: 'picture',
+ studentData: {
+ 0: {
+ ...expectedBlankRow,
+ loginType: 'picture',
+ }
+ },
+ editingData: {
+ 0: {
+ ...expectedBlankRow,
+ loginType: 'picture',
+ }
+ },
+ sectionId: 10,
+ };
+
+ const studentDataToAdd = {
+ id: 10,
+ name: 'new student',
+ age: 17,
+ gender: 'f',
+ secretPicturePath: '/wizard.jpg',
+ loginType: 'picture',
+ sectionId: 10,
+ isEditing: false,
+ };
+
+ // Add student
+ const addStudentSuccessAction = addStudentSuccess(studentDataToAdd);
+ const addedStudentState = manageStudents(initialState, addStudentSuccessAction);
+
+ assert.deepEqual(addedStudentState.editingData[0], {
+ ...expectedBlankRow,
+ loginType: 'picture',
+ });
+ assert.deepEqual(addedStudentState.studentData[0], {
+ ...expectedBlankRow,
+ loginType: 'picture',
+ });
+ assert.deepEqual(addedStudentState.studentData[10], {
+ ...studentDataToAdd
+ });
+ });
+
+ });
});
diff --git a/bin/cron/send_workshop_reminder_emails b/bin/cron/send_workshop_reminder_emails
deleted file mode 100755
index aaf08f5127020..0000000000000
--- a/bin/cron/send_workshop_reminder_emails
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env ruby
-
-# This script sends reminder via poste for professional development workshop
-# signups.
-
-require File.expand_path('../../../pegasus/src/env', __FILE__)
-require 'active_support'
-require 'active_support/core_ext/object/blank'
-require src_dir 'database'
-require 'cdo/only_one'
-require 'cdo/poste'
-
-# @param date_as_string [String] a date string in the form MM/DD/YY or MM/DD/YYYY.
-# @returns [Date | nil] a Date for date_as_string or nil if it does not parse
-# to a date.
-def parse_workshop_date(date_as_string)
- return nil if date_as_string.blank?
- year_part = date_as_string.split('/')[2]
- format_string = year_part.length == 2 ? '%m/%d/%y' : '%m/%d/%Y'
- Date.strptime(date_as_string, format_string)
-rescue ArgumentError
- nil
-end
-
-# Sends a workshop reminder email to the recipient specified by form.
-# @param form_id [Integer] the ID for the ProfessionalDevelopmentWorkshopSignup
-# form
-# @param email [String] the email for the ProfessionalDevelopmentWorkshopSignup
-# form
-def send_reminder_email(form_id, email)
- recipient = Poste2.ensure_recipient(email, ip_address: '127.0.0.1')
- Poste2.send_message('workshop_signup_reminder', recipient, form_id: form_id)
-end
-
-def main
- DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshop').each do |workshop|
- # Parse the JSON blob in data to determine the workshop date.
- parsed_data = JSON.parse(workshop[:data])
- workshop_date = parse_workshop_date(parsed_data['dates'].first['date_s'])
- # Only send workshop reminders if twelve days away, so skip otherwise.
- next unless workshop_date == Date.today + 12
- # Determine all the signups for this workshop, sending an email unless the
- # signup status is cancelled.
- DB[:forms].
- where(kind: 'ProfessionalDevelopmentWorkshopSignup').
- where(parent_id: workshop[:id]).
- each do |signup|
- parsed_signup_data = JSON.parse(signup[:data])
- next if parsed_signup_data['status_s'] == 'cancelled'
- send_reminder_email(signup[:id], signup[:email])
- end
- end
-end
-
-main if only_one_running?(__FILE__)
diff --git a/bin/cron/with_pg/Gemfile b/bin/cron/with_pg/Gemfile
new file mode 100644
index 0000000000000..4e805c45b7430
--- /dev/null
+++ b/bin/cron/with_pg/Gemfile
@@ -0,0 +1,5 @@
+source 'https://rubygems.org'
+
+eval_gemfile File.join('../../../', 'Gemfile')
+
+gem 'pg'
diff --git a/bin/generate_professional_development_workshop_teachers_report_csv b/bin/generate_professional_development_workshop_teachers_report_csv
deleted file mode 100755
index b3b2f119d1db0..0000000000000
--- a/bin/generate_professional_development_workshop_teachers_report_csv
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env ruby
-require File.expand_path('../../pegasus/src/env', __FILE__)
-require src_dir 'database'
-require pegasus_dir 'helpers/professional_development_workshop_helpers'
-require 'cdo/csv'
-require 'cdo/activity_constants'
-
-puts CSV.generate_from_dataset(generate_professional_development_workshop_teachers_report)
diff --git a/cookbooks/Berksfile.lock b/cookbooks/Berksfile.lock
index cd17c5fb293e3..7418714641aeb 100644
--- a/cookbooks/Berksfile.lock
+++ b/cookbooks/Berksfile.lock
@@ -63,7 +63,7 @@ GRAPH
seven_zip (>= 0.0.0)
windows (>= 0.0.0)
build-essential (2.1.3)
- cdo-apps (0.2.280)
+ cdo-apps (0.2.281)
apt (>= 0.0.0)
build-essential (>= 0.0.0)
cdo-cloudwatch-extra-metrics (>= 0.0.0)
diff --git a/cookbooks/cdo-apps/metadata.rb b/cookbooks/cdo-apps/metadata.rb
index 9b6916ead1193..d412fe40d5540 100644
--- a/cookbooks/cdo-apps/metadata.rb
+++ b/cookbooks/cdo-apps/metadata.rb
@@ -4,7 +4,7 @@
license 'All rights reserved'
description 'Installs/Configures cdo-apps'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
-version '0.2.280'
+version '0.2.281'
depends 'apt'
depends 'build-essential'
diff --git a/cookbooks/cdo-apps/templates/default/crontab.erb b/cookbooks/cdo-apps/templates/default/crontab.erb
index 7fa6d91d0ffcf..eb9db2831bca0 100644
--- a/cookbooks/cdo-apps/templates/default/crontab.erb
+++ b/cookbooks/cdo-apps/templates/default/crontab.erb
@@ -82,7 +82,6 @@
if node.chef_environment == 'production' # production daemon
cronjob at:'20 */2 * * *', do:deploy_dir('bin', 'cron', 'activity-monitor')
- cronjob at:'5 6 * * *', do:deploy_dir('bin', 'cron', 'send_workshop_reminder_emails')
cronjob at:'15 16 * * *', do:dashboard_dir('bin','scheduled_ops_emails')
cronjob at:'30 14 * * *', do:dashboard_dir('bin','scheduled_pd_workshop_emails')
cronjob at:'* 14 * * 1', do:dashboard_dir('bin','scheduled_pd_application_emails')
diff --git a/dashboard/app/assets/stylesheets/extra_links.scss b/dashboard/app/assets/stylesheets/extra_links.scss
index 1e68fd16af673..c60acf807611a 100644
--- a/dashboard/app/assets/stylesheets/extra_links.scss
+++ b/dashboard/app/assets/stylesheets/extra_links.scss
@@ -24,5 +24,5 @@
/* only display scrollbars when needed */
overflow: auto;
/* admin box appears in front of the rest of the level */
- z-index: 400;
+ z-index: 1000;
}
diff --git a/dashboard/app/controllers/api/v1/regional_partners_controller.rb b/dashboard/app/controllers/api/v1/regional_partners_controller.rb
index 9209b3ac83fcf..45478d3520fbf 100644
--- a/dashboard/app/controllers/api/v1/regional_partners_controller.rb
+++ b/dashboard/app/controllers/api/v1/regional_partners_controller.rb
@@ -11,4 +11,11 @@ def index
render json: regional_partner_mapping, include: :regional_partner
end
end
+
+ # GET /api/v1/regional-partner/for_user
+ def for_user
+ regional_partners = current_user.permission?(UserPermission::WORKSHOP_ADMIN) ? RegionalPartner.all : current_user.regional_partners
+
+ render json: regional_partners.order(:name).map {|partner| {id: partner.id, name: partner.name}}
+ end
end
diff --git a/dashboard/app/controllers/discourse_sso_controller.rb b/dashboard/app/controllers/discourse_sso_controller.rb
index bff0e33e7c783..77f0743c2a835 100644
--- a/dashboard/app/controllers/discourse_sso_controller.rb
+++ b/dashboard/app/controllers/discourse_sso_controller.rb
@@ -12,7 +12,6 @@ def sso
sso.external_id = current_user.id # from devise
sso.sso_secret = secret
sso.sso_url = CDO.discourse_sso_url
- sso.add_groups = 'Verified-Teachers' if current_user.verified_teacher?
redirect_to sso.to_url(CDO.discourse_sso_url)
end
diff --git a/dashboard/app/controllers/maker_controller.rb b/dashboard/app/controllers/maker_controller.rb
index e99088b823563..e0c1aab5a19df 100644
--- a/dashboard/app/controllers/maker_controller.rb
+++ b/dashboard/app/controllers/maker_controller.rb
@@ -1,11 +1,14 @@
require 'cdo/script_constants'
class MakerController < ApplicationController
- authorize_resource class: :maker_discount, except: :setup
+ authorize_resource class: :maker_discount, except: [:home, :setup]
# Maker Toolkit is currently used in CSD unit 6.
# Retrieves the current CSD unit 6 level that the user is working on.
def home
+ # Redirect to login if not signed in
+ authenticate_user!
+
csd_unit_6_script = Script.find_by_name(Script::CSD6_NAME)
current_level = current_user.next_unpassed_progression_level(csd_unit_6_script)
@csd_unit_6 = {
diff --git a/dashboard/app/controllers/projects_controller.rb b/dashboard/app/controllers/projects_controller.rb
index d8ce3660adbf4..03200e551040c 100644
--- a/dashboard/app/controllers/projects_controller.rb
+++ b/dashboard/app/controllers/projects_controller.rb
@@ -237,12 +237,17 @@ def create_new
return
end
return if redirect_under_13_without_tos_teacher(@level)
- redirect_to action: 'edit', channel_id: ChannelToken.create_channel(
+ channel = ChannelToken.create_channel(
request.ip,
StorageApps.new(storage_id('user')),
data: initial_data,
type: params[:key]
)
+ redirect_to(
+ action: 'edit',
+ channel_id: channel,
+ enableMaker: params['enableMaker'] ? true : nil
+ )
end
private def initial_data
diff --git a/dashboard/app/models/levels/gamelab_jr.rb b/dashboard/app/models/levels/gamelab_jr.rb
index 2c79da35f14ab..72c4c9a92bcfa 100644
--- a/dashboard/app/models/levels/gamelab_jr.rb
+++ b/dashboard/app/models/levels/gamelab_jr.rb
@@ -52,12 +52,28 @@ def common_blocks(type)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -68,6 +84,7 @@ def common_blocks(type)
+
@@ -91,6 +108,41 @@ def common_blocks(type)
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 10
+
+
+
+
+ 1
+
+
+
+
XML
end
diff --git a/dashboard/app/models/pd/teachercon1819_registration.rb b/dashboard/app/models/pd/teachercon1819_registration.rb
index 6d53490e11f8e..e685ce1a2ee7a 100644
--- a/dashboard/app/models/pd/teachercon1819_registration.rb
+++ b/dashboard/app/models/pd/teachercon1819_registration.rb
@@ -11,8 +11,8 @@
#
# Indexes
#
-# index_pd_teachercon1819_registrations_on_pd_application_id (pd_application_id)
-# index_pd_teachercon1819_registrations_on_regional_partner_id (regional_partner_id)
+# index_pd_summer_event1819_registrations_on_pd_application_id (pd_application_id)
+# index_pd_summer_event1819_registrations_on_regional_partner_id (regional_partner_id)
#
require 'cdo/shared_constants/pd/teachercon1819_registration_constants'
diff --git a/dashboard/app/views/maker/home.html.haml b/dashboard/app/views/maker/home.html.haml
index 7ac79f6405399..afb877e85d49c 100644
--- a/dashboard/app/views/maker/home.html.haml
+++ b/dashboard/app/views/maker/home.html.haml
@@ -1,3 +1,4 @@
+- @page_title = 'Code.org Maker App'
- maker_home_data = {course: @csd_unit_6}
%script{src: minifiable_asset_path('js/maker/home.js'), data: {makerHome: maker_home_data.to_json}}
diff --git a/dashboard/app/views/pd/workshop_mailer/_teacher_enrollment_details.html.haml b/dashboard/app/views/pd/workshop_mailer/_teacher_enrollment_details.html.haml
index a8b5b2f319791..316af7b0f8cc0 100644
--- a/dashboard/app/views/pd/workshop_mailer/_teacher_enrollment_details.html.haml
+++ b/dashboard/app/views/pd/workshop_mailer/_teacher_enrollment_details.html.haml
@@ -33,7 +33,8 @@
%ul
%li
It helps us understand who the population of teachers involved in our
- Computer Science Principles (CSP) PD program are.
+ = @workshop.course
+ PD program are.
%li
Your students will be asked to take a similar survey as part of the
course. This gives you a bit of a preview of the kinds of questions we
diff --git a/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_receipt.html.haml b/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_receipt.html.haml
index 1883291320556..fc184d69fef9b 100644
--- a/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_receipt.html.haml
+++ b/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_receipt.html.haml
@@ -10,7 +10,10 @@
- if @workshop.local_summer?
%p
Thanks for enrolling in
- = "#{@workshop.organizer.name}’#{@workshop.organizer.name.ends_with?('s') ? '' : 's'} 5-day Summer workshop on the Code.org CS Principles curriculum."
+ = "#{@workshop.organizer.name}’#{@workshop.organizer.name.ends_with?('s') ? '' : 's'} "
+ 5-day Summer workshop on the Code.org
+ = @workshop.course
+ curriculum.
- else
%p
Thanks for enrolling in Code.org’s
diff --git a/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_reminder.html.haml b/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_reminder.html.haml
index 4d7d96cc3d0a7..b95fe23b78ab3 100644
--- a/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_reminder.html.haml
+++ b/dashboard/app/views/pd/workshop_mailer/teacher_enrollment_reminder.html.haml
@@ -10,7 +10,8 @@
- if @workshop.local_summer?
%p
This is a reminder about your upcoming 5-day Summer workshop on the Code.org
- CS Principles curriculum.
+ = @workshop.course
+ curriculum.
- else
%p
This is a reminder about your upcoming Code.org
diff --git a/dashboard/app/views/scripts/show.html.haml b/dashboard/app/views/scripts/show.html.haml
index 9d01d3b75d104..b5835314cf520 100644
--- a/dashboard/app/views/scripts/show.html.haml
+++ b/dashboard/app/views/scripts/show.html.haml
@@ -70,11 +70,22 @@
- @script.courses.each do |course|
%li= link_to course_path(course)
- levels = Script.get_from_cache(@script.name).stages.map{ |stage| stage.script_levels.map{ |sl| sl.level }}.flatten
+ .row
+ .span1
+ = "Index"
+ .span3
+ = "Level name"
+ .span3
+ = "Template level"
+ .span3
+ = "Contained levels"
- levels.each_with_index do |level, index|
.row
.span1
= index + 1
.span3
= level.name
- .span8
- = level.instructions
+ .span3
+ = level.properties['project_template_level_name']
+ .span3
+ = level.properties['contained_level_names'].join(", ")
diff --git a/dashboard/config/routes.rb b/dashboard/config/routes.rb
index 38f2ec8cf6294..dcc69969edb29 100644
--- a/dashboard/config/routes.rb
+++ b/dashboard/config/routes.rb
@@ -553,6 +553,7 @@ module OPS
get 'schools/:school_district_id/:school_type', to: 'schools#index', defaults: {format: 'json'}
get 'schools/:id', to: 'schools#show', defaults: {format: 'json'}
get 'regional-partners/:school_district_id/:course', to: 'regional_partners#index', defaults: {format: 'json'}
+ get 'regional-partners/for_user', 'regional_partners'
get 'projects/gallery/public/:project_type/:limit(/:published_before)', to: 'projects/public_gallery#index', defaults: {format: 'json'}
diff --git a/dashboard/config/scripts/levels/New Game Lab Jr Project.level b/dashboard/config/scripts/levels/New Game Lab Jr Project.level
index 044abaf19dd57..0fb7728cb2b53 100644
--- a/dashboard/config/scripts/levels/New Game Lab Jr Project.level
+++ b/dashboard/config/scripts/levels/New Game Lab Jr Project.level
@@ -231,6 +231,15 @@
+
+
+
+
+ #ff0000
+
+
+
+ sprite
@@ -278,6 +287,46 @@
+
+
+
+ sprite
+
+
+
+
+ other
+
+
+
+
+
+
+ sprite
+
+
+
+
+
+
+ group
+
+
+
+
+
+
+
+ sprite
+
+
+
+
+ group
+
+
+
+
@@ -288,8 +337,79 @@
+
+
+
+ sprite
+
+
+
+
+ other
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+ WHILE
+
+
+ i
+
+
+ 1
+
+
+
+
+ 10
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 100
+
+
+
+
+
+
+
+ EQ
+
+
+ AND
+
+
+
+ TRUE
+
+
diff --git a/dashboard/test/controllers/api/v1/regional_partners_controller_test.rb b/dashboard/test/controllers/api/v1/regional_partners_controller_test.rb
index 975951ca6ddf9..1f3f079592459 100644
--- a/dashboard/test/controllers/api/v1/regional_partners_controller_test.rb
+++ b/dashboard/test/controllers/api/v1/regional_partners_controller_test.rb
@@ -43,4 +43,35 @@ class Api::V1::RegionalPartnersControllerTest < ActionController::TestCase
assert_equal workshop_days, response['workshop_days']
end
end
+
+ test 'for_user gets regional partners for user' do
+ program_manager = create :teacher
+
+ regional_partner_for_user = create :regional_partner, name: 'Regional Partner'
+ regional_partner_for_user.program_manager = program_manager.id
+
+ another_regional_partner_for_user = create :regional_partner, name: 'Another Regional Partner'
+ another_regional_partner_for_user.program_manager = program_manager.id
+
+ create :regional_partner, name: 'Other regional partner'
+
+ sign_in program_manager
+
+ get :for_user
+ response = JSON.parse(@response.body)
+ assert_equal [
+ {'name' => 'Another Regional Partner', 'id' => another_regional_partner_for_user.id},
+ {'name' => 'Regional Partner', 'id' => regional_partner_for_user.id}
+ ], response
+ end
+
+ test 'for_user gets all regional partners for workshop admin' do
+ regional_partner = create :regional_partner, name: 'New regional partner'
+ sign_in (create :workshop_admin)
+
+ get :for_user
+ response = JSON.parse(@response.body)
+ assert_equal RegionalPartner.count, response.length
+ assert response.include?({'id' => regional_partner.id, 'name' => regional_partner.name})
+ end
end
diff --git a/dashboard/test/controllers/api_controller_test.rb b/dashboard/test/controllers/api_controller_test.rb
index dff9d16b7ea50..8f63da1d0ff24 100644
--- a/dashboard/test/controllers/api_controller_test.rb
+++ b/dashboard/test/controllers/api_controller_test.rb
@@ -402,21 +402,14 @@ class ApiControllerTest < ActionController::TestCase
}
]
- response_body = JSON.parse(@response.body)
- # Since the order of the levelgroup_results with the response isn't defined, we manually
- # compare the actual and expected responses.
- # TODO(asher): Generalize this to somewhere where it can be reused.
- assert_equal 1, response_body.length
- assert_equal ['stage', 'levelgroup_results'], response_body[0].keys
- assert_equal expected_response[0]['stage'], response_body[0]['stage']
- assert_equal expected_response[0]['levelgroup_results'].count,
- response_body[0]['levelgroup_results'].count
- expected_response[0]['levelgroup_results'].each do |result|
- assert response_body[0]['levelgroup_results'].include? result
- end
- response_body[0]['levelgroup_results'].each do |result|
- assert expected_response[0]['levelgroup_results'].include? result
- end
+ actual_response = JSON.parse(@response.body)
+ assert_equal 1, actual_response.length
+ assert_equal ['stage', 'levelgroup_results'], actual_response[0].keys
+ assert_equal expected_response[0]['stage'], actual_response[0]['stage']
+ assert_levelgroup_results_match(
+ expected_response[0]['levelgroup_results'],
+ actual_response[0]['levelgroup_results']
+ )
end
test "should get surveys for section with script with single page anonymous level_group assessment" do
@@ -541,7 +534,14 @@ class ApiControllerTest < ActionController::TestCase
}
]
- assert_equal expected_response, JSON.parse(@response.body)
+ actual_response = JSON.parse(@response.body)
+ assert_equal 1, actual_response.length
+ assert_equal ['stage', 'levelgroup_results'], actual_response[0].keys
+ assert_equal expected_response[0]['stage'], actual_response[0]['stage']
+ assert_levelgroup_results_match(
+ expected_response[0]['levelgroup_results'],
+ actual_response[0]['levelgroup_results']
+ )
end
test "no anonymous survey data via assessment call" do
@@ -1600,4 +1600,68 @@ class ApiControllerTest < ActionController::TestCase
{method: "get", path: "/api/student_progress/2/15"}
)
end
+
+ #
+ # Given two arrays, checks that they represent equivalent bags (or multisets)
+ # of elements.
+ #
+ # Equivalent: [1, 1, 2], [1, 2, 1]
+ # Not equivalent: [1, 1, 2], [1, 2, 2]
+ #
+ # Optionally takes a comparator block. If omitted, == comparison is used.
+ #
+ # equivalent_bags?([2, 3, 4], [12, 13, 14]) {|a,b| a%10 == b%10}
+ #
+ # @param [Array] bag_a
+ # @param [Array] bag_b
+ # @param [Block] (optional) comparator
+ # @return [Boolean] true if sets are equivalent, false if not
+ #
+ def equivalent_bags?(bag_a, bag_b)
+ bag_b_remaining = bag_b.clone
+ bag_a.each do |a|
+ match_index = bag_b_remaining.find_index do |b|
+ if block_given?
+ yield a, b
+ else
+ a == b
+ end
+ end
+ if match_index.nil?
+ return false
+ else
+ bag_b_remaining.delete_at match_index
+ end
+ end
+ bag_b_remaining.empty?
+ end
+
+ test 'equivalent_bags? helper' do
+ assert equivalent_bags? [], []
+ assert equivalent_bags? [1, 1, 1, 2, 2], [2, 1, 2, 1, 1]
+ refute equivalent_bags? [1, 1, 1, 2, 2], [1, 1, 2, 2, 2]
+ assert equivalent_bags? [2, 3, 4], [12, 13, 14] {|a, b| a % 10 == b % 10}
+ refute equivalent_bags? [2, 3, 4], [11, 12, 13] {|a, b| a % 10 == b % 10}
+ end
+
+ def assert_levelgroup_results_match(expected_results, actual_results)
+ match = equivalent_bags?(expected_results, actual_results) do |expected, actual|
+ expected['type'] == actual['type'] &&
+ expected['question'] == actual['question'] &&
+ expected['answer_texts'] == actual['answer_texts'] &&
+ equivalent_bags?(expected['results'], actual['results'])
+ end
+ assert match, </edit' do
+ get :create_new, params: {key: 'applab'}
+ assert_response :redirect
+ assert @response.headers['Location'].ends_with? '/edit'
+ end
+
+ test '/applab/new with enableMaker param preserves param in redirect' do
+ get :create_new, params: {key: 'applab', enableMaker: 'true'}
+ assert_response :redirect
+ assert @response.headers['Location'].ends_with? '/edit?enableMaker=true'
+ end
end
diff --git a/dashboard/test/mailers/previews/pd_workshop_mailer_preview.rb b/dashboard/test/mailers/previews/pd_workshop_mailer_preview.rb
index 8e0b03bdc695e..da6509ee159dc 100644
--- a/dashboard/test/mailers/previews/pd_workshop_mailer_preview.rb
+++ b/dashboard/test/mailers/previews/pd_workshop_mailer_preview.rb
@@ -18,6 +18,10 @@ def teacher_enrollment_receipt__csf
mail :teacher_enrollment_receipt, Pd::Workshop::COURSE_CSF
end
+ def teacher_enrollment_receipt__csd_summer_workshop
+ mail :teacher_enrollment_receipt, Pd::Workshop::COURSE_CSD, Pd::Workshop::SUBJECT_CSD_SUMMER_WORKSHOP
+ end
+
def teacher_enrollment_receipt__csp_summer_workshop
mail :teacher_enrollment_receipt, Pd::Workshop::COURSE_CSP, Pd::Workshop::SUBJECT_CSP_SUMMER_WORKSHOP
end
@@ -38,6 +42,10 @@ def teacher_enrollment_reminder__csf
mail :teacher_enrollment_reminder, Pd::Workshop::COURSE_CSF
end
+ def teacher_enrollment_reminder__csd_summer_workshop
+ mail :teacher_enrollment_reminder, Pd::Workshop::COURSE_CSD, Pd::Workshop::SUBJECT_CSD_SUMMER_WORKSHOP
+ end
+
def teacher_enrollment_reminder__csp_summer_workshop
mail :teacher_enrollment_reminder, Pd::Workshop::COURSE_CSP, Pd::Workshop::SUBJECT_CSP_SUMMER_WORKSHOP
end
diff --git a/lib/cdo/redshift.rb b/lib/cdo/redshift.rb
new file mode 100644
index 0000000000000..fc222f516969b
--- /dev/null
+++ b/lib/cdo/redshift.rb
@@ -0,0 +1,31 @@
+# WARNING: This is explicitly not included in our root Gemfile for the reasons discussed in the PR
+# https://github.com/code-dot-org/code-dot-org/pull/14056. A separate gemfile should be created for
+# any scripts needing usage of this client and loaded via RakeUtils.with_bundle_dir.
+# @example:
+# RakeUtils.with_bundle_dir(File.dirname(__FILE__)) do
+# require 'cdo/redshift'
+# end
+
+RakeUtils.with_bundle_dir(File.expand_path('../../../bin/cron/with_pg', __FILE__)) do
+ require 'pg'
+end
+require 'singleton'
+
+# A thin wrapper around PG, providing a mechanism to execute SQL commands on our AWS Redshift
+# instance.
+class RedshiftClient
+ include Singleton
+
+ def initialize
+ port = 5439
+ options = ''
+ tty = ''
+ dbname = 'dashboard'
+ login = 'dev'
+ @conn = PGconn.new(CDO.redshift_host, port, options, tty, dbname, login, CDO.redshift_password)
+ end
+
+ def exec(sql_query)
+ @conn.exec(sql)
+ end
+end
diff --git a/pegasus/cache/i18n/en-US.yml b/pegasus/cache/i18n/en-US.yml
index 1ee4d30fe37b9..e60fb6593129c 100644
--- a/pegasus/cache/i18n/en-US.yml
+++ b/pegasus/cache/i18n/en-US.yml
@@ -1076,12 +1076,12 @@
course2_gradelevel: "Ages 6-18"
course3_gradelevel: "Ages 8-18"
course4_gradelevel: "Ages 10-18"
- coursea_gradelevel: "Grade 5+"
- courseb_gradelevel: "Grade 6+"
- coursec_gradelevel: "Grade 7+"
- coursed_gradelevel: "Grade 8+"
- coursee_gradelevel: "Grade 9+"
- coursef_gradelevel: "Grade 10+"
+ coursea_gradelevel: "Ages 4-7"
+ courseb_gradelevel: "Ages 5-8"
+ coursec_gradelevel: "Ages 6-10"
+ coursed_gradelevel: "Ages 7-11"
+ coursee_gradelevel: "Ages 8-12"
+ coursef_gradelevel: "Ages 9-13"
accelerated_gradelevel: "Ages 10-18"
codeorg_platformtext: "Modern browsers, smartphones, tablets"
codeintl_platformtext: "Modern browsers, smartphones, tablets"
@@ -1184,12 +1184,12 @@
course2_shortdescription_congrats: "For students with basic reading skills, this course builds on Course 1. Students will create programs to solve problems and develop interactive games or stories they can share. Recommended for grades 2-5."
course3_shortdescription_congrats: "Ready for the next level? Students will delve deeper into programming topics introduced in previous courses to find flexible solutions to more complex problems. By the end of this course, students create interactive stories and games they can share with anyone. Recommended for grades 4-5."
course4_shortdescription_congrats: "Ready to go further? Students will delve deeper into programming topics introduced in previous courses to find flexible solutions to more complex problems. By the end of this course, students create interactive stories and games they can share with anyone. Recommended for grades 4-8."
- coursea_shortdescription_congrats: ""
- courseb_shortdescription_congrats: ""
- coursec_shortdescription_congrats: ""
- coursed_shortdescription_congrats: ""
- coursee_shortdescription_congrats: ""
- coursef_shortdescription_congrats: ""
+ coursea_shortdescription_congrats: "An introduction to computer science for pre-readers."
+ courseb_shortdescription_congrats: "An introduction to computer science for pre-readers. (Similar to Course A, but with more variety for older students.)"
+ coursec_shortdescription_congrats: "Learn the basics of computer science and create your own art, stories, and games."
+ coursed_shortdescription_congrats: "Quickly cover concepts from Course C, then go further with algorithms, nested loops, conditionals, and more."
+ coursee_shortdescription_congrats: "Quickly cover concepts in Course C & D and then go further with functions."
+ coursef_shortdescription_congrats: "Learn all the concepts in Computer Science Fundamentals and create your own art, story or game."
codeorg_longdescription: "Learn the basic concepts of Computer Science with drag and drop programming. This is a game-like, self-directed tutorial starring video lectures by Bill Gates, Mark Zuckerberg, Angry Birds and Plants vs. Zombies. Learn repeat-loops, conditionals, and basic algorithms. Available in 34 languages."
codeintl_longdescription: "Learn the basic concepts of Computer Science with drag and drop programming. This is a game-like, self-directed tutorial starring video lectures by Bill Gates, Mark Zuckerberg, Angry Birds and Plants vs. Zombies. Learn repeat-loops, conditionals, and basic algorithms. Available in 34 languages."
thinkersmithspanish_longdescription: "Mediante el uso de un \"Vocabulario Robot\" predefinido, los estudiantes descubrirán como guiarse de modo tal de llevar a cabo tareas específicas sin ser estas discutidas previamente. Este segmento enseña a los estudiantes la conexión entre símbolos y acciones así como la valiosa habilidad de depuración."
diff --git a/pegasus/data/cdo-partners.csv b/pegasus/data/cdo-partners.csv
index ed647c14ab7e4..fe504c8e0f121 100644
--- a/pegasus/data/cdo-partners.csv
+++ b/pegasus/data/cdo-partners.csv
@@ -197,15 +197,18 @@ Codeforsu,http://www.codeforsu.org,international,TRUE,FALSE,TRUE,
CoderDojo,http://coderdojo.com/,international,TRUE,FALSE,TRUE,
CodingMarch,http://www.codingmarch.com/,international,FALSE,FALSE,TRUE,
CPIT,http://www.cpit.ac.nz/news-and-events/news/cpit-supports-hour-of-code?utm_source=Homepage&utm_medium=Banner&utm_campaign=ICT%20-%20Hour%20of%20Code#,international,TRUE,FALSE,TRUE,
+Czechitas,https://www.czechitas.cz/en/,international,TRUE,FALSE,TRUE,
Edvira,http://edvira.com,international,TRUE,FALSE,TRUE,
Excited Digital Learning,https://vimeo.com/excited,international,TRUE,FALSE,TRUE,
Fundacao Lemann,http://www.fundacaolemann.org.br/,international,TRUE,FALSE,TRUE,
Fundacion Sadosky,http://www.fundacionsadosky.org.ar/,international,TRUE,FALSE,TRUE,
Gabinete de Modernizacao das Tecnologias Educativas,http://www02.madeira-edu.pt/dre/main.aspx,international,TRUE,FALSE,TRUE,
+IAMAI Academy,https://iamai.hk/,international,FALSE,FALSE,TRUE,
Inspiring Fifty,http://www.inspiringfifty.com/,international,TRUE,FALSE,TRUE,
Jawwal,http://www.jawwal.ps/,international,TRUE,FALSE,TRUE,
Kids Code Jeunesse,http://kidscodejeunesse.org/,international,TRUE,FALSE,TRUE,
Kids and Code,http://www.kidsandcode.org,international,TRUE,FALSE,TRUE,
+Korea Information Science Education Federation,http://kcode.kr/,international,TRUE,FALSE,TRUE,
Love To Code,http://www.lovetocode.kz/,international,TRUE,FALSE,TRUE,
Malaysia Digital Economy Corporation,https://mdec.com.my/,international,TRUE,FALSE,TRUE,
Miur,http://www.istruzione.it/,international,TRUE,FALSE,TRUE,
@@ -218,6 +221,7 @@ Programar,http://program.ar/,international,TRUE,FALSE,TRUE,
Programma Il Futuro,https://www.programmailfuturo.it/,international,TRUE,FALSE,TRUE,
Rishs International School,http://www.rishsinternationalschool.com/,international,FALSE,FALSE,TRUE,
RobinCode,http://www.robincode.org/,international,TRUE,FALSE,TRUE,
+Sault Ste. Marie Innovation Centre,https://ssmic.com/,international,FALSE,FALSE,TRUE,
Student Edge,https://studentedge.com.au/,international,TRUE,FALSE,TRUE,
Suriname Online Education Center,http://www.soec.sr,international,TRUE,FALSE,TRUE,
Transforma Espana,http://ftransformaespana.es/,international,TRUE,FALSE,TRUE,
diff --git a/pegasus/data/cdo-state-promote.csv b/pegasus/data/cdo-state-promote.csv
index ad7a9befbb774..fecd460f791c1 100644
--- a/pegasus/data/cdo-state-promote.csv
+++ b/pegasus/data/cdo-state-promote.csv
@@ -24,7 +24,7 @@ ME,Maine,1384,3.4,112,24,-1272,No,No,No,No,No,No,No,No,No,,,,,76323,105631032,44
MI,Michigan,14358,3.6,1793,78,-12565,No,Yes,Yes,No,No,Yes,No,No,No,,,,,80478,1155503124,47350,5,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%,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,438946,7144,,,,,,,,,,,,
MN,Minnesota,12498,2.6,895,39,-11603,No,Yes,No,No,No,No,No,No,No,,,,Add your support,90134,1126494732,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%,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,318748,6610,,,,,,,,,,,,
MO,Missouri,10146,3.7,1138,47,-9008,No,No,No,No,No,No,No,No,No,,,,,82050,832479300,44620,1,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%,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,789,0,3,0,0,1357000,3606,2269,2547,1716,1567,942,399,301079,6289,,,,,,,,,,,,
-MS,Mississippi,1289,4.4,155,14,-1134,No,No,Yes,No,No,No,No,No,Yes,,,,,69507,89594523,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%,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,90737,2526,,,,,,,,,,,,
+MS,Mississippi,1289,4.4,155,14,-1134,No,No,Yes,Other,No,No,No,No,Yes,,,,,69507,89594523,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%,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,90737,2526,,Mississippi is in the process of developing K-12 computer science standards.,,,,,,,,,,K-12 CS standards in progress
MT,Montana,888,2.7,75,10,-813,No,No,Yes,No,No,Yes,No,No,No,,,,,64375,57165000,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%,www.code.org/promote/MT,no school districts in the state,America Campaign - Big Sky Code Academy and Technology and Innovation in Education,none,0,0,12,20,0,0,185000,485,374,120,341,116,4,9,40783,1186,,,,,,,,,,,,
NC,North Carolina,18069,4.5,1284,71,-16785,No,Yes,Yes,No,Yes,No,No,No,No,,,,,88971,1607616999,45280,13,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%,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,2248,54,28,0,38,2456000,11770,6626,4421,10183,3806,12482,1425,458574,11010,,,,,,,,,,,,
ND,North Dakota,935,3.3,117,5,-818,No,Yes,Yes,No,No,No,No,No,No,,,,,70311,65740785,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%,www.code.org/promote/ND,no school districts in the state,America Campaign - Big Sky Code Academy and Technology and Innovation in Education,none,1,10,0,0,0,0,104000,354,151,170,1,95,6,35,33064,1117,,,,,,,,,,,,
diff --git a/pegasus/helpers/professional_development_workshop_helpers.rb b/pegasus/helpers/professional_development_workshop_helpers.rb
deleted file mode 100644
index 44a38905a64c2..0000000000000
--- a/pegasus/helpers/professional_development_workshop_helpers.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-require 'tzinfo'
-
-def parse_date(date_string)
- return nil if date_string.nil?
-
- time = Chronic.parse(date_string)
- return nil if time.nil?
-
- date = time.to_date
-
- # midnight pacific time
- tz = TZInfo::Timezone.get('US/Pacific')
- tz.local_to_utc(Time.utc(date.year, date.month, date.day))
-end
-
-def generate_professional_development_workshop_payment_report(from=nil, to=nil)
- # generate a report to be used for paying affiliates
-
- if from && to
- from = parse_date(from)
- to = parse_date(to)
- end
-
- DB[:forms].where(kind: "ProfessionalDevelopmentWorkshop").map do |row|
- data = JSON.parse(row[:data]) rescue {}
- processed_data = JSON.parse(row[:processed_data]) rescue {}
-
- stopped_at = Chronic.parse(data['stopped_dt'])
-
- # TODO: database can't do the below date filtering because stopped_at is in the serialized JSON
- next unless stopped_at
- next if from && to && (stopped_at < from || stopped_at > to)
-
- {
- name: row[:name],
- user_id: row[:user_id],
- email: row[:email],
- type: data["type_s"],
- section_url: "https://code.org/teacher-dashboard#/sections/#{data['section_id_s']}",
- stopped_at: stopped_at.to_s,
- total_attendee_count: processed_data['total_attendee_count_i'],
- qualifying_attendee_count: processed_data['qualifying_attendee_count_i']
- }
- end.compact
-end
-
-def generate_professional_development_workshop_teachers_report
- # Grab the script IDs for the CSF scripts.
- csf_script_ids = DASHBOARD_DB[:scripts].
- where('name IN ("20-hour", "course1", "course2", "course3", "course4")').
- select(:id).
- map(&:values).
- flatten
-
- # generate a report about the teachers trained by affiliates and their students' progress
- PEGASUS_DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshop').map do |affiliate|
- data = JSON.parse(affiliate[:data]) rescue {}
-
- section_id = data['section_id_s']
- next unless section_id
-
- # a row for each teacher trained by an affiliate
- DASHBOARD_DB[:followers].
- where(section_id: section_id).
- join(:users, id: :student_user_id).
- select(:users__id___id, :users__name___name, :users__email___email).map do |teacher|
- # get data on students of the teacher
- teacher_user_id = teacher[:id]
- next unless teacher_user_id
-
- students_count = DASHBOARD_DB[:followers].
- where(user_id: teacher_user_id).
- join(:users, id: :student_user_id).
- count
-
- students_with_progress_count = DASHBOARD_DB[:followers].
- where(followers__user_id: teacher_user_id).
- join(:users, id: :student_user_id).
- join(:user_scripts, user_id: :id).
- where(script_id: csf_script_ids).
- count
-
- {
- teacher_id: teacher_user_id,
- students_count: students_count,
- students_with_progress_count: students_with_progress_count
- }
- end.compact
- end.compact.flatten
-end
-
-def generate_professional_development_workshop_signup_report(secret)
- workshop = PEGASUS_DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshop', secret: secret).first
-
- PEGASUS_DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshopSignup', parent_id: workshop[:id]).map do |row|
- data = JSON.parse(row[:data]) rescue {}
- if data['status_s'] == 'cancelled'
- nil
- else
- {
- name: data['name_s'],
- email: data['email_s'],
- role: (data['teacher_role_ss'] - ['Other']).concat(data['teacher_role_other_ss'] || []).uniq.to_csv,
- experience: data['teacher_tech_experience_level_s'].gsub(/ \(.*$/, ''),
- school_name: data['school_name_s'],
- school_location: data['school_location_s'],
- school_type: (data['school_type_ss'] - ['Other']).concat(data['school_type_other_ss'] || []).uniq.to_csv,
- school_district: data['school_district_s'],
- school_levels: (data['school_levels_ss'] - ['Other']).concat(data['school_levels_other_ss'] || []).uniq.to_csv,
- students: data['number_students_s'],
- }
- end
- end.compact
-end
-
-def generate_professional_development_workshops_report(from=nil, to=nil)
- from = Chronic.parse(from.to_s)
- to = Chronic.parse(to.to_s)
-
- PEGASUS_DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshop').map do |workshop|
- data = JSON.parse(workshop[:data]) rescue {}
-
- if first_date = data['dates'].first
- first_date = first_date['date_s']
- first_date = Chronic.parse(first_date.to_s)
- end
-
- next unless first_date
- next if from && to && (first_date < from || first_date > to)
-
- signup_count = 0
-
- PEGASUS_DB[:forms].
- where(kind: 'ProfessionalDevelopmentWorkshopSignup').
- and(parent_id: workshop[:id]).
- map do |signup|
- signup_data = JSON.parse(signup[:data]) rescue {}
- signup_count += 1 unless signup_data['status_s'] == 'cancelled'
- end
-
- {
- Name: data['name_s'],
- User_ID: workshop[:user_id],
- Email: data['email_s'],
- Date: data['dates'].map {|i| i['date_s']}.join(' '),
- Location: data['location_name_s'] + ' (' + data['location_address_s'] + ')',
- Type: data['type_s'],
- Signups: signup_count.to_s + '/' + data['capacity_s'],
- }
- end.compact.flatten
-end
diff --git a/pegasus/routes/v2_forms_routes.rb b/pegasus/routes/v2_forms_routes.rb
index bebe571e373a3..46e16ba678910 100644
--- a/pegasus/routes/v2_forms_routes.rb
+++ b/pegasus/routes/v2_forms_routes.rb
@@ -89,29 +89,6 @@
call(env.merge('REQUEST_METHOD' => 'REVIEW', 'PATH_INFO' => "/v2/forms/#{kind}/#{secret}"))
end
-get '/v2/forms/ProfessionalDevelopmentWorkshopSignup/:secret/status/cancelled' do |secret|
- def send_receipts(form)
- templates = ['workshop_signup_cancel_receipt', 'workshop_signup_cancel_notice']
- recipient = Poste2.create_recipient(form[:email], name: form[:name], ip_address: form[:updated_ip])
- templates.each do |template|
- Poste2.send_message(template, recipient, form_id: form[:id])
- end
- templates.count
- end
-
- dont_cache
- form = DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshopSignup', secret: secret).first
- forbidden! if form.empty?
- data = JSON.parse(form[:data])
- data['status_s'] = 'cancelled'
- DB[:forms].where(kind: 'ProfessionalDevelopmentWorkshopSignup', secret: secret).update(data: data.to_json, indexed_at: nil)
-
- send_receipts(form)
-
- content_type :json
- data.to_json
-end
-
get '/v2/forms/:parent_kind/:parent_secret/children/:kind' do |parent_kind, parent_secret, kind|
dont_cache
results = []
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 94ff0b5c1af31..f6e39a04b9b84 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/22bae7914bd4f357160b205e077e38a6-AK.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/88f5d0c1b643d7d988b610907b7d0e01-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 87266213004de..f743a395e3841 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/0a270d7c3a548f66e27f3d69aace44b6-AL.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/433c972f6688be2baf56c3edcfb9e92e-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 429152e177036..d0c6cc60898bf 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/c4172f461b7a895c41037cca801b542e-AR.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/0919d18471ef19742a932ded451ba40f-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 cffd2aa2bcaee..a335ebc281f17 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/1eeb5052be35e7b9d3d43a79cde42651-AZ.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/8d54dc0087a643336af57465595e4909-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 bce1b23a6a81d..3cd02806ce9bc 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/e20f6a0ee36593fa77037c16748ac83e-CA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/e50e410d673ba8db19a84f453ee117fe-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 a1beed16ed37d..eb5f38e7b8cae 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/763f85e900b525298b95d204724d6117-CO.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/178b4c9052ec6ab0f9a7437ad41e6c9d-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 7523f1410d31a..7e20a7364ce2b 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/b19cef528acf1349ada0a9d3f3eac161-CT.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/6edea68b21a65af22777e617f9ae06f5-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 6f4de6f06ed97..39373b0095162 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/f51801a97034c994c27955f396339e43-DC.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/82164f686b92fc202b82574372dc4d4b-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 678dc5af77016..6caec3de20e34 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/a109c6a71b651251fdd43bab4de838e6-DE.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/391fb6b4b7a0f7f4bb29f80fc32b899b-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 bf191a4898c8f..0489f8398dfb8 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/90263a9b7ed9c9ec15df7383534463dc-FL.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/b7635690a4329a79bca0ecdab7d68e4c-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 cf63231162052..8b024887240c6 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/b70ac7c750bd2ca9b19eba369e01622a-GA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/9ada406ee6959642c5db2f14a5eead23-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 6ceadeb61e205..62a3d934145a7 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/556cd7f6312eba4122f6acc0db4e6838-HI.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/258f014f9272e5e7bf96bda0c5ef9d1e-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 558b2e61db18a..8298e67109ae1 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/fbaac4b3cd4efad53ad92b67521529bc-IA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/dfd269ea87a72fe2b0e2fac83bcbbfd3-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 70d5aa6c6259f..e0ba865ac73b4 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/3a5df5fbabbfa29df169d80ca0f9864a-ID.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/70583b6b6da74982d58e2292e6a7b861-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 e72cd8f27a1e9..a0ceac2094136 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/e2e0950aecd2f69e2ca4eeb9decc45f5-IL.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/2d82071b2d95e1a942e0e8864db3421a-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 7fb2adcecada1..688d47f8a6089 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/2ac67f0d3a857667c6833a2073ad352a-IN.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/1b1295ecd9af6f7b463598a31453fea3-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 fa44f8bddff3e..002c33515efe0 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/f7354510903bc473fec8eac2b01e27cf-KS.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/e98fa8d859a8585aaa3bdeb927a676e7-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 98c43ba9e1376..cc83ec45f1b8e 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/63f2be270c453c07dd27c9dffe03a29a-KY.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/d17db8ce154bcd17d423a9f457452978-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 11ec2b83100f0..d8cf80d420fc2 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/a593e7d1223ba8bd6ade47968f384da3-LA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/cdba14e45084464b7bbbb9043367a461-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 a97edf9ff36ad..caca3888f3965 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/f9fd844d2f582e9472e92109b29d780a-MA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/7efab1641ce3f088b2d57e97543cd909-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 af23d7fd4c346..1a1b80d95de5a 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/7562a8b0cf78211a0557e587487fc876-MD.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/ae60d85378c66f37cfe9aa120c6e9748-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 b81fe5b5169d5..09c5f22731948 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/82697e536c5ff2fda1e3541d458c4a3b-ME.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/044c189b8b717bb52dbb0ba768707dc7-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 bf1b9711242c2..be4a5b1372e26 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/471132d81bb8376e45395576c35edaed-MI.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/2820ff7f78490b62bf05ff36e1128e16-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 9ed3122d915d6..59fb8e85d70c5 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/d9e695e5ef00bddd09ee98a0f2155e59-MN.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/ad3634d9ee9a144c51965086c2465d4b-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 08ea575797a6d..c7d2dabc5ecef 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/4a8c7f8551e757138cf6051bb68577ce-MO.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/80a1d213896ac6ee39aa526e10ffbd34-MO.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MS.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MS.pdf.fetch
index dcbb7de1025c5..a69624cdbf46b 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MS.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MS.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/ebf060c084c52535dabeb08417c1831c-MS.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/2314ee7c23b57beaf5ffb055fc7b9694-MS.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MT.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MT.pdf.fetch
index e07f01836bc34..6359b0474f536 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/MT.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/MT.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/428d433b60fb2f987c1ec263d3602e08-MT.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/20104e7cb71fcdeebcd1b9786fa582a3-MT.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NC.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NC.pdf.fetch
index 1fb709bfb8784..f0e04107d620c 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NC.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NC.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/23de3ec84e3ed2e1072f73c3dc0d4cc0-NC.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/244c13f998488f910c5043a5ed5d4bf4-NC.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/ND.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/ND.pdf.fetch
index b15535ea90e29..61d9e8ec1c56c 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/ND.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/ND.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/c3db3d5a8acf5ccd0c69f5640415dd5a-ND.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/b4df4dc0f7d7da55cb93278e714a51a1-ND.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NE.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NE.pdf.fetch
index 9b986570f064f..672ab73c64260 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NE.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NE.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/30f67b735da4e0320b01205b18344d50-NE.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/bf2a5eba124ee5b6fd832087a2bbe999-NE.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NH.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NH.pdf.fetch
index 29549350afbd6..547542ec9c423 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NH.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NH.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/6e4379473a0ef42653e3e48959c14de6-NH.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/9a998f94d9f250f2c56aa313789900f1-NH.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NJ.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NJ.pdf.fetch
index 80851c8a10fc2..e3913e62d0af0 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NJ.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NJ.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/142de33601b5d9586fb1d84e0e2ad496-NJ.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/9795d18aada3868c571b2f1e66c8c36c-NJ.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NM.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NM.pdf.fetch
index f21faf6becd46..f1e9026620bfc 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NM.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NM.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/4d3c07ced2cd7b82c4b18257c7405d7e-NM.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/19749d6261a03232978ba7d49bdd1b02-NM.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NV.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NV.pdf.fetch
index 4ebb6d1e9ee37..623eb3e255ec2 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NV.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NV.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/e8b902539aba6f77dc23f91956c0681f-NV.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/4ffdc9f89956b6b890265f424dbe53e8-NV.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NY.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NY.pdf.fetch
index e071a5f25a564..4647ac1e96dd4 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/NY.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/NY.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/68d7d758fe1be9f5c3977a0a9a11ab40-NY.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/99e2e0c36b36ea36520a4e647bc08eac-NY.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/OH.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/OH.pdf.fetch
index dabaf97fdbc1f..981429bf52c5a 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/OH.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/OH.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/29e09d00cecdbef4263751a23b2d4fb7-OH.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/3a71a96041af6dd15e14d020d1b90e16-OH.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/OK.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/OK.pdf.fetch
index a10d65dd13e67..dc528b566181f 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/OK.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/OK.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/33bb5c2552f4a1e8be50f0d607145990-OK.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/9fd5ee5696e7364385905fbff670d129-OK.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/OR.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/OR.pdf.fetch
index 67dc139dc9416..4ca8596feaf04 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/OR.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/OR.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/e0d2e85769a89429808d52b42c6576a4-OR.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/0b4f31ed9c1b4f722bf4c164675270a5-OR.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/PA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/PA.pdf.fetch
index a31d05ad4f561..eda73b6cea17f 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/PA.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/PA.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/aacede228b7c23554ec0767278b15efb-PA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/c1eb3da2f7cb044a29686fb50d4228ea-PA.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/RI.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/RI.pdf.fetch
index 339187fd31867..006f95d6ad18b 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/RI.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/RI.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/ea9835f2821cf25370d237ad36722450-RI.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/d7328c20d3b5bf7ae193e847bf6100b5-RI.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/SC.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/SC.pdf.fetch
index 90482a83ed39c..434b75af501ed 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/SC.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/SC.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/2b63ccefb27f3cd4ae084e0038b7ccbd-SC.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/d074476232a4979fd39299bcd2b92734-SC.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/SD.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/SD.pdf.fetch
index becee7ca29205..4db5d5cddecb6 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/SD.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/SD.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/d19b405845e1aa11ee3198f3b977a6a5-SD.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/b863096b5306154158c5d5990a66f5b7-SD.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/TN.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/TN.pdf.fetch
index 202608f03d00f..a1cd34c4c85fb 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/TN.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/TN.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/ad822dafd48e9bb999ee36b8fc253863-TN.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/245e022c1d8fec537564f1f1bfe10c09-TN.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/TX.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/TX.pdf.fetch
index 91739b1050ab7..3f4da8a0b6d51 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/TX.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/TX.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/60b2f82a42b570ac24af0d1ab1a83492-TX.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/11b79777efd282603dff9561e7c79d42-TX.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/UT.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/UT.pdf.fetch
index ce90e8f88207f..67bf84e583abc 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/UT.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/UT.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/3ba03247c86d32fbd63a02ccca8b6016-UT.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/4974e6411959e4e9681813e8ef00dfec-UT.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/VA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/VA.pdf.fetch
index 442a928cb11d3..bda226def5e5c 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/VA.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/VA.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/0b7502cd5c770d2ed902595c4fd539ed-VA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/d2f11b7b73bc3caebb72fbc2929bd8cf-VA.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/VT.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/VT.pdf.fetch
index 27cc00d164e51..d4e362808e61c 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/VT.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/VT.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/42a2c4347f0147ffe25421539a0e4274-VT.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/d9e90927879dbe166692785327fa58fd-VT.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WA.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WA.pdf.fetch
index 383eafd79abb6..41de73d45dd6a 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WA.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WA.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/944e09d04e1b20a51e389a70d26b1042-WA.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/4260d9b6f12db8a4b3ad60931c756164-WA.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WI.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WI.pdf.fetch
index 67be1fa1c3a94..663329f71cb24 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WI.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WI.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/a5be685ede30291fbed0ca69e0b5a424-WI.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/1f93fc0a2f7635ad89225d8b42713bd5-WI.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WV.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WV.pdf.fetch
index a2288e3fd487b..af44637cf7780 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WV.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WV.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/94c14dc0d435933a15e595d52157af9a-WV.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/1ea8e5509b13ece74f61fcffe693c268-WV.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WY.pdf.fetch b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WY.pdf.fetch
index bb4a7ce963305..a2987b325eb32 100644
--- a/pegasus/sites.v3/code.org/public/advocacy/state-facts/WY.pdf.fetch
+++ b/pegasus/sites.v3/code.org/public/advocacy/state-facts/WY.pdf.fetch
@@ -1 +1 @@
-https://cdo-fetch.s3.amazonaws.com/82c8812d4cbc3e6f609b9e194e651f1b-WY.pdf
\ No newline at end of file
+https://cdo-fetch.s3.amazonaws.com/119b1b6409715bd60e8e6d9793f98fed-WY.pdf
\ No newline at end of file
diff --git a/pegasus/sites.v3/code.org/public/educate/professional-learning/cs-discoveries-faqs.pdf b/pegasus/sites.v3/code.org/public/educate/professional-learning/cs-discoveries-faqs.pdf
deleted file mode 100644
index f5f80700f0f2e..0000000000000
Binary files a/pegasus/sites.v3/code.org/public/educate/professional-learning/cs-discoveries-faqs.pdf and /dev/null differ
diff --git a/pegasus/sites.v3/code.org/public/educate/professional-learning/cs-principles-faqs.pdf b/pegasus/sites.v3/code.org/public/educate/professional-learning/cs-principles-faqs.pdf
deleted file mode 100644
index df388604ae0b2..0000000000000
Binary files a/pegasus/sites.v3/code.org/public/educate/professional-learning/cs-principles-faqs.pdf and /dev/null differ
diff --git a/pegasus/sites.v3/code.org/public/educate/regional-partner/faq.md b/pegasus/sites.v3/code.org/public/educate/regional-partner/faq.md
index 5d193d110e7a4..303788c5c53a3 100644
--- a/pegasus/sites.v3/code.org/public/educate/regional-partner/faq.md
+++ b/pegasus/sites.v3/code.org/public/educate/regional-partner/faq.md
@@ -60,7 +60,6 @@ We are particularly looking for new Regional Partners in:
- Louisiana
- North California (Humboldt or Shasta County preferred)
- Oregon
-- Southern Illinois
- Vermont
diff --git a/pegasus/sites.v3/code.org/public/educate/regional-partner/playbook/funding.md b/pegasus/sites.v3/code.org/public/educate/regional-partner/playbook/funding.md
index 7aa22abdad496..5f3d31af113f5 100644
--- a/pegasus/sites.v3/code.org/public/educate/regional-partner/playbook/funding.md
+++ b/pegasus/sites.v3/code.org/public/educate/regional-partner/playbook/funding.md
@@ -9,6 +9,8 @@ nav: regional_partner_playbook_nav
# Topics
+- [Announcements](#announce)
+
**Organization Sustainability:**
- [Goals](#goal)
@@ -29,6 +31,22 @@ nav: regional_partner_playbook_nav
- [Supports for Pursuing Federal and State Grants](#grants)
+# Announcements
+
+### Federal Funding - Consortia Development Survey
+In March, the US Department of Education will release details about the federal grant opportunities for CS we first heard about last fall. Code.org will not be applying for these federal funds and will not lead or directly sign onto any application. We do, however, want to explore bringing together some regional partners to apply together as a consortium. There are two potential funding targets at the US Dept. of Ed -- SEED (Supporting Effective Educator Development) and EIR (Education, Innovation and Research) grant programs run by the Department of Ed. These grants typically span 3-5 years with funding of $1.5M-$5M. The grants can fund CS professional development, as well as some program management and evaluation expenses. These grants also come with compliance requirements for recipients.
+
+Code.org’s role would be to help facilitate the formation of one or more consortium (3-6 partners each) and support the development of a grant proposal with a lead partner. Each consortium member’s role would be to execute on the Code.org programs and partner with the lead for the consortium on funding and compliance requests.
+
+We’ve developed a short survey to gauge your interest and readiness for joining a consortium and to gather some initial information.
+
+The timeline is pretty tight on this because of the budget issues Washington has faced. When Department of Ed releases the grant notices in early March, there will only be 60 days to build a consortium and write the application. Once it is filed we’d expect to know the results by late summer, with funds available sometime in the fall, if successful.
+
+**Please complete this survey by February 27th**. If you are interested, we’ll get in touch with you prior to the Summit to invite you to a 30-minute meeting for prospective partners on Wednesday, March 7 (at the March Summit).
+
+[**Back to the top**](#top)
+
+________________
# How does your organization become sustainable?
This year most of your funding will come from Code.org.
diff --git a/pegasus/sites.v3/code.org/public/educate/resources/recruit.md b/pegasus/sites.v3/code.org/public/educate/resources/recruit.md
index 67cdb603ca9ef..307578238010b 100644
--- a/pegasus/sites.v3/code.org/public/educate/resources/recruit.md
+++ b/pegasus/sites.v3/code.org/public/educate/resources/recruit.md
@@ -39,7 +39,7 @@ Hear from current students as they talk about the topics covered in each course
### **Sign up for CS Discoveries**
-<%=view :display_video_thumbnail, id: "signup", video_code: "g4qfsH8bc8s", play_button: 'center' %>
+<%=view :display_video_thumbnail, id: "intro_csd", video_code: "g4qfsH8bc8s", play_button: 'center' %>
[**YouTube**](http://www.youtube.com/watch?v=g4qfsH8bc8s) |
[**Download**](https://videos.code.org/cs-discoveries/what-is-cs-discoveries.mp4)
diff --git a/pegasus/sites.v3/code.org/public/images/avatars/czechitas.png b/pegasus/sites.v3/code.org/public/images/avatars/czechitas.png
new file mode 100644
index 0000000000000..069ca6fcb961a
Binary files /dev/null and b/pegasus/sites.v3/code.org/public/images/avatars/czechitas.png differ
diff --git a/pegasus/sites.v3/code.org/public/images/avatars/korea_information_science_education_federation.png b/pegasus/sites.v3/code.org/public/images/avatars/korea_information_science_education_federation.png
new file mode 100644
index 0000000000000..9a8161e908749
Binary files /dev/null and b/pegasus/sites.v3/code.org/public/images/avatars/korea_information_science_education_federation.png differ
diff --git a/pegasus/sites.v3/code.org/public/private/professional-development-workshop-report.csv.erb b/pegasus/sites.v3/code.org/public/private/professional-development-workshop-report.csv.erb
deleted file mode 100644
index ec55f1fef35d6..0000000000000
--- a/pegasus/sites.v3/code.org/public/private/professional-development-workshop-report.csv.erb
+++ /dev/null
@@ -1,11 +0,0 @@
-<%=
-
-dont_cache
-content_type :csv
-response.headers['Content-Disposition'] = "attachment;filename=#{File.basename(request.path_info)}"
-
-require 'cdo/csv'
-
-CSV.generate_from_dataset(generate_professional_development_workshop_payment_report(params[:from], params[:to]))
-
-%>
diff --git a/pegasus/sites.v3/code.org/public/private/professional-development-workshop-report.md b/pegasus/sites.v3/code.org/public/private/professional-development-workshop-report.md
deleted file mode 100644
index d23b9bca2fb3a..0000000000000
--- a/pegasus/sites.v3/code.org/public/private/professional-development-workshop-report.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Professional Development Workshops
----
-
-# Professional Development Workshops
-
-<%
- rows = generate_professional_development_workshop_payment_report(params[:from], params[:to])
-%>
-
-## Filter by date:
-
-
-
-<% if rows.empty? %>
-## No results
-<% else %>
-
-## [ Download CSV](/private/professional-development-workshop-report.csv?from=<%= params[:from] ? URI.escape(params[:from]) : ''%>&to=<%= params[:to] ? URI.escape(params[:to]) : '' %>)
-
-## Preview
-
-
-
- <% rows[0].keys.each do |key| %>
-
<%= key %>
- <% end %>
-
- <% rows.each do |row| %>
-
- <% row.values.each do |value| %>
-
<%= value %>
- <% end %>
-
- <% end %>
-
-
-<% end %>
diff --git a/pegasus/sites.v3/code.org/public/professional-development-workshops/cancel/splat.haml b/pegasus/sites.v3/code.org/public/professional-development-workshops/cancel/splat.haml
deleted file mode 100644
index 345b5bfb0b9c9..0000000000000
--- a/pegasus/sites.v3/code.org/public/professional-development-workshops/cancel/splat.haml
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Cancel workshop registration
-nav: blank
-rightbar: blank
----
-- dont_cache
-- workshop_signup_secret = request.splat_path_info[1..-1]
-- pass unless workshop_signup = Form2.from_row(DB[:forms].where(kind:'ProfessionalDevelopmentWorkshopSignup', secret:workshop_signup_secret).first)
-- workshop_signup_data = workshop_signup.data
-- pass unless workshop = Form2.from_row(DB[:forms].where(kind:'ProfessionalDevelopmentWorkshop', id:workshop_signup.parent_id).first)
-- workshop_data = workshop.data
-
-%h1 Cancel workshop registration
-
-- if workshop_signup_data['status_s'] == 'cancelled'
- %p Your registration for this workshop has already been cancelled.
-- else
- %form#cancel-workshop-registration-form{role: "form", onsubmit: "event.preventDefault(); cancelWorkshopRegistrationFormSubmit();", style: 'margin-top: 30px;'}
- #error-message{style: 'display: none'}
- %p Are you sure you want to cancel registration for the following workshop?
- .row
- .col-sm-4{style: "text-align: right;"} Date:
- .col-sm-8
- -workshop_data['dates'].each do |date|
- =date['date_s'] + ', ' + date['start_time_s'] + '-' + date['end_time_s']
- %br/
- .row
- .col-sm-4{style: "text-align: right;"} Location:
- .col-sm-8
- = workshop_data['location_name_s']
- %br/
- = workshop_data['location_address_s']
- .row{style: "margin-top: 30px;"}
- .col-sm-8.col-sm-offset-4
- .form-group
- %button#btn-submit.btn.btn-default{type: "submit"} Cancel registration
-
- #thanks{:style=>"display: none;"}
- :markdown
- Your registration has been cancelled. You can sign up for a different workshop [here](/professional-development-workshops).
-
-:javascript
-
- function processResponse(data)
- {
- $('#cancel-workshop-registration-form').hide();
- $('#thanks').show();
- }
-
- function processError(data)
- {
- $('#error-message').text('An error occurred. Please try again or contact us if you continue to receive this error.').show();
- $('body').scrollTop(0);
- $("#btn-submit").removeAttr('disabled');
- $("#btn-submit").removeClass("button_disabled").addClass("button_enabled");
- }
-
- function cancelWorkshopRegistrationFormSubmit()
- {
- $("#btn-submit").attr('disabled','disabled');
- $("#btn-submit").removeClass("button_enabled").addClass("button_disabled");
-
- $.ajax({
- url: "/v2/forms/ProfessionalDevelopmentWorkshopSignup/#{workshop_signup_secret}/status/cancelled",
- type: "get",
- }).done(processResponse).fail(processError);
-
- return false;
- }
diff --git a/pegasus/sites.v3/code.org/public/professional-development-workshops/splat.haml b/pegasus/sites.v3/code.org/public/professional-development-workshops/splat.haml
deleted file mode 100644
index 8f5286c83b4c6..0000000000000
--- a/pegasus/sites.v3/code.org/public/professional-development-workshops/splat.haml
+++ /dev/null
@@ -1,328 +0,0 @@
----
-title: Register for a workshop
----
-- dont_cache
-- workshop_id = request.splat_path_info[1..-1]
-- pass unless form = Form2.from_row(DB[:forms].where(kind:'ProfessionalDevelopmentWorkshop', id:workshop_id).first)
-- data = form.data
-
--signup_count = 0
--signup_rows = DB[:forms].where(kind:'ProfessionalDevelopmentWorkshopSignup').and(parent_id:workshop_id)
--signup_rows.each do |signup_row|
- -signup = JSON.parse(signup_row[:data])
- -signup_count += 1 unless signup['status_s'] == 'cancelled'
-
--affiliate = Form2.from_row(DASHBOARD_DB[:users].where(id: form.user_id).first)
-
--if first_date = data['dates'].first
- -first_date = Chronic.parse(first_date['date_s'] + ' ' + first_date['start_time_s'])
-
-%script{type: "text/javascript", src: "/js/sifter.min.js"}
-%script{type: "text/javascript", src: "/js/microplugin.min.js"}
-%script{type: "text/javascript", src: "/js/selectize.min.js"}
-%script{type: "text/javascript", src: "/js/selectize-fast-click.js"}
-%link{rel: "stylesheet", type: "text/css", href: "/css/selectize.bootstrap3.css"}/
-%script{type: "text/javascript", src: "https://maps.googleapis.com/maps/api/js?sensor=true&libraries=places,geometry&v=3.7"}
-
-/[if lt IE 9]
-%script{src: "/js/es5-shim.min.js"}
-
-.row
- .col-sm-8
- %h1
- Register for a Code Studio workshop (for teachers, grades K-5)
-
-#affiliate-workshop-signup-form-wrapper.row
- .col-sm-8
- -if (signup_count >= data['capacity_s'].to_i) || (first_date < Time.now)
- .alert.alert-danger{role: "alert"}
- This workshop is no longer accepting signups. Please choose another one or contact the facilitator (email below) to be notified when additional workshops are announced.
- %p Taught by Code.org Affiliates who are experienced computer science educators, our free workshops will prepare you to teach the Code Studio courses for grades K-5.
-
- .col-sm-6
- %h2 Workshop details
- .row
- .col-sm-4{style: "text-align: right;"} Date:
- .col-sm-8
- -data['dates'].each do |date|
- =date['date_s'] + ', ' + date['start_time_s'] + '-' + date['end_time_s']
- %br/
- .row
- .col-sm-4{style: "text-align: right;"} Location:
- .col-sm-8
- = data['location_name_s']
- - if data['location_address_s'] != data['location_name_s']
- %br/
- = data['location_address_s']
-
- -unless data['notes_s'].nil_or_empty?
- %p{style: "margin-top: 1em;"}= data['notes_s']
-
- -if (signup_count < data['capacity_s'].to_i) && (first_date >= Time.now)
- %form#affiliate-workshop-signup-form{role: "form", onsubmit: "event.preventDefault(); affiliateWorkshopSignupFormSubmit();"}
-
- %p.form-intro-text{style: "margin-top: 2em;"} Fields marked with a * are required. Your email address will be shared with the workshop facilitator.
- #error-message{style: 'display: none'}
-
- .main-section
- %h2 Your information
- .form-group
- %label.control-label{for: "workshop-signup-name"} Your Name
- %span.form-required-field *
- %div
- %input#workshop-signup-name.form-control{name: "name_s", placeholder: "Your name", type: "text", required: true}/
- .form-group
- %label.control-label{for: "workshop-signup-email"} Email address
- %span.form-required-field *
- %div
- %input#workshop-signup-email.form-control{name: "email_s", placeholder: "Email address", type: "email", required: true}/
- .form-group
- %label.control-label{for: "workshop-signup-email-confirm"} Confirm email address
- %span.form-required-field *
- %div
- %input#workshop-signup-email-confirm.form-control{name: "email_confirm_s", placeholder: "Email address", type: "email", required: true}/
-
- .form-group
- %label.control-label{for: "workshop-signup-teacher-role"} Role (select all that apply)
- %span.form-required-field *
- %div
- %select#workshop-signup-teacher-role.form-control{name: "teacher_role_ss[]", type: "select", required: true, multiple: true}
- %option{selected: true, value: ""}
- -ProfessionalDevelopmentWorkshopSignup.teacher_roles.each do |label|
- %option{value: label}= label
- %option#workshop-signup-teacher-role-other-option{value: 'Other'} Other (enter below)
- %div{id: 'workshop-signup-teacher-role-other-wrapper', style: 'display: none;'}
- %label.control-label{for: "workshop-signup-teacher-role-other"}<
- %em{style: 'font-weight: normal;'} Other role(s) (comma-separated)
- %span.form-required-field *
- %div
- %input#workshop-signup-teacher-role-other.form-control{name: "teacher_role_other_ss", placeholder: "Other role(s)", type: "text"}/
-
- .form-group
- %label.control-label{for: "workshop-signup-teacher-tech-experience-level"} Level of computer science experience (all levels are welcome!)
- %span.form-required-field *
- %div
- %select#workshop-signup-teacher-tech-experience-level.form-control{name: "teacher_tech_experience_level_s", type: "select", required: true}
- %option{selected: true, value: ""}
- -ProfessionalDevelopmentWorkshopSignup.teacher_tech_experience_levels.each do |level|
- %option{value: level}= level
-
- .main-section
- %h2 School information
- .form-group
- %label.control-label{for: "workshop-signup-school-name"} School name
- %span.form-required-field *
- %div
- %input#workshop-signup-school-name.form-control{name: "school_name_s", placeholder: "School name", type: "text", required: true}/
- .form-group
- %label.control-label{for: "workshop-signup-school-location"} School location
- %span.form-required-field *
- %div
- %input#workshop-signup-school-location.form-control{name: "school_location_s", placeholder: "Location", type: "text", required: true}/
- .form-group
- %label.control-label{for: "workshop-signup-school-type"} School type (select all that apply)
- %span.form-required-field *
- %div
- %select#workshop-signup-school-type.form-control{name: "school_type_ss[]", type: "select", required: true, multiple: true}
- %option{selected: true, value: ""}
- -ProfessionalDevelopmentWorkshopSignup.school_types.each do |label|
- %option{value: label}= label
- %option#workshop-signup-school-type-other-option{value: 'Other'} Other (enter below)
- %div{id: 'workshop-signup-school-type-other-wrapper', style: 'display: none;'}
- %label.control-label{for: "workshop-signup-school-type-other"}<
- %em{style: 'font-weight: normal;'} Other school type(s) (comma-separated)
- %span.form-required-field *
- %div
- %input#workshop-signup-school-type-other.form-control{name: "school_type_other_ss", placeholder: "Other school type(s)", type: "text"}/
- .form-group
- %label.control-label{for: "workshop-signup-school-district"} School district
- %div
- %input#workshop-signup-school-district.form-control{name: "school_district_s", placeholder: "School district", type: "text"}/
- .form-group
- %label.control-label{for: "workshop-signup-school-levels"} Grade you teach (select all that apply)
- %span.form-required-field *
- %div
- %select#workshop-signup-school-levels.form-control{name: "school_levels_ss[]", type: "select", required: true, multiple: true}
- %option{selected: true, value: ""}
- -ProfessionalDevelopmentWorkshopSignup.school_levels.each do |label|
- %option{value: label}= label
- %option#workshop-signup-school-levels-other-option{value: 'Other'} Other (enter below)
- %div{id: 'workshop-signup-school-levels-other-wrapper', style: 'display: none;'}
- %label.control-label{for: "workshop-signup-school-levels-other"}<
- %em{style: 'font-weight: normal;'} Other school level(s) (comma-separated)
- %span.form-required-field *
- %div
- %input#workshop-signup-school-levels-other.form-control{name: "school_levels_other_ss", placeholder: "Other school level(s)", type: "text"}/
- .form-group
- %label.control-label{for: "workshop-signup-number-students"} Number of students you teach
- %span.form-required-field *
- %div
- %input#workshop-signup-number-students.form-control{name: "number_students_s", placeholder: "Number of students", type: "text", required: true}/
-
- .form-group{style: 'margin-top: 45px;'}
- %button#btn-submit.btn.btn-default{type: "submit"} Submit
-
- -if File.file?(sites_v3_dir("code.org/views/workshop_affiliates/#{affiliate[:id]}_bio.md"))
- .col-sm-5.col-sm-offset-1
- %h2{style: "font-size: 18px;"} Facilitated by:
- -if File.file?(pegasus_dir("sites.v3/code.org/public/images/affiliate-images/#{affiliate[:id]}.jpg"))
- %img{src: "/images/affiliate-images/fit-180/#{affiliate[:id]}.jpg", style: "margin-bottom: .5em;"}
- %div
- =view "workshop_affiliates/#{affiliate[:id]}_bio"
-
--if (signup_count < data['capacity_s'].to_i) && (first_date >= Time.now)
- #thanks{:style=>"display: none;"}
- .row
- .col-sm-8
- :markdown
- Thank you for signing up to attend a Code.org K-5 workshop.
-
- **To prepare for your workshop:**
-
- Sign up for a [teacher account](http://learn.code.org/users/sign_up?user%5Buser_type%5D=teacher) at Code.org if you don’t already have one. Review the following [introductory course materials](http://code.org/educate/k5/introPD). These will give you a head start into the course materials to be covered and maximizing learning time during the in-person workshop.
-
- **IMPORTANT: Bring your own laptop:**
-
- This workshop requires you bring your own laptop. To teach the Code Studio courses in your school you will want to make sure your school’s tablets, laptop carts or computer lab support modern browsers. Review [this page](https://support.code.org/hc/en-us/articles/202591743-What-kind-of-operating-system-and-browser-do-I-need-to-use-Code-org-s-online-learning-system-) for more information regarding compatible operating systems and browsers.
-
- %h2 Workshop details
- .row
- .col-sm-4{style: "text-align: right;"} Date:
- .col-sm-8
- -data['dates'].each do |date|
- =date['date_s'] + ', ' + date['start_time_s'] + '-' + date['end_time_s']
- %br/
- .row
- .col-sm-4{style: "text-align: right;"} Location:
- .col-sm-8
- = data['location_name_s']
- - if data['location_address_s'] != data['location_name_s']
- %br/
- = data['location_address_s']
-
- .row
- .col-sm-4{style: "text-align: right;"} Workshop facilitator:
- .col-sm-8
- = affiliate.name
- %br/
- = affiliate.email
-
- -unless data['notes_s'].nil_or_empty?
- %p{style: "margin-top: 1em;"}= data['notes_s']
-
--if (signup_count < data['capacity_s'].to_i) && (first_date >= Time.now)
-
- :javascript
-
- $(document).ready(function() {
- $('#affiliate-workshop-signup-form select').selectize({
- plugins: ['fast_click']
- });
-
- var location_input = document.getElementById('workshop-signup-school-location');
- var location_autocomplete = new google.maps.places.SearchBox(location_input); // Google Maps autocomplete.
-
- $('#workshop-signup-school-type').change(function() {
- if ($.inArray('Other', $(this).val()) > -1) {
- $('#workshop-signup-school-type-other-wrapper').show();
- } else {
- $('#workshop-signup-school-type-other').val('');
- $('#workshop-signup-school-type-other-wrapper').hide();
- }
- }).triggerHandler('change');
-
- $('#workshop-signup-school-levels').change(function() {
- if ($.inArray('Other', $(this).val()) > -1) {
- $('#workshop-signup-school-levels-other-wrapper').show();
- } else {
- $('#workshop-signup-school-levels-other').val('');
- $('#workshop-signup-school-levels-other-wrapper').hide();
- }
- }).triggerHandler('change');
-
- $('#workshop-signup-teacher-role').change(function() {
- if ($.inArray('Other', $(this).val()) > -1) {
- $('#workshop-signup-teacher-role-other-wrapper').show();
- } else {
- $('#workshop-signup-teacher-role-other').val('');
- $('#workshop-signup-teacher-role-other-wrapper').hide();
- }
- }).triggerHandler('change');
- });
-
- function processResponse(data)
- {
- // Facebook Conversion Tracking Pixel script START
- (function() {
- var _fbq = window._fbq || (window._fbq = []);
- if (!_fbq.loaded) {
- var fbds = document.createElement('script');
- fbds.async = true;
- fbds.src = '//connect.facebook.net/en_US/fbds.js';
- var s = document.getElementsByTagName('script')[0];
- s.parentNode.insertBefore(fbds, s);
- _fbq.loaded = true;
- }
- })();
- window._fbq = window._fbq || [];
- window._fbq.push(['track', '6023436586161', {'value':'0.01','currency':'USD'}]);
- // Facebook Conversion Tracking Pixel script END
-
- $('#affiliate-workshop-signup-form-wrapper').hide();
- $('#thanks').show();
- }
-
- function processError(data)
- {
- $('.has-error').removeClass('has-error');
-
- var errors = data.responseJSON;
- var error_keys = Object.keys(errors);
- var errors_count = error_keys.length;
- var required_error = false;
- var error_messages = [];
-
- for (var i = 0; i < errors_count; i++) {
- var error_list = errors[error_keys[i]];
-
- if (error_list.indexOf('required') != -1) {
- required_error = true;
- }
-
- if (error_list.indexOf('mismatch') != -1) {
- error_messages.push('The email address fields do not match.');
- $('#workshop-signup-email-confirm').parents('.form-group').addClass('has-error');
- }
-
- error_id = '#workshop-signup-' + error_keys[i].replace(/_/g, '-');
- error_id = error_id.replace(/-[sb]s?$/, '');
- $(error_id).parents('.form-group').addClass('has-error');
- }
-
- if (required_error) {
- error_messages.push('At least one required field was left empty.');
- }
-
- if (error_messages.length > 0) {
- $('#error-message').html('
' + error_messages.join('
') + '
').show();
- }
-
- $('body').scrollTop(0);
- $("#btn-submit").removeAttr('disabled');
- $("#btn-submit").removeClass("button_disabled").addClass("button_enabled");
- }
-
- function affiliateWorkshopSignupFormSubmit()
- {
- $("#btn-submit").attr('disabled','disabled');
- $("#btn-submit").removeClass("button_enabled").addClass("button_disabled");
-
- $.ajax({
- url: "/forms/ProfessionalDevelopmentWorkshop/#{workshop_id}/children/ProfessionalDevelopmentWorkshopSignup",
- type: "post",
- dataType: "json",
- data: $('#affiliate-workshop-signup-form').serialize()
- }).done(processResponse).fail(processError);
-
- return false;
- }
diff --git a/pegasus/sites.v3/hourofcode.com/public/images/czechitas.png b/pegasus/sites.v3/hourofcode.com/public/images/czechitas.png
new file mode 100644
index 0000000000000..069ca6fcb961a
Binary files /dev/null and b/pegasus/sites.v3/hourofcode.com/public/images/czechitas.png differ
diff --git a/pegasus/sites.v3/hourofcode.com/public/images/iamai_academy.jpg b/pegasus/sites.v3/hourofcode.com/public/images/iamai_academy.jpg
new file mode 100644
index 0000000000000..bb04ab23ccc82
Binary files /dev/null and b/pegasus/sites.v3/hourofcode.com/public/images/iamai_academy.jpg differ
diff --git a/pegasus/sites.v3/hourofcode.com/public/images/korea_information_science_education_federation.png b/pegasus/sites.v3/hourofcode.com/public/images/korea_information_science_education_federation.png
new file mode 100644
index 0000000000000..9a8161e908749
Binary files /dev/null and b/pegasus/sites.v3/hourofcode.com/public/images/korea_information_science_education_federation.png differ
diff --git a/pegasus/sites.v3/hourofcode.com/public/images/sault_ste_marie_innovation_centre.jpg b/pegasus/sites.v3/hourofcode.com/public/images/sault_ste_marie_innovation_centre.jpg
new file mode 100644
index 0000000000000..f7d916992cd07
Binary files /dev/null and b/pegasus/sites.v3/hourofcode.com/public/images/sault_ste_marie_innovation_centre.jpg differ
diff --git a/pegasus/sites.v3/hourofcode.com/public/international-partners.md b/pegasus/sites.v3/hourofcode.com/public/international-partners.md
index 1611d11b0c866..11ebec29ab69d 100644
--- a/pegasus/sites.v3/hourofcode.com/public/international-partners.md
+++ b/pegasus/sites.v3/hourofcode.com/public/international-partners.md
@@ -81,6 +81,7 @@ You, too, can play a leading role to get more people in your country involved! I
| Portugal | Gabinete de Modernização das Tecnologias Educativas | Rodolfo Pinto | http://www02.madeira-edu.pt/dre/main.aspx |
| Romania | ADFABER | Alin Chiriac | alin@adfaber.org |
| Singapore | Infocomm Media Development Authority of Singapore | | https://www.imda.gov.sg/ |
+| South Korea | Korea Information Science Education Federation | | http://kcode.kr/ hwankim92@gmail.com |
| Spain | Acludi | Juana Martínez | www.acludi.blogspot.com acludi@yahoo.com |
| Spain | CSTA Spain | Santiago Fernández-Cabaleiro | www.aapri.es santiagocabaleiro@gmail.com |
| Spain | Informatics Faculty - University of the Basque Country (UPV/EHU) | Edurne Larraza Mendiluze | https://www.ehu.eus/en/web/informatika-fakultatea/home edurne.larraza@ehu.eus |
diff --git a/shared/middleware/files_api.rb b/shared/middleware/files_api.rb
index 6a8c5f8e7aadb..9dff70b138914 100644
--- a/shared/middleware/files_api.rb
+++ b/shared/middleware/files_api.rb
@@ -267,7 +267,7 @@ def put_file(endpoint, encrypted_channel_id, filename, body)
version_to_replace = params['version']
timestamp = params['firstSaveTimestamp']
tab_id = params['tabId']
- buckets.check_current_version(encrypted_channel_id, filename, version_to_replace, timestamp, tab_id)
+ buckets.check_current_version(encrypted_channel_id, filename, version_to_replace, timestamp, tab_id, current_user_id)
response = buckets.create_or_replace(encrypted_channel_id, filename, body, version_to_replace)
@@ -472,7 +472,7 @@ def copy_file(endpoint, encrypted_channel_id, filename, source_filename)
not_authorized unless owns_channel?(encrypted_channel_id)
- get_bucket_impl(endpoint).new.restore_previous_version(encrypted_channel_id, filename, request.GET['version']).to_json
+ get_bucket_impl(endpoint).new.restore_previous_version(encrypted_channel_id, filename, request.GET['version'], current_user_id).to_json
end
#
diff --git a/shared/middleware/helpers/bucket_helper.rb b/shared/middleware/helpers/bucket_helper.rb
index a8f6474206bdf..316a96603f20b 100644
--- a/shared/middleware/helpers/bucket_helper.rb
+++ b/shared/middleware/helpers/bucket_helper.rb
@@ -174,7 +174,7 @@ def create_or_replace(encrypted_channel_id, filename, body, version = nil, abuse
response
end
- def check_current_version(encrypted_channel_id, filename, version_to_replace, timestamp, tab_id)
+ def check_current_version(encrypted_channel_id, filename, version_to_replace, timestamp, tab_id, user_id)
return unless filename == 'main.json' && @bucket == CDO.sources_s3_bucket && version_to_replace
owner_id, channel_id = storage_decrypt_channel_id(encrypted_channel_id)
@@ -188,9 +188,11 @@ def check_current_version(encrypted_channel_id, filename, version_to_replace, ti
FirehoseClient.instance.put_record(
'analysis-events',
study: 'project-data-integrity',
+ study_group: 'v2',
event: 'replace-non-current-main-json',
project_id: encrypted_channel_id,
+ user_id: user_id,
data_json: {
replacedVersionId: version_to_replace,
@@ -260,7 +262,7 @@ def list_versions(encrypted_channel_id, filename)
# Copies the given version of the file to make it the current revision.
# (All intermediate versions are preserved.)
- def restore_previous_version(encrypted_channel_id, filename, version_id)
+ def restore_previous_version(encrypted_channel_id, filename, version_id, user_id)
owner_id, channel_id = storage_decrypt_channel_id(encrypted_channel_id)
key = s3_path owner_id, channel_id, filename
@@ -270,12 +272,14 @@ def restore_previous_version(encrypted_channel_id, filename, version_id)
FirehoseClient.instance.put_record(
'analysis-events',
study: 'project-data-integrity',
+ study_group: 'v2',
event: 'version-restored',
# Make it easy to limit our search to restores in the sources bucket for a certain project.
project_id: encrypted_channel_id,
data_string: @bucket,
+ user_id: user_id,
data_json: {
restoredVersionId: version_id,
newVersionId: response.version_id,