def __init__(self): self.api_client = ApiClient() self.api_headers = { 'Accept': 'application/json', 'Authorization': self.get_auth_value() } self.zipcode_re = re.compile(r'^tacome\s+(\d{5})\s*$')
def test_catme_invoke_calls_api_client_fetch_text_is_none(): api_client = ApiClient() api_client.fetch = MagicMock(return_value=[{"name": "foo"}]) catme = CatMe() catme.api_client = api_client text, attachments = catme.invoke("catme", "fakeuser") assert text is None
def test_action_telljoke_calls_api_client_fetch(): joke = 'ha ha, great joke!' cc_bot = CCBot() api_client = ApiClient() api_client.fetch_raw = MagicMock(return_value=joke) cc_bot.api_client = api_client response = cc_bot.action_telljoke(None) assert response == joke
def test_goatme_invoke_calls_api_client_fetch_returns_url_from_link_if_no_images_array( ): api_client = ApiClient() api_client.fetch = MagicMock(return_value={'data': [{'link': 'test_url'}]}) goat_me = GoatMe() goat_me.imgur_key = "fake_imgur_key" goat_me.api_client = api_client text, attachments = goat_me.invoke("goatme", "fakeuser") assert attachments == [{'image_url': 'test_url', 'title': 'test_url'}]
def test_catme_invoke_calls_api_client_fetch_returns_edgecats_url(): api_client = ApiClient() api_client.fetch = MagicMock(return_value=[{"name": "foo"}]) catme = CatMe() catme.api_client = api_client text, attachments = catme.invoke("catme", "fakeuser") assert attachments == [{ "title": "http://edgecats.net/cats/foo", "image_url": "http://edgecats.net/cats/foo" }]
def __init__(self, command_name, search_term): """ Creates a Tenor ccbot command named command_name Args: command_name: The command name. This will be the utterance invoking the command. search_term: The text to search against the Tenor web service. Note that you should url encode any spaces or special characters. For example 'dr.+who' not 'dr. who' """ BotCommand.__init__(self, command_name, 'all') self.search_term = search_term self.api_client = ApiClient()
def change_password(): try: token = auth.get_id_token() passwords = ApiClient(auth.get_oauth_session(), app) passwords.change_password(token['sub'], request.form.get('oldPassword'), request.form.get('password')) flash('Password was successfully changed to a new one.', 'success') return redirect(url_for('index')) except HTTPError as error: log_error( 'Could not change password for the current user because of: ', error) return render_template('change_password.html')
class Xkcd: """ xkcd [<id>|latest] Options: <id>: Shows specific comic strip by numeric id. Example: `xkcd 221` latest: Shows latest comic. Example: `xkcd latest` """ api_client = None def __init__(self): self.api_client = ApiClient() def get_channel_id(self): return "all" def fetch_info(self, comic_id=None): url = "https://xkcd.com/info.0.json" if comic_id is None else "https://xkcd.com/" + str( comic_id) + "/info.0.json" data = self.api_client.fetch(url) return data def invoke(self, input, user): info = self.fetch_info() last_comic_id = info["num"] command, args = self.parse_command(input) comic_id = None if (len(args) > 0): command = str(args[0]) if command.isalpha() and command == "latest": comic_id = last_comic_id else: comic_id = args[0] random_comic = comic_id if comic_id is not None else random.randint( 0, last_comic_id) comic_data = self.fetch_info(random_comic) return SlackResponse.attachment(title=comic_data["title"], text=comic_data["alt"], image_url=comic_data["img"]) def get_command(self): return "xkcd" def parse_command(self, command): parts = command.split(' ') size = len(parts) command = parts[0] if size > 0 else None count = 1 args = [] while (count < size): argument = parts[count].strip() if not argument is '': args.append(argument) count = count + 1 return command, args
def test_goatme_invoke_calls_api_client_fetch_if_greater_than_30_minutes(): #arrange id = uuid.uuid1() api_client = ApiClient() api_client.fetch = MagicMock(return_value={'data': [{'link': id}]}) goat_me = GoatMe() goat_me.imgur_key = "fake_imgur_key" goat_me.api_client = api_client #act text, attachments = goat_me.invoke("goatme", "fakeuser") #assert assert attachments == [{'image_url': id, 'title': id}] target = datetime.datetime.now() + datetime.timedelta( minutes=40) #change datetime to 12 minutes from now with mock_datetime(target, datetime): new_id = uuid.uuid1() api_client.fetch = MagicMock(return_value={'data': [{'link': new_id}]}) text, attachments = goat_me.invoke("goatme", "fakeuser") assert attachments != [{'image_url': id, 'title': id}] assert attachments == [{'image_url': new_id, 'title': new_id}]
class TenorCommand(BotCommand): BASE_URL = 'https://api.tenor.com/v1/search?media_filter=minimal&q=' api_client = None def __init__(self, command_name, search_term): """ Creates a Tenor ccbot command named command_name Args: command_name: The command name. This will be the utterance invoking the command. search_term: The text to search against the Tenor web service. Note that you should url encode any spaces or special characters. For example 'dr.+who' not 'dr. who' """ BotCommand.__init__(self, command_name, 'all') self.search_term = search_term self.api_client = ApiClient() def get_data(self): return self.api_client.fetch(self.get_search_url() , {'Content-Type': 'application/json', 'Accept': 'application/json'}) def get_search_url(self): return self.BASE_URL + self.search_term def invoke(self, command, user): data = self.get_data() if data is None or data['results'] is None or len(data['results']) < 1: return SlackResponse.text('No results for ' + self.search_term) item = random.choice(data['results']) return TenorCommand.create_slack_response(item) @staticmethod def create_slack_response(item): return SlackResponse.attachment(title='Here you go:', image_url=item['media'][0]['gif']['url'], author_link=item['url'], author_name='Via Tenor' )
class CatMe: url = "https://api.github.com/repos/flores/moarcats/contents/cats?ref=master" api_client = None def __init__(self): self.api_client = ApiClient() def get_channel_id(self): return "all" @timed_memoize(minutes=30) def get_data(self): return self.api_client.fetch(self.url) def invoke(self, command, user): data = self.get_data() image = random.choice(data).get("name","") image_url = "http://edgecats.net/cats/" + image return SlackResponse.attachment(title=image_url,image_url= image_url) def get_command(self): return "catme"
class EarthMe: api_client = None def __init__(self): self.api_client = ApiClient() def get_info(self): data = self.api_client.fetch( "https://epic.gsfc.nasa.gov/api/images.php") image_data = random.choice(data) return image_data def get_channel_id(self): return "all" def get_data(self): image_data = self.get_info() return (image_data.get('image', None), str(image_data['centroid_coordinates']['lat']), str(image_data['centroid_coordinates']['lon']), image_data['caption'], image_data['date']) def invoke(self, command, user): image, lat, lng, caption, date = self.get_data() image_url = "https://epic.gsfc.nasa.gov/epic-archive/jpg/" + image + ".jpg" maps_url = "https://www.google.com/maps/@" + lat + "," + lng + ",6z" pretext = caption text = "Taken on " + date author_name = lat + " " + lng + " (location map)" author_link = maps_url return SlackResponse.attachment(pretext=pretext, text=text, image_url=image_url, author_name=author_name, author_link=author_link) def get_command(self): return "earthme"
def __init__(self): self.api_client = ApiClient() self.api_headers = { 'Accept': 'application/json', 'x-token': os.environ.get('SLACK_CODE_CAMP_BOT_CODECAMP_API_TOKEN') }
class CampMe: """ CampMe [verb] [value] Options: now: Shows sessions going on now next: Shows sessions starting next time slot speaker [speaker name]: Shows sessions by stated speaker `campme speaker Marcel Marceau` shows sessions by Marcel Marceau. sessions at [HH:mm]: Shows sessions occuring at the said time slot. The time specifier should be 24 hour notation (millitary time) and must match session start time. """ api_client = None USAGE_TEXT = 'Try: `campme next` or `campme now` or `campme speaker Bob Bobbernaugh`, or `campme sessions at 14:15` .' MANUAL = 'Help for the Code Camp Bot\n\n* `campme next` shows sessions starting next time slot.\n* `campme now` shows sessions in progress.\n* `campme speaker Marcel Marceau` shows sessions by the specified speakr. You may use first or last name only or both.\n* `campme sessions at 16:00` will return sessions starting at 4PM today. Use 24 hour clock 13:00 is 1PM, 14:00 is 2PM etc.' URL = "https://www.socalcodecamp.com/v1/schedule/sessions" NO_MATCHES_FOUND = '¯\\_(ツ)_/¯ No sessions matching criteria' def __init__(self): self.api_client = ApiClient() self.api_headers = { 'Accept': 'application/json', 'x-token': os.environ.get('SLACK_CODE_CAMP_BOT_CODECAMP_API_TOKEN') } def get_verb(self, command): parts = command.split() return parts[1:] if len(parts) > 1 else None @timed_memoize(minutes=30) def get_data(self, url): return self.api_client.fetch(url, headers=self.api_headers) def invoke(self, command, user): verb = self.get_verb(command) if (verb is None): return SlackResponse.text(self.USAGE_TEXT) if (verb[0] == 'help' or verb[0] == '?'): return SlackResponse.text(self.MANUAL) try: result = self.get_data(self.URL) except HTTPError as he: return SlackResponse.text(str(he)) except URLError as ue: return SlackResponse.text(str(ue.args)) return self.create_slack_response(result, verb) @staticmethod def create_slack_response(api_response, verb): if (len(api_response) == 0): return SlackResponse.text('Server returned no data ¯\\_(ツ)_/¯') subset = CampMe.filter_items(api_response, verb) formatted = CampMe.format_text(subset, verb[0] == 'speaker') return SlackResponse.attachment( title=verb, text=formatted, author_name='Code Camp Bot', author_link='https://www.socalcodecamp.com/schedule.aspx') @staticmethod def filter_items(items, verb): if (verb[0] == 'now'): return [v for v in items if CampMe.is_now(v)] if (verb[0] == 'next'): return [v for v in items if CampMe.is_next(v)] if (verb[0] == 'speaker' and len(verb) > 1): regex = CampMe.build_regex(verb[1:]) return [v for v in items if CampMe.is_by_speaker(v, regex)] if (verb[0] == 'sessions' and verb[1] == 'at' and len(verb) > 2): return [ v for v in items if CampMe.is_at_time(v, verb[2], datetime.now()) ] return items @staticmethod def is_now(session): starts = datetime.strptime(session.get('SessionStart'), "%Y-%m-%dT%H:%M:%S") ends = datetime.strptime(session.get('SessionEnd'), "%Y-%m-%dT%H:%M:%S") now = datetime.now() return now >= starts and now < ends @staticmethod def is_next(session): starts = datetime.strptime(session.get('SessionStart'), "%Y-%m-%dT%H:%M:%S") now = datetime.now() return starts > now and starts < now + timedelta(hours=1, minutes=15) @staticmethod def build_regex(name_parts): pattern = '(\\b' pattern += '\\b|\\b'.join(name_parts) pattern += '\\b)' return re.compile(pattern, re.IGNORECASE) @staticmethod def is_by_speaker(session, regex): return (regex.search(session['SpeakerFirstName']) != None or regex.search(session['SpeakerLastName']) != None) @staticmethod def is_at_time(session, stated_time, clock): session_dt = datetime.strptime(session.get('SessionStart'), "%Y-%m-%dT%H:%M:%S") stated_dt = datetime.strptime(stated_time, "%H:%M") return (session_dt.hour == stated_dt.hour and session_dt.minute == stated_dt.minute and session_dt.day == clock.day) @staticmethod def nice(time_string): parsed = datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S") return parsed.strftime('%a %H:%M') @staticmethod def format_text(items, is_by_speaker=False): result = '' if items is None or len(items) == 0: return CampMe.NO_MATCHES_FOUND # u'Room' (98644544):u'SLH 102' # u'SessionEnd' (98644880):u'2018-11-11T11:15:00' # u'SessionId' (98644352):u'a83dca4a-06f8-48b6-a398-e857c74d6a30' # u'SessionName' (96970048):u'How to Ace Technical Interviews' # u'SessionStart' (98644304):u'2018-11-11T10:15:00' # u'SpeakerFirstName' (98639808):u'Abhi' # u'SpeakerLastName' (98639664):u'Jain' isfirst = True for item in items: if (isfirst and not is_by_speaker): result += ('%s - %s\n================\n' % (CampMe.nice(item.get('SessionStart')), CampMe.nice(item.get('SessionEnd')))) isfirst = False result = result + ( '* %s %s: %s @ %s %s\n' % (item.get('SpeakerFirstName'), item.get('SpeakerLastName'), item.get('SessionName'), item.get('Room'), CampMe.nice(item.get('SessionStart')) if is_by_speaker else '')) return result def get_command(self): return "campme" def get_channel_id(self): return "all"
class TacoMe: url = "https://api.yelp.com/v3/businesses/search?term=taco&sort_by=distance&categories=foodtrucks&location=" api_client = None def __init__(self): self.api_client = ApiClient() self.api_headers = { 'Accept': 'application/json', 'Authorization': self.get_auth_value() } self.zipcode_re = re.compile(r'^tacome\s+(\d{5})\s*$') def get_channel_id(self): return "all" def get_auth_value(self): token = os.environ.get('SLACK_CODE_CAMP_BOT_YELP_TOKEN') return 'Bearer ' + token if token else None def get_zipcode(self, command): matched = self.zipcode_re.match(command) return matched.group(1) if matched else None def get_data(self, url): return self.api_client.fetch(url, headers=self.api_headers) def invoke(self, command, user): zip = self.get_zipcode(command) if (zip is None): return SlackResponse.text( r'Try: `tacome _ZIP_CODE_`. Example: `tacome 90405`') url = self.url + zip try: result = self.get_data(url) except HTTPError as he: return SlackResponse.text(str(he)) except URLError as ue: return SlackResponse.text(str(ue.args)) return self.create_slack_response(result) def create_slack_response(self, api_response): if (api_response['total'] == 0): return SlackResponse.text('No taco ¯\\_(ツ)_/¯') found = random.choice(api_response['businesses']) description = 'Rated %s by %s people, is %s meters away' % ( found['rating'], found['review_count'], int(found['distance'])) return SlackResponse.attachment(title=found['name'], image_url=found['image_url'], text=description, author_name='Taco details...', author_link=found['url']) def get_command(self): return "tacome"
def change_password(): passwords = ApiClient(auth.get_oauth_session(), app) password_pattern = passwords.get_user_password_pattern( auth.get_id_token()['sub']) return render_template('change_password.html', passwordPattern=password_pattern)
class CCBot: deny_response = [ 'No, {name}. I won''t {action}. I REFUSE', 'Oh boy, here we go again. Why don''t you like me {name}? {action}? really .. REALLY?', 'Doesn''t this get old, {name}? Would you rather I give you a computer error? Fine.... {action} is not supported. Go Away', 'What did I ever do to you {name}? Do I deserve this torment? I''m just a friendly bot and you ask me unspeakable things like {action}', 'JUST ... STOP, {name}. URGH..{action}, really?' ] bully_id = os.environ.get('BULLY_USER_ID') bully_name = None api_client = None def __init__(self): self.api_client = ApiClient() def get_channel_id(self): return "all" def invoke(self, input, user): self.bully_name = bot.get_user_name_by_id(self.bully_id) text = None command,action,args= self.parse_command(input) method_name = "action_" + action if method_name in dir(self): method_to_call = getattr(self, method_name) result = method_to_call(args) text = result else: if user == self.bully_id: result = random.choice(self.deny_response).format(name=self.bully_name, action=action) text = result return SlackResponse.text(text) def get_command(self): return "ccbot" def parse_command(self,command): parts = command.split(' ') size = len(parts) command = parts[0] if size > 0 else None action = parts[1] if size > 1 else None count = 2 args = [] while(count<size): argument = parts[count].strip() if not argument is '': args.append(argument) count = count + 1 return command,action,args #CCBot actions in the format "ccbot <action> <args>" #All actions receive an args array with any data passed in def action_get_time(self,args): return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') def action_schedule(self,args=[]): return "https://www.socalcodecamp.com/schedule.aspx" def action_telljoke(self,args): headers = {'Accept' : 'text/plain'} data = self.api_client.fetch_raw("https://icanhazdadjoke.com/",headers) return data def action_debug_bully_id(self,args=[]): return self.bully_id def action_debug_bully_name(self,args=[]): return self.bully_name
def __init__(self): self.api_client = ApiClient()