diff --git a/.gitignore b/.gitignore index d2f5d943..6b2d07c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ .env venv/ *.pyc -config.py +./config.py *.config.py limbo.sqlite3 limbo.egg-info @@ -17,3 +17,4 @@ slask.egg-info/ .vagrant .python-version .cache +.idea \ No newline at end of file diff --git a/config.ini b/config.ini new file mode 100644 index 00000000..b954f9c1 --- /dev/null +++ b/config.ini @@ -0,0 +1,7 @@ +[DEFAULT] + +SLACK_TOKEN = token + +[BOT] + +logfile = logfile.log \ No newline at end of file diff --git a/limbo/config.py b/limbo/config.py new file mode 100644 index 00000000..ca4078a8 --- /dev/null +++ b/limbo/config.py @@ -0,0 +1,55 @@ +import logging +import os + +import configparser as confparser + + +class Config(object): + + def __init__(self): + self.env_config = {} + self.file_config = None # type: confparser.ConfigParser + self.load_env_config() + self.load_config_file() + + def load_config_file(self): + config_file = self.env_config.get("config_location", "config.ini") + # check if config exists + if not os.path.exists(config_file): + logger = logging.getLogger(__name__) + logger.warning("File for configuration not found") + else: + self.file_config = confparser.ConfigParser() + self.file_config.read(config_file) + + def load_env_config(self): + config = {} + self._getif(config, "token", "SLACK_TOKEN") + self._getif(config, "loglevel", "LIMBO_LOGLEVEL") + self._getif(config, "logfile", "LIMBO_LOGFILE") + self._getif(config, "logformat", "LIMBO_LOGFORMAT") + self._getif(config, "plugins", "LIMBO_PLUGINS") + self._getif(config, "config_location", "LIMBO_CONFIG_LOCATION") + self.env_config = config + + def _getif(self, config, name, envvar): + if envvar in os.environ: + config[name] = os.environ.get(envvar) + + def get_by_section(self, plugin_name, item_name): + if plugin_name and plugin_name + "_" + str(item_name) in self.env_config.keys(): + return self.env_config[plugin_name + "_" + item_name] + if not self.file_config: + return None + try: + return self.file_config.get(plugin_name, item_name) + except confparser.Error: + return None # in case of not finding it anywhere + + def get(self, *args): + if len(args) > 1: + return self.get_by_section(args[0], args[1]) + return self.get_by_section("BOT", args[0]) + + def __getitem__(self, item): + return self.get("BOT", item) diff --git a/limbo/limbo.py b/limbo/limbo.py index 4f2065fb..6b038f0a 100644 --- a/limbo/limbo.py +++ b/limbo/limbo.py @@ -15,6 +15,7 @@ from .slack import SlackClient, SlackConnectionError, SlackLoginError from .server import LimboServer from .fakeserver import FakeServer +from .config import Config CURDIR = os.path.abspath(os.path.dirname(__file__)) DIR = functools.partial(os.path.join, CURDIR) @@ -170,21 +171,6 @@ def handle_event(event, server): return handler(event, server) -def getif(config, name, envvar): - if envvar in os.environ: - config[name] = os.environ.get(envvar) - - -def init_config(): - config = {} - getif(config, "token", "SLACK_TOKEN") - getif(config, "loglevel", "LIMBO_LOGLEVEL") - getif(config, "logfile", "LIMBO_LOGFILE") - getif(config, "logformat", "LIMBO_LOGFORMAT") - getif(config, "plugins", "LIMBO_PLUGINS") - - return config - def loop(server, test_loop=None): """Run the main loop @@ -308,7 +294,7 @@ def encode(str_, codec='utf8'): def main(args): - config = init_config() + config = Config() if args.test: init_log(config) db = init_db(args.database_name) diff --git a/limbo/plugins/google.py b/limbo/plugins/google.py index a30c79b6..344d48a8 100644 --- a/limbo/plugins/google.py +++ b/limbo/plugins/google.py @@ -7,6 +7,25 @@ from urllib.request import quote, unquote import requests +google_api_key = None +google_cse_id = None + +def on_init(server): + global google_api_key + global google_cse_id + google_api_key = server.config.get("GOOGLE", "API") + google_cse_id = server.config.get("GOOGLE", "CSE") + +def improved_google(q): + # google custom search is more acurate than the old search + # in order to use google custom search configure your account and get your API KEY and CSE ID + # instructions to configure can be found here: https://stackoverflow.com/a/45911123/2999723 + results = requests.get("https://www.googleapis.com/customsearch/v1?key=%s&cx=%s&q=%s"%(google_api_key, google_cse_id, query)).json() + #pprint.pprint(results) + if not results or "items" not in results.keys(): + return ":crying_cat_face: Sorry, google doesn't have an answer for you :crying_cat_face:" + result = results["items"][0] + return result["title"] + " in: "+ result["link"] def google(q): query = quote(q) @@ -30,8 +49,10 @@ def on_message(msg, server): match = re.findall(r"!(?:google|search) (.*)", text) if not match: return - - return google(match[0]) + if google_api_key and google_cse_id: + return improved_google(match[0]) + else: + return google(match[0]) on_bot_message = on_message diff --git a/test/test_cmd.py b/test/test_cmd.py index 95e48fa8..68a9b314 100644 --- a/test/test_cmd.py +++ b/test/test_cmd.py @@ -6,6 +6,8 @@ DIR = os.path.dirname(os.path.realpath(__file__)) TESTPLUGINS = os.path.join(DIR, "plugins") +os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" + # http://stackoverflow.com/a/13160748/42559 def sh(cmd): diff --git a/test/test_config.py b/test/test_config.py new file mode 100644 index 00000000..823f959d --- /dev/null +++ b/test/test_config.py @@ -0,0 +1,24 @@ +# -*- coding: UTF-8 -*- +import os + +DIR = os.path.dirname(os.path.realpath(__file__)) +PARENT = os.path.split(DIR)[0] + +from limbo.config import Config + + +def test_config(): + # test wrong config location + os.environ["LIMBO_CONFIG_LOCATION"] = "config_non_existent.ini" + config = Config() + assert config.file_config is None + + # know a correct config location + os.environ["LIMBO_CONFIG_LOCATION"] = "config.ini" + config = Config() + assert config["SLACK_TOKEN"] == "token" + + # test non existing setting + result = config.get("weather", "weather_token") + assert not result +