Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions sql/insights/create_questions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,126 @@ UPDATE questions SET dependency_response=(SELECT ARRAY_AGG(id) FROM response_cho
WHERE question_text=ANY(ARRAY['How noticeable do you think the effects of your difficulty sleeping are to other people?',
'How much does your difficulty sleeping interfere with the rest of your day? (e.g. daytime fatigue, mood, concentration, memory, mood, etc.)']);

-- jyfan 2016-10-31 strict alarm questions
INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 6:00 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 6:30 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 7:00 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 7:30 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 8:00 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 8:30 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 9:00 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 9:30 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO questions (question_text, lang, frequency, response_type, responses, dependency, ask_time, category)
VALUES (
'You could benefit from a consistent wake time. Set a recurring alarm for 10:00 AM? Existing alarms will be deleted.', -- text
'EN', -- lang
'trigger', -- frequency (note, trigger is currently not implemented in QuestionProcessor)
'choice', --response_type,
'{"Yes", "No", "No, this time doesn''t work"}', --text responses
null, -- dependency
'anytime', -- ask_time
'insight' --category
);

INSERT INTO response_choices (question_id, response_text)
(SELECT id, UNNEST(responses) FROM questions WHERE id IN (SELECT id FROM questions ORDER BY id DESC LIMIT 9));

UPDATE questions SET responses = S.texts, responses_ids = S.ids FROM (
SELECT question_id, ARRAY_AGG(id) AS ids, ARRAY_AGG(response_text) AS texts
FROM response_choices where question_id IN
(select id from questions order by id DESC LIMIT 9) GROUP BY question_id) AS S
WHERE questions.id = S.question_id;






Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public enum Category {
GOAL_SCHEDULE_THOUGHTS(33),
GOAL_SCREENS(34),
GOAL_WAKE_VARIANCE(35),
SLEEP_DEPRIVATION(36);
SLEEP_DEPRIVATION(36),
STRICT_ALARM(37);

private int value;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.hello.suripu.core.models.Insights;

import org.joda.time.DateTime;

/**
* Created by jyfan on 11/7/16.
*/
public class QuestionCard {
public Long accountId;
public Integer questionId;
public DateTime startDate;
public DateTime expireDate;

private QuestionCard(final Long accountId,
final Integer questionId,
final DateTime startDate,
final DateTime expireDate) {
this.accountId = accountId;
this.questionId = questionId;
this.startDate = startDate;
this.expireDate = expireDate;
}

public static QuestionCard createQuestionCard(final Long accountId,
final Integer questionId,
final DateTime startDate,
final DateTime expireDate) {
return new QuestionCard(accountId, questionId, startDate, expireDate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public enum QuestionCategory {
ANOMALY_LIGHT("anomaly_light"),
GOAL_GO_OUTSIDE("goal_go_outside"),
GOAL("goal"),
SURVEY("survey");
SURVEY("survey"),
INSIGHT("insight"); //paired with insight, should be 1st priority

private String value;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.hello.suripu.core.db.AccountReadDAO;
Expand All @@ -15,6 +16,8 @@
import com.hello.suripu.core.db.DeviceReadDAO;
import com.hello.suripu.core.db.InsightsDAODynamoDB;
import com.hello.suripu.core.db.MarketingInsightsSeenDAODynamoDB;
import com.hello.suripu.core.db.QuestionResponseDAO;
import com.hello.suripu.core.db.QuestionResponseReadDAO;
import com.hello.suripu.core.db.SleepStatsDAODynamoDB;
import com.hello.suripu.core.db.TrendsInsightsDAO;
import com.hello.suripu.core.flipper.FeatureFlipper;
Expand All @@ -24,6 +27,9 @@
import com.hello.suripu.core.models.Insights.InfoInsightCards;
import com.hello.suripu.core.models.Insights.InsightCard;
import com.hello.suripu.core.models.Insights.MarketingInsightsSeen;
import com.hello.suripu.core.models.Insights.QuestionCard;
import com.hello.suripu.core.models.Question;
import com.hello.suripu.core.models.Questions.QuestionCategory;
import com.hello.suripu.core.preferences.AccountPreferencesDAO;
import com.hello.suripu.core.preferences.PreferenceName;
import com.hello.suripu.core.preferences.TemperatureUnit;
Expand All @@ -42,6 +48,7 @@
import com.hello.suripu.core.processors.insights.SleepDeprivation;
import com.hello.suripu.core.processors.insights.SleepMotion;
import com.hello.suripu.core.processors.insights.SoundDisturbance;
import com.hello.suripu.core.processors.insights.StrictAlarm;
import com.hello.suripu.core.processors.insights.TemperatureHumidity;
import com.hello.suripu.core.processors.insights.WakeStdDevData;
import com.hello.suripu.core.processors.insights.WakeVariance;
Expand Down Expand Up @@ -99,6 +106,7 @@ public class InsightProcessor {
private final AccountReadDAO accountReadDAO;
private final CalibrationDAO calibrationDAO;
private final MarketingInsightsSeenDAODynamoDB marketingInsightsSeenDAODynamoDB;
private final QuestionResponseDAO questionResponseDAO;

private static final ImmutableSet<InsightCard.Category> marketingInsightPool = ImmutableSet.copyOf(Sets.newHashSet(InsightCard.Category.DRIVE,
InsightCard.Category.EAT,
Expand All @@ -109,6 +117,8 @@ public class InsightProcessor {
InsightCard.Category.SWIM,
InsightCard.Category.WORK));

private final Map<String, Integer> strictAlarmTextQidMap;

public InsightProcessor(@NotNull final DeviceDataDAODynamoDB deviceDataDAODynamoDB,
@NotNull final DeviceReadDAO deviceReadDAO,
@NotNull final TrendsInsightsDAO trendsInsightsDAO,
Expand All @@ -122,7 +132,9 @@ public InsightProcessor(@NotNull final DeviceDataDAODynamoDB deviceDataDAODynamo
@NotNull final LightData lightData,
@NotNull final WakeStdDevData wakeStdDevData,
@NotNull final CalibrationDAO calibrationDAO,
@NotNull final MarketingInsightsSeenDAODynamoDB marketingInsightsSeenDAODynamoDB
@NotNull final MarketingInsightsSeenDAODynamoDB marketingInsightsSeenDAODynamoDB,
@NotNull final QuestionResponseDAO questionResponseDAO,
@NotNull final Map<String, Integer> strictAlarmTextQidMap
) {
this.deviceDataDAODynamoDB = deviceDataDAODynamoDB;
this.deviceReadDAO = deviceReadDAO;
Expand All @@ -138,6 +150,8 @@ public InsightProcessor(@NotNull final DeviceDataDAODynamoDB deviceDataDAODynamo
this.accountReadDAO = accountReadDAO;
this.calibrationDAO = calibrationDAO;
this.marketingInsightsSeenDAODynamoDB = marketingInsightsSeenDAODynamoDB;
this.questionResponseDAO = questionResponseDAO;
this.strictAlarmTextQidMap = strictAlarmTextQidMap;
}

public void generateInsights(final Long accountId, final DateTime accountCreated, final RolloutClient featureFlipper) {
Expand Down Expand Up @@ -169,7 +183,7 @@ private Optional<InsightCard.Category> generateNewUserInsights(final Long accoun
if (featureFlipper.userFeatureActive(FeatureFlipper.INSIGHTS_LAST_SEEN, accountId, Collections.EMPTY_LIST)) {
final List<InsightsLastSeen> insightsLastSeenList = this.insightsLastSeenDAO.getAll(accountId);
recentCategories = InsightsLastSeen.getLastSeenInsights(insightsLastSeenList);
}else {
} else {
recentCategories = this.getRecentInsightsCategories(accountId);
}
return generateNewUserInsights(accountId, accountAge, recentCategories);
Expand Down Expand Up @@ -464,7 +478,10 @@ public Optional<InsightCard.Category> generateInsightsByCategory(final Long acco
final DateTimeFormatter timeFormat;
final TemperatureUnit tempUnit;

final DateTime queryEndDate = DateTime.now(DateTimeZone.UTC).withTimeAtStartOfDay();

Optional<InsightCard> insightCardOptional = Optional.absent();
Optional<QuestionCard> questionCardOptional = Optional.absent();
switch (category) {
case AIR_QUALITY:
insightCardOptional = Particulates.getInsights(accountId, deviceAccountPair, sleepStatsDAODynamoDB, deviceDataInsightQueryDAO, calibrationDAO);
Expand Down Expand Up @@ -538,6 +555,9 @@ public Optional<InsightCard.Category> generateInsightsByCategory(final Long acco
case SOUND:
insightCardOptional = SoundDisturbance.getInsights(accountId, deviceAccountPair, deviceDataDAODynamoDB, sleepStatsDAODynamoDB);
break;
case STRICT_ALARM:
questionCardOptional = StrictAlarm.getQuestion(sleepStatsDAODynamoDB, accountId, queryEndDate, DAYS_ONE_WEEK, strictAlarmTextQidMap);
break;
case SWIM:
insightCardOptional = MarketingInsights.getSwimInsight(accountId);
break;
Expand All @@ -546,7 +566,6 @@ public Optional<InsightCard.Category> generateInsightsByCategory(final Long acco
insightCardOptional = TemperatureHumidity.getInsights(accountId, deviceAccountPair, deviceDataInsightQueryDAO, tempUnit, sleepStatsDAODynamoDB);
break;
case WAKE_VARIANCE:
final DateTime queryEndDate = DateTime.now(DateTimeZone.UTC).withTimeAtStartOfDay();
insightCardOptional = WakeVariance.getInsights(sleepStatsDAODynamoDB, accountId, wakeStdDevData, queryEndDate, DAYS_ONE_WEEK);
break;
case WORK:
Expand All @@ -565,6 +584,15 @@ public Optional<InsightCard.Category> generateInsightsByCategory(final Long acco
final InsightsLastSeen newInsight = new InsightsLastSeen(accountId, insightCardOptional.get().category, DateTime.now(DateTimeZone.UTC));
this.insightsLastSeenDAO.markLastSeen(newInsight);
return Optional.of(category);

} else if (questionCardOptional.isPresent()) {
final QuestionCard questionCard = questionCardOptional.get();

//insert question to postgres
this.questionResponseDAO.insertAccountQuestion(questionCard.accountId, questionCard.questionId, questionCard.startDate, questionCard.expireDate);
final InsightsLastSeen newMockInsight = new InsightsLastSeen(accountId, category, DateTime.now(DateTimeZone.UTC));
this.insightsLastSeenDAO.markLastSeen(newMockInsight);
return Optional.of(category);
}

return Optional.absent();
Expand Down Expand Up @@ -664,6 +692,8 @@ public static class Builder {
private @Nullable AccountInfoProcessor accountInfoProcessor;
private @Nullable CalibrationDAO calibrationDAO;
private @Nullable MarketingInsightsSeenDAODynamoDB marketingInsightsSeenDAODynamoDB;
private @Nullable QuestionResponseDAO questionResponseDAO;
private @Nullable Map<String, Integer> strictAlarmTextQidMap;

public Builder withMarketingInsightsSeenDAO(final MarketingInsightsSeenDAODynamoDB marketingInsightsSeenDAO) {
this.marketingInsightsSeenDAODynamoDB = marketingInsightsSeenDAO;
Expand Down Expand Up @@ -719,6 +749,25 @@ public Builder withCalibrationDAO(final CalibrationDAO calibrationDAO) {
return this;
}

public Builder withQuestionResponseDAO(final QuestionResponseDAO questionResponseDAO) {
this.questionResponseDAO = questionResponseDAO;
return this;
}

public Builder withQuestions(final QuestionResponseDAO questionResponseDAO) {
this.strictAlarmTextQidMap = new HashMap<>();

final List<Question> allQuestions = questionResponseDAO.getAllQuestions();
for (final Question question : allQuestions) {
if (question.category != QuestionCategory.INSIGHT) {
continue;
}
this.strictAlarmTextQidMap.put(question.text, question.id);
}

return this;
}

public InsightProcessor build() {
checkNotNull(deviceReadDAO, "deviceReadDAO can not be null");
checkNotNull(trendsInsightsDAO, "trendsInsightsDAO can not be null");
Expand All @@ -733,8 +782,11 @@ public InsightProcessor build() {
checkNotNull(wakeStdDevData, "wakeStdDevData cannot be null");
checkNotNull(calibrationDAO, "calibrationDAO cannot be null");
checkNotNull(marketingInsightsSeenDAODynamoDB, "marketInsightsSeenDAO cannot be null");
checkNotNull(questionResponseDAO, "questionResponseDAO cannot be null");
checkNotNull(strictAlarmTextQidMap, "textQidMap cannot be null");

return new InsightProcessor(deviceDataDAODynamoDB,
return new InsightProcessor(
deviceDataDAODynamoDB,
deviceReadDAO,
trendsInsightsDAO,
scoreDAODynamoDB,
Expand All @@ -747,7 +799,9 @@ public InsightProcessor build() {
lightData,
wakeStdDevData,
calibrationDAO,
marketingInsightsSeenDAODynamoDB);
marketingInsightsSeenDAODynamoDB,
questionResponseDAO,
strictAlarmTextQidMap);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ public List<Question> getSurveyQuestions(final Long accountId, final DateTime to
/*
Insert questions
*/

private void saveQuestion(final Long accountId, final Question question, final DateTime todayLocal, final DateTime expireDate) {
LOGGER.debug("action=saved_question processor=question_survey account_id={} question_id={} today_local={} expire_date={}", accountId, question.id, todayLocal, expireDate);
this.questionResponseDAO.insertAccountQuestion(accountId, question.id, todayLocal, expireDate);
Expand Down
Loading