diff --git a/.gitignore b/.gitignore index 0033751..b76ad2b 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,9 @@ fabric.properties .idea/caches/build_file_checksums.ser resouces/facts.txt + +secrets.local + +facts.txt + +.idea/terminal.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..deb38e6 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +groupme-facts-bot \ No newline at end of file diff --git a/.idea/groupme-facts-bot.iml b/.idea/groupme-facts-bot.iml new file mode 100644 index 0000000..e98566c --- /dev/null +++ b/.idea/groupme-facts-bot.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..4c9fb1f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4267c41 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/terminal.xml b/.idea/terminal.xml new file mode 100644 index 0000000..fbd11ad --- /dev/null +++ b/.idea/terminal.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0acceb --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +A simple random facts bot for Groupme using Python \ No newline at end of file diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..bcc746e --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +import service \ No newline at end of file diff --git a/common.py b/common.py new file mode 100644 index 0000000..593b45d --- /dev/null +++ b/common.py @@ -0,0 +1,6 @@ +from pathlib import Path + + +def get_project_root() -> Path: + """Returns project root folder.""" + return Path(__file__).parent.parent diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..efc85f8 --- /dev/null +++ b/config.yaml @@ -0,0 +1,41 @@ +region: us-east-2 + +function_name: avan_facts_bot +handler: service.handler +description: Random Avan facts via groupme +runtime: python3.7 +#role: lambda_basic_execution + +# S3 upload requires appropriate role with s3:PutObject permission +# (ex. basic_s3_upload), a destination bucket, and the key prefix +# bucket_name: 'example-bucket' +# s3_key_prefix: 'path/to/file/' + +# if access key and secret are left blank, boto will use the credentials +# defined in the [default] section of ~/.aws/credentials. +aws_access_key_id: ${AWS_TOKEN_ID} +aws_secret_access_key: ${AWS_TOKEN} + +# dist_directory: dist +# timeout: 15 +# memory_size: 512 +# concurrency: 500 +# + +# Experimental Environment variables +environment_variables: + BOT_NAME: ${BOT_NAME} + DB_TABLE_NAME: ${DB_TABLE_NAME} + GROUPME_KEY: ${GROUPME_KEY} + FACTS_PATH: ${FACTS_PATH} + +# If `tags` is uncommented then tags will be set at creation or update +# time. During an update all other tags will be removed except the tags +# listed here. +#tags: +# tag_1: foo +# tag_2: bar + +# Build options +build: + source_directories: lib # a comma delimited list of directories in your project root that contains source to package. diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..7bca529 --- /dev/null +++ b/constants.py @@ -0,0 +1,7 @@ +import os + +BOT_NAME = os.environ.get("BOT_NAME") +DB_TABLE_NAME = os.environ.get("DB_TABLE_NAME") +FACTS_PATH = os.environ.get("FACTS_PATH") +GROUPME = os.environ.get("GROUPME_KEY") + diff --git a/db_service.py b/db_service.py new file mode 100644 index 0000000..89ab2b8 --- /dev/null +++ b/db_service.py @@ -0,0 +1,15 @@ +from abc import abstractmethod + + +class DbService: + + def __init__(self) -> None: + super().__init__() + + @abstractmethod + def get_fact(self): + raise NotImplementedError + + @abstractmethod + def get_multiple_facts(self, count=5): + raise NotImplementedError diff --git a/dynamo_db.py b/dynamo_db.py new file mode 100644 index 0000000..ab19c9d --- /dev/null +++ b/dynamo_db.py @@ -0,0 +1,34 @@ +import random + +import boto3 + +import constants +from db_service import DbService +import common + + +class DynamoDb(DbService): + + def __init__(self) -> None: + super().__init__() + self.FACTS_LIST = [] + self.dynamodb = boto3.resource('dynamodb') + self.facts_table = self.dynamodb.Table(constants.DB_TABLE_NAME) + print(self.facts_table.creation_date_time) + + def load_facts_from_db(self): + # global facts_table + self.FACTS_LIST.clear() + resp = self.facts_table.scan() + self.FACTS_LIST = [i["fact"] for i in resp["Items"]] + assert self.FACTS_LIST + + def get_fact(self): + if self.FACTS_LIST is None or not self.FACTS_LIST: + self.load_facts_from_db() + return random.choice(self.FACTS_LIST) + + def get_multiple_facts(self, count=2): + if self.FACTS_LIST is None or not self.FACTS_LIST: + self.load_facts_from_db() + return random.sample(self.FACTS_LIST, k=count) diff --git a/event.json b/event.json new file mode 100644 index 0000000..f5ac7c2 --- /dev/null +++ b/event.json @@ -0,0 +1,4 @@ +{ + "pi": 3.14, + "e": 2.718 +} diff --git a/fact_bot.py b/fact_bot.py new file mode 100644 index 0000000..cb5687b --- /dev/null +++ b/fact_bot.py @@ -0,0 +1,19 @@ +import fact_service +import groupme +import constants + + +def post_fact_to_group(): + # Get Groupme api token to post with + groupme_client = groupme.get_client() + # Get specific group from groupme + fact_bot = groupme.get_bot(constants.BOT_NAME) + # Get Random Fact + fact = fact_service.get_random_fact() + # Post fact in Group + # groupme_client. + message = fact_bot.post(text=fact) + + +if __name__ == '__main__': + post_fact_to_group() diff --git a/fact_service.py b/fact_service.py new file mode 100644 index 0000000..3319e50 --- /dev/null +++ b/fact_service.py @@ -0,0 +1,17 @@ +from dynamo_db import DynamoDb +from text_db import TextDb + + +def get_random_fact(): + ret_fact = None + # db_service = TextDb() + db_service = DynamoDb() + ret_fact = db_service.get_fact() + return ret_fact + + +def get_multiple_random_facts(): + ret_fact = None + db_service = TextDb() + ret_fact = db_service.get_multiple_facts() + return ret_fact diff --git a/facts_sample.txt b/facts_sample.txt new file mode 100644 index 0000000..03ae83f --- /dev/null +++ b/facts_sample.txt @@ -0,0 +1,11 @@ +Charles Darwin's personal pet tortoise didn't die until recently. +The average person will spend six months of their life waiting for red lights to turn green. +A bolt of lightning contains enough energy to toast 100,000 slices of bread. +President Lyndon B. Johnson owned a water-surfing car. +Cherophobia is the word for the irrational fear of being happy. +You can hear a blue whale's heartbeat from two miles away. +Nearly 30,000 rubber ducks were lost a sea in 1992 and are still being discovered today. +There's a Manhattan-specific ant. +The inventor of the frisbee was turned into a frisbee after he died. +There's a bridge exclusively for squirrels. +Subway footlongs aren't always a foot long. diff --git a/groupme.py b/groupme.py new file mode 100644 index 0000000..dbf18e6 --- /dev/null +++ b/groupme.py @@ -0,0 +1,40 @@ +from groupy import Client + +import constants + +GROUPME_CLIENT: Client = None + + +def init_client(): + global GROUPME_CLIENT + GROUPME_CLIENT = Client.from_token(constants.GROUPME) + + +def get_client(): + if GROUPME_CLIENT is None: + init_client() + return GROUPME_CLIENT + + +def get_group(group_name): + found_group = Exception("Input group not found") + if GROUPME_CLIENT is None: + init_client() + group_list = GROUPME_CLIENT.groups.list(per_page=50) + for ret_group in group_list: + if group_name.casefold() == ret_group.name.casefold(): + found_group = ret_group + break + return found_group + + +def get_bot(bot_name): + found_bot = Exception("Input bot not found") + if GROUPME_CLIENT is None: + init_client() + bot_list = GROUPME_CLIENT.bots.list() + for ret_bot in bot_list: + if bot_name.casefold() == ret_bot.name.casefold(): + found_bot = ret_bot + break + return found_bot diff --git a/requirements.txt b/requirements.txt index 140019e..7c23132 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ +boto3 GroupyAPI -pytest \ No newline at end of file +pytest +python-lambda \ No newline at end of file diff --git a/service.py b/service.py new file mode 100644 index 0000000..b800cf9 --- /dev/null +++ b/service.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +import fact_bot + + +def handler(event, context): + # Your code goes here! + fact_bot.post_fact_to_group() diff --git a/test_dynamo_db.py b/test_dynamo_db.py new file mode 100644 index 0000000..43fe319 --- /dev/null +++ b/test_dynamo_db.py @@ -0,0 +1,15 @@ +from dynamo_db import DynamoDb + + +class TestDynamoDb: + def test_get_fact(self): + text_db_service = DynamoDb() + random_fact = text_db_service.get_fact() + assert random_fact is not None + assert random_fact != "" + + def test_get_multiple_facts(self): + text_db_service = DynamoDb() + random_facts_list = text_db_service.get_multiple_facts() + assert random_facts_list is not None + assert len(random_facts_list) > 0 diff --git a/test_text_db.py b/test_text_db.py new file mode 100644 index 0000000..7744be7 --- /dev/null +++ b/test_text_db.py @@ -0,0 +1,15 @@ +from text_db import TextDb + + +class TestTextDb: + def test_get_fact(self): + text_db_service = TextDb() + random_fact = text_db_service.get_fact() + assert random_fact is not None + assert random_fact != "" + + def test_get_multiple_facts(self): + text_db_service = TextDb() + random_facts_list = text_db_service.get_multiple_facts() + assert random_facts_list is not None + assert len(random_facts_list) > 0 diff --git a/text_db.py b/text_db.py new file mode 100644 index 0000000..4c3f1d2 --- /dev/null +++ b/text_db.py @@ -0,0 +1,27 @@ +import random + +import constants +from db_service import DbService +import common + + +class TextDb(DbService): + + def __init__(self) -> None: + super().__init__() + self.FACTS_LIST = None + + def load_facts_from_file(self): + facts_file = open(f"{constants.FACTS_PATH}", mode="r") + self.FACTS_LIST = facts_file.readlines() + assert self.FACTS_LIST + + def get_fact(self): + if self.FACTS_LIST is None: + self.load_facts_from_file() + return random.choice(self.FACTS_LIST) + + def get_multiple_facts(self, count=5): + if self.FACTS_LIST is None: + self.load_facts_from_file() + return random.sample(self.FACTS_LIST, k=count)