1# -*- coding: utf-8 -*- # 2# Copyright 2018 Google LLC. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""This module manages the survey prompting.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import unicode_literals 20 21import time 22 23from googlecloudsdk.core import config 24from googlecloudsdk.core import log 25from googlecloudsdk.core import yaml 26from googlecloudsdk.core.util import files as file_utils 27from googlecloudsdk.core.util import prompt_helper 28 29SURVEY_PROMPT_INTERVAL = 86400 * 14 # 14 days 30SURVEY_PROMPT_INTERVAL_AFTER_ANSWERED = 86400 * 30 * 3 # 90 days 31 32 33class PromptRecord(prompt_helper.PromptRecordBase): 34 """The survey prompt record. 35 36 Attributes: 37 _cache_file_path: cache file path. 38 last_answer_survey_time: the time user most recently answered the survey 39 (epoch time). 40 last_prompt_time: the time when user is most recently prompted (epoch time). 41 dirty: bool, True if record in the cache file should be updated. Otherwise, 42 False. 43 """ 44 45 def __init__(self): 46 super(PromptRecord, self).__init__( 47 cache_file_path=config.Paths().survey_prompting_cache_path) 48 self._last_prompt_time, self._last_answer_survey_time = ( 49 self.ReadPromptRecordFromFile()) 50 51 def ReadPromptRecordFromFile(self): 52 """Loads the prompt record from the cache file. 53 54 Returns: 55 Two-value tuple (last_prompt_time, last_answer_survey_time) 56 """ 57 if not self.CacheFileExists(): 58 return None, None 59 60 try: 61 with file_utils.FileReader(self._cache_file_path) as f: 62 data = yaml.load(f) 63 return (data.get('last_prompt_time', None), 64 data.get('last_answer_survey_time', None)) 65 except Exception: # pylint:disable=broad-except 66 log.debug('Failed to parse survey prompt cache. ' 67 'Using empty cache instead.') 68 return None, None 69 70 def _ToDictionary(self): 71 res = {} 72 if self._last_prompt_time is not None: 73 res['last_prompt_time'] = self._last_prompt_time 74 if self._last_answer_survey_time is not None: 75 res['last_answer_survey_time'] = self._last_answer_survey_time 76 return res 77 78 @property 79 def last_answer_survey_time(self): 80 return self._last_answer_survey_time 81 82 @last_answer_survey_time.setter 83 def last_answer_survey_time(self, value): 84 self._last_answer_survey_time = value 85 self._dirty = True 86 87 88class SurveyPrompter(prompt_helper.BasePrompter): 89 """Manages prompting user for survey. 90 91 Attributes: 92 _prompt_record: PromptRecord, the record of the survey prompt history. 93 _prompt_message: str, the prompting message. 94 """ 95 _DEFAULT_SURVEY_PROMPT_MSG = ('To take a quick anonymous survey, run:\n' 96 ' $ gcloud survey') 97 98 def __init__(self, msg=_DEFAULT_SURVEY_PROMPT_MSG): 99 self._prompt_record = PromptRecord() 100 self._prompt_message = msg 101 102 def PrintPromptMsg(self): 103 log.status.write('\n\n' + self._prompt_message + '\n\n') 104 105 def ShouldPrompt(self): 106 """Check if the user should be prompted.""" 107 if not (log.out.isatty() and log.err.isatty()): 108 return False 109 110 last_prompt_time = self._prompt_record.last_prompt_time 111 last_answer_survey_time = self._prompt_record.last_answer_survey_time 112 now = time.time() 113 if last_prompt_time and (now - last_prompt_time) < SURVEY_PROMPT_INTERVAL: 114 return False 115 if last_answer_survey_time and (now - last_answer_survey_time < 116 SURVEY_PROMPT_INTERVAL_AFTER_ANSWERED): 117 return False 118 return True 119 120 def Prompt(self): 121 """Prompts user for survey if user should be prompted.""" 122 # Don't prompt users right after users install gcloud. Wait for 14 days. 123 if not self._prompt_record.CacheFileExists(): 124 with self._prompt_record as pr: 125 pr.last_prompt_time = time.time() 126 return 127 128 if self.ShouldPrompt(): 129 self.PrintPromptMsg() 130 with self._prompt_record as pr: 131 pr.last_prompt_time = time.time() 132