1
0
mirror of https://github.com/gryf/slack-backup.git synced 2025-12-17 19:40:21 +01:00

4 Commits
v0.3 ... v0.4

Author SHA1 Message Date
7ccc2bddaa Added section about config in readme 2016-11-28 16:54:48 +01:00
db658f917f Added manifest 2016-11-27 20:52:34 +01:00
8568b552ca Readme update 2016-11-27 20:39:47 +01:00
c1c4581248 Added config file 2016-11-27 20:39:20 +01:00
6 changed files with 327 additions and 21 deletions

2
MANIFEST.in Normal file
View File

@@ -0,0 +1,2 @@
include README.rst
include config_example

View File

@@ -68,7 +68,7 @@ typical session:
(myenv)user@localhost ~/mylogs $ slack-backup fetch \ (myenv)user@localhost ~/mylogs $ slack-backup fetch \
--token xxxx-1111111111-222222222222-333333333333-r4nd0ms7uff \ --token xxxx-1111111111-222222222222-333333333333-r4nd0ms7uff \
--user some@email.address.org --password secret --team myteam \ --user some@email.address.org --password secret --team myteam \
-qqq -d mydatabase.sqlite -qq -d mydatabase.sqlite
where: where:
@@ -116,6 +116,60 @@ command.
See help for the ``slack-backup`` command for complete list of options. See help for the ``slack-backup`` command for complete list of options.
Configuration
-------------
For convenience, you can place all of needed options into configuration file
(aka .ini), which all options (with their defaults) will look like:
.. code:: ini
[common]
channels =
database =
quiet = 0
verbose = 0
[generate]
output =
format = text
theme = plain
[fetch]
user =
password =
team =
token =
Note, that you don't have to put every option. To illustrate ``fetch`` example
from above, here is a corresponding config file:
.. code:: ini
[common]
database = mydatabase.sqlite
quiet = 2
[fetch]
user = some@email.address.org
password = secret
team = myteam
token = xxxx-1111111111-222222222222-333333333333-r4nd0ms7uff
Note, that only ``[common]`` and ``[fetch]`` sections are provided, so it is
enough to invoke ``slack-backup`` command as:
.. code:: shell-session
(myenv)user@localhost ~/mylogs $ slack-backup fetch
There are couple of places, where configuration file would be searched for, in
particular order:
* file provided via argument ``-i`` or ``--config``
* ``slack-backup.ini`` in current directory
* ``$XDG_CONFIG_HOME/slack-backup.ini``, where ``$XDG_CONFIG_HOME`` usually
defaults to ``$HOME/.config``
Details Details
------- -------

View File

