Skip to content

Commit

Permalink
Merge pull request #13965 from code-dot-org/staging
Browse files Browse the repository at this point in the history
  • Loading branch information
ewjordan committed Mar 23, 2017
2 parents d0bac56 + 305300b commit 71f8739
Show file tree
Hide file tree
Showing 225 changed files with 3,114 additions and 538 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,4 @@ gem 'octokit'
gem 'full-name-splitter', github: 'pahanix/full-name-splitter'
gem 'rambling-trie'

gem 'omniauth-openid-connect'
gem 'omniauth-openid-connect', github: 'wjordan/omniauth-openid-connect', ref: 'cdo'
20 changes: 13 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ GIT
builder
oauth (>= 0.4.5, < 0.6)

GIT
remote: https://github.com/wjordan/omniauth-openid-connect.git
revision: 2397b1415896e2639a7582a36e26c90b9211f99f
ref: cdo
specs:
omniauth-openid-connect (0.2.2)
addressable (~> 2.3)
omniauth (~> 1.1)
openid_connect (~> 1.0, >= 1.0.3)

GIT
remote: https://github.com/wjordan/omniauth-windowslive.git
revision: 68ece379fa4d79a49505454c52aaf9142cd2ed74
Expand Down Expand Up @@ -415,17 +425,13 @@ GEM
omniauth-oauth2 (1.4.0)
oauth2 (~> 1.0)
omniauth (~> 1.2)
omniauth-openid-connect (0.2.3)
addressable (~> 2.3)
omniauth (~> 1.1)
openid_connect (~> 0.9.2)
open_uri_redirections (0.2.1)
openid_connect (0.9.2)
openid_connect (1.0.3)
activemodel
attr_required (>= 1.0.0)
json (>= 1.4.3)
json-jwt (>= 1.5.0)
rack-oauth2 (>= 1.2.1)
rack-oauth2 (>= 1.3.1)
swd (>= 1.0.0)
tzinfo
validate_email
Expand Down Expand Up @@ -747,7 +753,7 @@ DEPENDENCIES
omniauth-clever (~> 1.2.1)!
omniauth-facebook (~> 4.0.0.rc1)
omniauth-google-oauth2 (~> 0.3.1)
omniauth-openid-connect
omniauth-openid-connect!
omniauth-windowslive (~> 0.0.11)!
open_uri_redirections
os
Expand Down
85 changes: 65 additions & 20 deletions apps/src/lib/util/firehose.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,13 @@

import AWS from 'aws-sdk';

const IDENTITY_POOL_ID = 'us-east-1:fbfec393-0afb-4682-84d4-59ad04a302f4';
const AWS_REGION = 'us-east-1';

AWS.config.region = AWS_REGION;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: IDENTITY_POOL_ID,
});
const FIREHOSE = new AWS.Firehose({apiVersion: '2015-08-04'});

