-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of github.com:matthew-parlette/scripts
- Loading branch information
Showing
3 changed files
with
232 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.yaml | ||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# OVerview | ||
|
||
Create Trello cards on a weekly or monthly basis. | ||
|
||
The cards will be in a specific list on a specific board. | ||
|
||
# Config | ||
|
||
Example Configuration `config.yaml`: | ||
|
||
``` | ||
monthly: | ||
'1': | ||
- plan finances for the month | ||
trello: | ||
api-key: API-KEY-HERE | ||
api-secret: API-SECRET-HERE | ||
board: qs9sZTxs | ||
list: 5624e269b8a14c9076961c7d | ||
token: TOKEN-HERE | ||
token-secret: TOKEN-SECRET_HERE | ||
weekly: | ||
monday: | ||
- task | ||
thursday: | ||
- take out trash | ||
``` | ||
|
||
## trello | ||
|
||
The `trello` section defines API keys and which board and list to use. | ||
|
||
If you don't know the board or list IDs, you can run the script in debug | ||
(`./recurring-tasks -d`) and it will print a list of IDs for the boards or | ||
lists. | ||
|
||
## monthly | ||
|
||
Using weekday names, specify a list of tasks to perform on each day | ||
|
||
## monthly | ||
|
||
Using the day of the month (integer), specify a list of tasks to perform | ||
on that day. | ||
|
||
# Usage | ||
|
||
To run this as a daily cron job: | ||
|
||
``` | ||
0 6 * * * cd /home/matt/scripts/recurring-tasks;./recurring-tasks -c personal.yaml | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
#!/usr/bin/python | ||
|
||
import argparse | ||
import logging | ||
import os | ||
import yaml | ||
import trello | ||
import trello.util | ||
import datetime | ||
|
||
global config | ||
|
||
|
||
def merge(x, y): | ||
""" | ||
store a copy of x, but overwrite with y's values where applicable | ||
""" | ||
merged = dict(x, **y) | ||
|
||
xkeys = x.keys() | ||
|
||
# if the value of merged[key] was overwritten with y[key]'s value | ||
# then we need to put back any missing x[key] values | ||
for key in xkeys: | ||
# if this key is a dictionary, recurse | ||
if isinstance(x[key], dict) and key in y: | ||
merged[key] = merge(x[key], y[key]) | ||
|
||
return merged | ||
|
||
|
||
def create_card(name, description=""): | ||
log.debug("Creating card '{}'...".format(name)) | ||
|
||
if config['trello']['board']: | ||
board = trelloAPI.get_board(config['trello']['board']) | ||
if board: | ||
log.debug("Loaded board {}".format(str(board))) | ||
if config['trello']['list']: | ||
trellolist = board.get_list(config['trello']['list']) | ||
if trellolist: | ||
trellolist.add_card( | ||
name=name, | ||
desc=description) | ||
log.info("Card created for {}".format(name)) | ||
else: | ||
log.error("Couldn't load list {}".format( | ||
config['trello']['list'])) | ||
else: | ||
log.error("No list id defined in config. " | ||
"Possible values are:\n{}".format( | ||
'\n'.join(["{} - {}".format( | ||
l.id, l.name) for l in board.open_lists()]))) | ||
else: | ||
log.error("Couldn't load board {}".format( | ||
config['trello']['board'])) | ||
else: | ||
log.error("No board id defined in config. " | ||
"Possible values are:\n{}".format( | ||
'\n'.join(["{} - {}".format( | ||
b.id, b.name) for b in trelloAPI.list_boards()]))) | ||
|
||
if __name__ == "__main__": | ||
# Parse command line arguments | ||
parser = argparse.ArgumentParser( | ||
description='Process command line options.') | ||
parser.add_argument( | ||
'-d', '--debug', action='store_true', help='Enable debug logging') | ||
parser.add_argument( | ||
'-c', '--config', help='Specify a config file to use', | ||
type=str, default='config.yaml') | ||
parser.add_argument('--version', action='version', version='0') | ||
args = parser.parse_args() | ||
|
||
# Setup logging options | ||
log_level = logging.DEBUG if args.debug else logging.INFO | ||
log = logging.getLogger(os.path.basename(__file__)) | ||
log.setLevel(log_level) | ||
formatter = logging.Formatter('%(asctime)s:%(name)s:%(levelname)s' | ||
':%(funcName)s(%(lineno)i):%(message)s') | ||
|
||
# Console Logging | ||
ch = logging.StreamHandler() | ||
ch.setLevel(log_level) | ||
ch.setFormatter(formatter) | ||
log.addHandler(ch) | ||
|
||
# File Logging | ||
fh = logging.FileHandler(os.path.basename(__file__) + '.log') | ||
fh.setLevel(log_level) | ||
fh.setFormatter(formatter) | ||
log.addHandler(fh) | ||
|
||
log.info("Initializing...") | ||
|
||
log.info("Loading configuration...") | ||
# Load Config | ||
global config | ||
defaults = { | ||
"weekly": { | ||
# "monday": [ | ||
# "task", | ||
# ], | ||
}, | ||
"monthly": { | ||
# "1": [ | ||
# "task", | ||
# ], | ||
}, | ||
"trello": { | ||
"api-key": "", | ||
"api-secret": "", | ||
"token": "", | ||
"token-secret": "", | ||
"board": "", | ||
"list": "", | ||
}, | ||
} | ||
if os.path.isfile(args.config): | ||
log.debug("Loading config file %s" % args.config) | ||
config = yaml.load(file(args.config)) | ||
if config: | ||
# config contains items | ||
config = merge(defaults, yaml.load(file(args.config))) | ||
log.debug("Config merged with defaults") | ||
else: | ||
# config is empty, just use defaults | ||
config = defaults | ||
log.debug("Config file was empty, loaded config from defaults") | ||
else: | ||
log.debug("Config file does not exist, creating a default config...") | ||
config = defaults | ||
|
||
log.debug("Config loaded as:\n%s, saving this to disk" % str(config)) | ||
with open(args.config, 'w') as outfile: | ||
outfile.write(yaml.dump(config, default_flow_style=False)) | ||
log.debug("Config loaded as:\n%s" % str(config)) | ||
|
||
log.info("Initializing Trello...") | ||
global trello | ||
try: | ||
trelloAPI = trello.TrelloClient( | ||
api_key=config['trello']['api-key'], | ||
api_secret=config['trello']['api-secret'], | ||
token=config['trello']['token'], | ||
token_secret=config['trello']['token-secret']) | ||
if args.debug: | ||
log.debug("Testing Trello (Listing Boards)...") | ||
log.debug(str(trelloAPI.list_boards())) | ||
except trello.exceptions.ResourceUnavailable: | ||
log.error("Authentication error, starting oauth generation...") | ||
trello.util.create_oauth_token( | ||
expiration='never', | ||
key=config['trello']['api-key'], | ||
secret=config['trello']['api-secret']) | ||
|
||
log.info("Initialization complete") | ||
|
||
dow = datetime.datetime.today().strftime("%A").lower() # string | ||
log.debug("Day of week is {}".format(dow)) | ||
dom = datetime.datetime.today().strftime("%-d") # decimal | ||
log.debug("Day of month is {}".format(str(dom))) | ||
|
||
tasks = [] | ||
# Check for day of week tasks | ||
if str(dow) in config['weekly']: | ||
tasks.extend(config['weekly'][str(dow)]) | ||
|
||
# Check for day of month tasks | ||
if str(dom) in config['monthly']: | ||
tasks.extend(config['monthly'][str(dom)]) | ||
|
||
log.info("Tasks for today are {}".format(tasks)) | ||
|
||
# Create task cards | ||
for task in tasks: | ||
log.info("Creating task card '{}'...".format(task)) | ||
create_card(name=task, description="") |