@@ -7,6 +7,7 @@ import argparse
import logging import logging
from slack_backup import client from slack_backup import client
from slack_backup import config
def setup_logger(args): def setup_logger(args):
@@ -47,60 +48,73 @@ def main():
fetch = subparser.add_parser('fetch', help='Update local db with Slack' fetch = subparser.add_parser('fetch', help='Update local db with Slack'
' data') ' data')
fetch.add_argument('-t', '--token', required=True, help='Slack token - ' fetch.add_argument('-t', '--token', default=None, help='Slack token - '
'a string, which can be generated/obtained via ' 'a string, which can be generated/obtained via '
'https://api.slack.com/docs/oauth-test-tokens page.') 'https://api.slack.com/docs/oauth-test-tokens page.')
fetch.add_argument('-u', '--user', default='', help='Username for your ' fetch.add_argument('-u', '--user', default=None, help='Username for your '
'Slack account') 'Slack account')
fetch.add_argument('-p', '--password', default='', help='Password for your ' fetch.add_argument('-p', '--password', default=None, help='Password for '
'Slack account.') 'your Slack account.')
fetch.add_argument('-e', '--team', required=True, help='Team name, which ' fetch.add_argument('-e', '--team', default=None, help='Team name, which '
'is part of slack url, for example: if url is ' 'is part of slack url, for example: if url is '
'"https://team.slack.com" than "team" is a name of ' '"https://team.slack.com" than "team" is a name of '
'the team.') 'the team.')
fetch.add_argument('-v', '--verbose', help='Be verbose. Adding more "v" ' fetch.add_argument('-v', '--verbose', help='Be verbose. Adding more "v" '
'will increase verbosity', action="count", default=0) 'will increase verbosity', action="count",
fetch.add_argument('-q', '--quiet', help='Be quiet. Adding more "q"' default=None)
'will decrease verbosity', action="count", default=0) fetch.add_argument('-q', '--quiet', help='Be quiet. Adding more "q" will'
fetch.add_argument('-c', '--channels', default=[], nargs='+', ' decrease verbosity', action="count", default=None)
fetch.add_argument('-c', '--channels', default=None, nargs='+',
help='List of channels to perform actions on. ' help='List of channels to perform actions on. '
'Default is all channels.') 'Default is all channels.')
fetch.add_argument('-d', '--database', default='', fetch.add_argument('-d', '--database', default=None,
help='Path to the database file.') help='Path to the database file.')
fetch.add_argument('-i', '--config', default=None,
help='Use specific config file.')
fetch.set_defaults(func=fetch_data) fetch.set_defaults(func=fetch_data)
generate = subparser.add_parser('generate', help='Generate logs out of ' generate = subparser.add_parser('generate', help='Generate logs out of '
'data in provided database') 'data in provided database')
generate.add_argument('-o', '--output', default='logs', help="Output " generate.add_argument('-o', '--output', default=None, help="Output "
"directory for store logs. All logs are organised " "directory for store logs. All logs are organised "
"per channel. By default it's `logs' directory") "per channel. By default it's `logs' directory")
generate.add_argument('-f', '--format', default='none', generate.add_argument('-f', '--format', default=None,
choices=('text', 'none'), choices=('text', 'none'),
help='Output format. Default is none; only database ' help='Output format. Default is none; only database '
'is updated by latest messages for all/selected ' 'is updated by latest messages for all/selected '
'channels.') 'channels.')
generate.add_argument('-t', '--theme', default='plain', generate.add_argument('-t', '--theme', default=None,
choices=('plain', 'unicode'), choices=('plain', 'unicode'),
help='Choose theme for text output. It doesn\'t ' help='Choose theme for text output. It doesn\'t '
'affect other output formats.') 'affect other output formats.')
generate.add_argument('-v', '--verbose', help='Be verbose. Adding more "v"' generate.add_argument('-v', '--verbose', help='Be verbose. Adding more '
'will increase verbosity', action="count", default=0) '"v" will increase verbosity', action="count",
default=None)
generate.add_argument('-q', '--quiet', help='Be quiet. Adding more "q" ' generate.add_argument('-q', '--quiet', help='Be quiet. Adding more "q" '
'will decrease verbosity', action="count", default=0) 'will decrease verbosity', action="count",
default=None)
generate.add_argument('-c', '--channels', default=[], nargs='+', generate.add_argument('-c', '--channels', default=[], nargs='+',
help='List of channels to perform actions on. ' help='List of channels to perform actions on. '
'Default is all channels.') 'Default is all channels.')
generate.add_argument('-d', '--database', default='', generate.add_argument('-d', '--database', default=None,
help='Path to the database file.') help='Path to the database file.')
generate.add_argument('-i', '--config', default=None,
help='Use specific config file.')
generate.set_defaults(func=generate_raport) generate.set_defaults(func=generate_raport)
args = parser.parse_args() args = parser.parse_args()
cfg = config.Config()
msg = cfg.update(args)
setup_logger(args) setup_logger(args)
logging.info(msg)
args.func(args) args.func(args)

View File