/**
* A barebones client for posting data to an AWS Firehose stream.
* Usage:
* FirehoseClient.putRecord(
* firehoseClient.putRecord(
* 'analysis-events',
* {
* created_at: new Date(), // REQUIRED
* created_at: new Date().toISOString(), // REQUIRED
* environment: 'production', // REQUIRED
* study: 'underwater basket weaving', // REQUIRED
* study_group: 'control', // OPTIONAL
Expand All @@ -33,11 +24,11 @@ const FIREHOSE = new AWS.Firehose({apiVersion: '2015-08-04'});
* }
* );
* Usage:
* FirehoseClient.putRecordBatch(
* firehoseClient.putRecordBatch(
* 'analysis-events',
* [
* {
* created_at: new Date(), // REQUIRED
* created_at: new Date().toISOString(), // REQUIRED
* environment: 'production', // REQUIRED
* study: 'underwater basket weaving', // REQUIRED
* study_group: 'control', // OPTIONAL
Expand All @@ -52,7 +43,7 @@ const FIREHOSE = new AWS.Firehose({apiVersion: '2015-08-04'});
* data_json: JSON.stringify(x) // OPTIONAL
* },
* {
* created_at: new Date(), // REQUIRED
* created_at: new Date().toISOString(), // REQUIRED
* environment: 'production', // REQUIRED
* study: 'underwater basket weaving', // REQUIRED
* study_group: 'control', // OPTIONAL
Expand All @@ -71,13 +62,45 @@ const FIREHOSE = new AWS.Firehose({apiVersion: '2015-08-04'});
*/
// TODO(asher): Add the ability to queue records individually, to be submitted
// as a batch.
export default class FirehoseClient {
class FirehoseClient {
isTestEnvironment() {
if (window && window.location) {
const hostname = window.location.hostname;
if ("test.code.org" === hostname || "test-studio.code.org" === hostname) {
return true;
}
}
return false;
}

isDevelopmentEnvironment() {
if (window && window.location) {
const hostname = window.location.hostname;
if (hostname.includes("localhost")) {
return true;
}
}
return false;
}

shouldSendAnalytics() {
return !(this.isTestEnvironment() || this.isDevelopmentEnvironment());
}

/**
* Pushes one data record into the delivery stream.
* @param {string} deliveryStreamName The name of the delivery stream.
* @param {hash} data The data to push.
* @param {boolean} alwaysSendAnalytics Force analytics to be sent even in development/test (default false)
*/
putRecord(deliveryStreamName, data) {
putRecord(deliveryStreamName, data, alwaysSendAnalytics = false) {
if (!alwaysSendAnalytics && !this.shouldSendAnalytics()) {
console.groupCollapsed("Skipped sending analytics event to " + deliveryStreamName+ " in development/test: " + data.event);
console.log(data);
console.groupEnd();
return;
}

FIREHOSE.putRecord(
{
DeliveryStreamName: deliveryStreamName,
Expand All @@ -99,14 +122,28 @@ export default class FirehoseClient {
* Pushes an array of data records into the delivery stream.
* @param {string} deliveryStreamName The name of the delivery stream.
* @param {array[hash]} data The data to push.
* @param {boolean} alwaysSendAnalytics Force analytics to be sent even in development/test (default false)
*/
putRecordBatch(deliveryStreamName, data) {
putRecordBatch(deliveryStreamName, data, alwaysSendAnalytics = false) {
if (!alwaysSendAnalytics && !this.shouldSendAnalytics()) {
console.groupCollapsed("Skipped sending analytics event batch to " + deliveryStreamName + " in development/test");
data.map(function (record) {
console.log(record);
});
console.groupEnd();
return;
}

const batch = data.map(function (record) {
return {
Data: JSON.stringify(record)
};
});

FIREHOSE.putRecordBatch(
{
DeliveryStreamName: deliveryStreamName,
Records: {
Data: data.map(JSON.stringify),
},
Records: batch
},
function (err, data) {
if (err) {
Expand All @@ -118,3 +155,11 @@ export default class FirehoseClient {
);
}
}

// This obfuscated code sets up AWS config (against a very restricted user, so this is not a
// security concern, we just don't want to make the credentials super obvious
// eslint-disable-next-line
const _0x12ed=['\x41\x4b\x49\x41\x4a\x41\x41\x4d\x42\x59\x4d\x36\x55\x53\x59\x54\x34\x35\x34\x51','\x78\x4e\x4e\x39\x4e\x79\x32\x61\x6d\x39\x78\x75\x4b\x79\x57\x39\x53\x2b\x4e\x76\x41\x77\x33\x67\x68\x68\x74\x68\x72\x6b\x37\x6b\x6e\x51\x59\x54\x77\x6d\x4d\x48','\x75\x73\x2d\x65\x61\x73\x74\x2d\x31','\x63\x6f\x6e\x66\x69\x67'];(function(_0xb54a92,_0x4e682a){var _0x44f3e8=function(_0x35c55a){while(--_0x35c55a){_0xb54a92['\x70\x75\x73\x68'](_0xb54a92['\x73\x68\x69\x66\x74']());}};_0x44f3e8(++_0x4e682a);}(_0x12ed,0x127));var _0xd12e=function(_0x2cedd5,_0x518781){_0x2cedd5=_0x2cedd5-0x0;var _0x4291ea=_0x12ed[_0x2cedd5];return _0x4291ea;};AWS[_0xd12e('0x0')]=new AWS['\x43\x6f\x6e\x66\x69\x67']({'\x61\x63\x63\x65\x73\x73\x4b\x65\x79\x49\x64':_0xd12e('0x1'),'\x73\x65\x63\x72\x65\x74\x41\x63\x63\x65\x73\x73\x4b\x65\x79':_0xd12e('0x2'),'\x72\x65\x67\x69\x6f\x6e':_0xd12e('0x3')});
const FIREHOSE = new AWS.Firehose({apiVersion: '2015-08-04'});
const firehoseClient = new FirehoseClient();
export default firehoseClient;
118 changes: 116 additions & 2 deletions apps/src/sites/studio/pages/signup.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import $ from 'jquery';
import experiments from '@cdo/apps/util/experiments';
import firehoseClient from '@cdo/apps/lib/util/firehose';
import {createUuid, trySetLocalStorage} from '@cdo/apps/utils';

window.SignupManager = function (options) {
this.options = options;
var self = this;
var lastUserType = "";

// Check for URL having: /users/sign_up?user%5Buser_type%5D=teacher
if (self.options.isTeacher === "true") {
Expand All @@ -22,6 +25,7 @@ window.SignupManager = function (options) {
} else {
url = "/";
}
logFormSuccess();
window.location.href = url;
}

Expand All @@ -45,6 +49,7 @@ window.SignupManager = function (options) {
errorField.fadeTo("normal", 1);
}
}
logFormError(err);
}

$("#user_user_type").change(function () {
Expand Down Expand Up @@ -99,6 +104,9 @@ window.SignupManager = function (options) {

// Implicitly accept terms of service for students.
$("#user_terms_of_service_version").prop('checked', true);

logTeacherToggle(false);
lastUserType = "student";
}

function showTeacher() {
Expand All @@ -115,18 +123,122 @@ window.SignupManager = function (options) {

// Force teachers to explicitly accept terms of service.
$("#user_terms_of_service_version").prop('checked', false);

logTeacherToggle(true);
lastUserType = "teacher";
}

function getEnvironment() {
const hostname = window.location.hostname;
if (hostname.includes("adhoc")) {
// check first for adhoc, since hostnames might include other keywords
return "adhoc";
}
if (hostname.includes("test")) {
return "test";
}
if (hostname.includes("staging")) {
return "staging";
}
if (hostname.includes("levelbuilder")) {
return "levelbuilder";
}
if (hostname.includes("localhost")) {
return "development";
}
if (hostname.includes("code.org")) {
return "production";
}
return "unknown";
}

/**
* Log signup-related analytics events to Firehose
* @param eventName name of the event to log
* @param extraData optional hash object for supplemental data (will show up in the data_json field)
*/
function logAnalyticsEvent(eventName, extraData = {}) {
if (!self.uuid) {
if (!!window.localStorage && !!window.localStorage.getItem("analyticsID")) {
self.uuid = window.localStorage.getItem("analyticsID");
} else {
self.uuid = createUuid();
trySetLocalStorage("analyticsID", self.uuid);
}
}

const streamName = "analysis-events";
const environment = getEnvironment();
const study = "signup_school_dropdown";
const studyGroup = shouldShowSchoolDropdown() ? "show_school_dropdown" : "control";

let dataJson = {
user_agent: window.navigator.userAgent,
window_width: window.innerWidth,
window_height: window.innerHeight,
hostname: window.location.hostname,
full_path: window.location.href
};
Object.assign(dataJson, extraData);
if (!!window.optimizely) {
const optimizelyData = {
optimizely_data: window.optimizely.data.state
};
Object.assign(dataJson, optimizelyData);
}

firehoseClient.putRecord(
streamName,
{
created_at: new Date().toISOString(),
environment: environment,
study: study,
study_group: studyGroup,
event: eventName,
uuid: self.uuid,
data_json: JSON.stringify(dataJson),
}
);
}

function logTeacherToggle(isTeacher) {
let event;
// We track change events separately depending on whether they're initial selections or changes
if (lastUserType === "") {
event = isTeacher ? "select_teacher" : "select_student";
} else {
event = isTeacher ? "select_teacher_from_student" : "select_student_from_teacher";
}
logAnalyticsEvent(event);
}

function logFormSubmitted() {
const event = isTeacherSelected() ? "submit_teacher" : "submit_student";
logAnalyticsEvent(event);
}

function logFormError(err) {
const event = isTeacherSelected() ? "submit_error_teacher" : "submit_error_student";
logAnalyticsEvent(event, {error_info: err});
}

function logFormSuccess() {
const event = isTeacherSelected() ? "submit_success_teacher" : "submit_success_student";
logAnalyticsEvent(event);
}

function isTeacherSelected() {
var formData = $('#new_user').serializeArray();
var userType = $.grep(formData, e => e.name === "user[user_type]");
const formData = $('#new_user').serializeArray();
const userType = $.grep(formData, e => e.name === "user[user_type]");
if (userType.length === 1 && userType[0].value === "teacher") {
return true;
}
return false;
}

$(".signupform").submit(function () {
logFormSubmitted();

// Clear the prior hashed email.
$('#user_hashed_email').val('');

Expand Down Expand Up @@ -195,4 +307,6 @@ window.SignupManager = function (options) {
$("#user_name").placeholder();
$("#user_email").placeholder();
$("#user_school").placeholder();

logAnalyticsEvent("page_load");
};
13 changes: 8 additions & 5 deletions bin/oneoff/data_fix/survey_results_remove_year
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ PREFIX_TO_REMOVE = 'survey2016_'.freeze
SurveyResult.
where(kind: SurveyResult::DIVERSITY_2016).
find_each do |survey_result|
# The keys to transform are in the properties column, so extract them from the
# JSON.
# The keys to transform are stored in the properties hash.
properties = survey_result.properties
transformed_properties = {}
survey_result.properties.each do |key, value|
raise unless key.start_with? PREFIX_TO_REMOVE
properties.each do |key, value|
unless key.start_with? PREFIX_TO_REMOVE
raise "Found unexpected key: (#{key}, #{value}) in #{survey_result.id}."
end
transformed_properties[key.gsub(PREFIX_TO_REMOVE, '')] = value
end
survey_result.update!(properties: transformed_properties)
survey_result.properties = transformed_properties
survey_result.save!
end

0 comments on commit 71f8739

Please sign in to comment.