@@ -10,7 +10,7 @@ except ImportError:
setup(name="slack-backup", setup(name="slack-backup",
packages=["slack_backup"], packages=["slack_backup"],
version="0.3", version="0.4",
description="Make copy of slack converstaions", description="Make copy of slack converstaions",
author="Roman Dobosz", author="Roman Dobosz",
author_email="gryf73@gmail.com", author_email="gryf73@gmail.com",

102
slack_backup/config.py Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Configuration module for slack-backup
"""
import json
import os
import configparser
class Config(object):
"""Configuration keeper"""
ints = ['verbose', 'quiet']
sections = {'common': ['channels', 'database', 'quiet', 'verbose'],
'fetch': ['user', 'password', 'team', 'token'],
'generate': ['output', 'format', 'theme']}
def __init__(self):
"""
Init. Read config, if exists, and update passed argument parser
object.
"""
self.cp = configparser.ConfigParser()
self._options = {'channels': [],
'database': None,
'quiet': 0,
'verbose': 0,
'user': None,
'password': None,
'team': None,
'token': None,
'output': None,
'format': None,
'theme': None}
# This message supposed to be displayed in INFO level. During the time
# of running the code where it should be displayed there is no
# complete information about logging level. Displaying message is
# dependent on the a) config file, b) argument from commandline. Let's
# resolve if user want to have that information or not after merging
# those two sources. If user do not want to see any message in INFO
# level, we shouldn't do so.
self.msg = ''
def update(self, args):
self.load_config(args)
self.parse_loaded_options()
self.update_args(args)
return self.msg
def load_config(self, args):
locations = [args.config,
'./slack-backup.conf',
os.path.expandvars('$XDG_CONFIG_HOME/slack-backup.ini'),
os.path.expandvars('$HOME/.config/slack-backup.ini')]
for location in locations:
if os.path.exists(location):
self.cp.read(location)
self.msg = 'Found configuration file: %s' % location
break
else:
self.msg = 'No configuration file found'
def parse_loaded_options(self):
for section in self.cp.sections():
if section not in self.sections:
continue
for option in self.sections[section]:
if option in self.ints:
val = self.cp.getint(section, option, fallback=0)
elif option == 'channels':
val = self.cp.get(section, option, fallback='[]')
val = json.loads(val)
else:
val = self.cp.get(section, option, fallback='')
self._options[option] = val
def update_args(self, args):
# special case, re-set information for verbose/quiet options
if args.verbose is not None and self._options['quiet'] is not None:
self._options['quiet'] = 0
self._options['verbose'] = args.verbose
if args.quiet is not None and self._options['verbose'] is not None:
self._options['verbose'] = 0
self._options['quiet'] = args.quiet
for sec_id in (args.parser, 'common'):
for option in self.sections[sec_id]:
if option in args:
if getattr(args, option) is not None:
continue
setattr(args, option, self._options[option])

134
tests/test_config.py Normal file
View File

@@ -0,0 +1,134 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import tempfile
import os
import unittest
from slack_backup import config
CONF = """\
[common]
channels=["one","two", "three"]
database=dbfname.sqlite
quiet=1
verbose=2
[generate]
output=logs
format=text
theme=plain
[fetch]
user=someuser@address.com
password=secret
team=myteam
token=xxxx-1111111111-222222222222-333333333333-r4nd0ms7uff
"""
class TestConfig(unittest.TestCase):
def setUp(self):
fd, self.confname = tempfile.mkstemp()
os.close(fd)
with open(self.confname, 'w') as fobj:
fobj.write(CONF)
def tearDown(self):
os.unlink(self.confname)
def test_config(self):
self.assertTrue(os.path.exists(self.confname))
self.assertTrue(os.path.isfile(self.confname))
args = argparse.Namespace()
args.config = None
args.parser = 'fetch'
args.verbose = 2
args.quiet = None
args.channels = None
args.database = None
args.user = None
args.password = None
args.team = None
args.token = None
conf = config.Config()
conf.update(args)
self.assertDictEqual(vars(args), {'config': None,
'parser': 'fetch',
'verbose': 2,
'quiet': 0,
'channels': [],
'database': '',
'user': None,
'password': None,
'team': None,
'token': None})
args = argparse.Namespace()
args.config = self.confname
args.parser = 'fetch'
args.verbose = 2
args.quiet = None
args.channels = None
args.database = None
args.user = None
args.password = None
args.team = None
args.token = None
conf = config.Config()
conf.update(args)
self.assertEqual(conf._options['verbose'], 2)
self.assertListEqual(conf._options['channels'],
['one', 'two', 'three'])
self.assertEqual(conf._options['database'], 'dbfname.sqlite')
self.assertEqual(conf._options['user'], 'someuser@address.com')
self.assertDictEqual(vars(args), {'config': self.confname,
'parser': 'fetch',
'verbose': 2,
'quiet': 0,
'channels': ['one', 'two', 'three'],
'database': 'dbfname.sqlite',
'user': 'someuser@address.com',
'password': 'secret',
'team': 'myteam',
'token': 'xxxx-1111111111-'
'222222222222-333333333333-'
'r4nd0ms7uff'})
# override some conf options with commandline
args = argparse.Namespace()
args.config = self.confname
args.parser = 'fetch'
args.verbose = None
args.quiet = 2
args.channels = ['foo']
args.database = None
args.user = 'joe'
args.password = 'ultricies'
args.team = ''
args.token = 'the token'
conf = config.Config()
conf.update(args)
self.assertDictEqual(vars(args), {'config': self.confname,
'parser': 'fetch',
'verbose': 0,
'quiet': 2,
'channels': ['foo'],
'database': 'dbfname.sqlite',
'user': 'joe',
'password': 'ultricies',
'team': '',
'token': 'the token'})