コード例 #1
0
ファイル: nextaction.py プロジェクト: twobraids/localbin
class TodoistActionAPI(RequiredConfig):
    """An encapsulation of the Todoist API.  It wraps the lower level
    methods with methods appropriate for this task."""
    required_config = Namespace()
    required_config.add_option(
        name="api_key",
        default='',
        doc="Todoist API Key",
    )
    required_config.add_option(
        name="delay",
        default=5,
        doc="Specify the delay in seconds between syncs"
    )
    required_config.add_option(
        name="debug",
        default=False,
        doc="Enable debugging"
    )
    required_config.add_option(
        name="one_time",
        default=False,
        doc="Update Todoist once and exit"
    )
    def __init__(self, config, logging):
        super(TodoistActionAPI, self).__init__()
        self.config = config
        self.api = TodoistAPI(token=config.api_key)
        self.api.sync()
        self.logging = logging
コード例 #2
0
def main():
    API_TOKEN = get_token()
    if not API_TOKEN:
        logging.warn('Please set the API token in environment variable.')
        exit()
    api = TodoistAPI(API_TOKEN)
    api.sync()
    return api
コード例 #3
0
ファイル: nextaction.py プロジェクト: leospol/NextAction
    def setup(self):
        self.parse_args()

        # Run the initial sync
        logging.debug('Connecting to the Todoist API')
        self.api = TodoistAPI(token=self.args.api_key)
        logging.debug('Syncing the current state from the API')
        self.api.sync()
        self.next_label_id = self.check_label(self.args.label)
        self.active_label_id = self.check_label(self.args.active)
        self.waitfor_label_id = self.check_label(self.args.waitfor)
コード例 #4
0
ファイル: my_todoist.py プロジェクト: Koenma413/django-th
 def __init__(self, token=None, **kwargs):
     super(ServiceTodoist, self).__init__(token, **kwargs)
     self.AUTH_URL = 'https://todoist.com/oauth/authorize'
     self.ACC_TOKEN = 'https://todoist.com/oauth/access_token'
     self.REQ_TOKEN = 'https://todoist.com/oauth/access_token'
     self.consumer_key = settings.TH_TODOIST['client_id']
     self.consumer_secret = settings.TH_TODOIST['client_secret']
     self.scope = 'task:add,data:read,data:read_write'
     self.service = 'ServiceTodoist'
     self.oauth = 'oauth2'
     if token:
         self.token = token
         self.todoist = TodoistAPI(token)
コード例 #5
0
#!/usr/local/bin/python

# TODOIST

from datetime import date, timedelta, datetime
from dateutil import parser
from todoist.api import TodoistAPI
import creds

# PROJECTS / IDs

todoist_api = TodoistAPI()

# GET ALL TASKS WITH DUE DATE


def todoist_list(date):

    # Sync (load) data
    todoist_api.sync()

    tasks = []

    for item in todoist_api.state['items']:
        due = item['due_date_utc']
        if due:
            # Slicing :10 gives us the relevant parts
            if due[:10] == date:
                tasks.append(item)

    # Sort by priority
コード例 #6
0
 def __init__(self):
     self.api_key = os.environ.get("API_KEY")
     self.api_call = TodoistAPI(self.api_key)
     self.api_call.sync()
コード例 #7
0
 def find_project_id(self, project_name):
     api_call = TodoistAPI(self.api_key)
     api_call.sync()
     for project in range(len(api_call.state['projects'])):
         if api_call.state['projects'][project].data['name'].lower() == project_name.lower():
             return api_call.state['projects'][project].data['id']
コード例 #8
0
ファイル: ToDoist.py プロジェクト: manujosephv/MovieScraper
class ToDoist:
    
    __metaclass__ = Singleton
    
    def __init__(self):
        self.api = TodoistAPI(Config.TODOIST_API_KEY)
        self.api.sync()
        self.mt = MusicTools()

    def find_project_id_by_name(self,project_name):
        projects = self.api.state['projects']
        for project in projects:
            if project['name'] == project_name:
                return project['id']
            
    def add_item(self, item, project_id=None, project_name = None):
        if (project_id is None) and (project_name is None):
            raise ValueError('Either project_id or project_name should be provided')
        if project_id is None:
            project_id = self.find_project_id_by_name(project_name)
        self.api.items.add(item,project_id)

    def walk_items_in_project(self, function_to_call, project=Config.TODOIST_PROJECT_NAME, commit=True, mark_read = True):
        items = self.api.state['items']
        logger.info("Scanning and Downloading ToDoist List:{}".format(project))
        for item in items:
            logger.debug(u"Scanning {}|{}".format(item['content'], item['id']))
            if item and ('checked' in item.data.keys()):
                if ((item['project_id'] == self.find_project_id_by_name(project)) & (item['checked']==0)): #For Debug  & (item['id']==112286022)    
                    function_to_call(item, mark_read)
        if commit:
            self.api.commit()

    def download_song(self,item, mark_read):
        result = 1
        song = self.get_song(item['content'])
        if song:
            logger.info(u"Scanned Results: {}|{}".format(song.full_title, song.video_link))
            result = self.mt.download_music(song.video_link, song.full_title, is_quiet=True)
            # result = 1
            logger.debug("Download Result: {} | 1 is a failure, 0 is a success".format(result))
        #1 is a failure, 0 is a success
            if result == 0:
                logger.info("Download Success. Marking item as completed...")
                if mark_read:
                    item.complete()
                self.mt.fix_id3(song)
            else:
                logger.error(u"Downloading of {} failed. Moving to the next item...".format(song.full_title))

    def get_song(self,item):
        #Checking Youtube Links
        youtube=Youtube()
        link = youtube.extract_youtube_link_from_text(item)
        if link:
            full_title = youtube.get_title_from_youtube_code(get_youtube_code_from_link(link))
            song = Song(full_title= full_title, video_link = link, )
        else:
            soundcloud = Soundcloud()
            link = soundcloud.extract_soundcloud_link_from_text(item)
            if link:
                song= Song(full_title=soundcloud.get_title_soundcloud(link), video_link = link)
            else:
                #Items without a link
                songs = youtube.youtube_search(item,1)
                if len(songs) >0 :
                    song = songs[0]
                else:
                    return None
        return song
コード例 #9
0
ファイル: todoist_add.py プロジェクト: jvsoest/cmd_tricks
                    default='',
                    help='the actual text for the task')
inputArgs = parser.parse_args()

# Load ~/.cmd_tricks.json config file
config = None
with open(os.path.join(Path.home(), ".cmd_tricks.json")) as f:
    config = json.load(f)

# Exit if no config is found
if config is None:
    print("Could not load config file (at ~/.cmd_tricks.json)")
    sys.exit(1)

# Read Todoist API key form .cmd_tricks.json
api = TodoistAPI(config["todoist"]["api_key"])

# get contents from clipboard
cbContents = None
if inputArgs.clipboard:
    cbContents = clipboard.paste()


############################
# Add GUI functions
############################
class UserInterface:
    def __init__(self, todoistApi, taskName, taskNote):
        # super().__init__()
        self.todoistApi = todoistApi
コード例 #10
0
def create_task(key=tovakey):
    api = TodoistAPI(key)
    api.sync()
    payload = request.get_json()
    task1_to_add = payload["context"]["facts"]["task1_to_add"]["grammar_entry"]
    no_of_tasks = 1
    if "due_date" in payload['context']['facts'].keys():
        due_date = payload["context"]["facts"]["due_date"]["grammar_entry"]
    else:
        due_date = None
    if "task2_to_add" in payload['context']['facts'].keys():
        task2_to_add = payload["context"]["facts"]["task2_to_add"][
            "grammar_entry"]
        no_of_tasks = 2
    if "task3_to_add" in payload['context']['facts'].keys():
        task3_to_add = payload["context"]["facts"]["task3_to_add"][
            "grammar_entry"]
        no_of_tasks = 3
    if "project_to_add" in payload['context']['facts'].keys():
        target_project = payload["context"]["facts"]["project_to_add"][
            "grammar_entry"]
        projects = extract_projects(api)
        project_found = False
        for project in projects:
            if project[0].lower() == target_project.lower():
                project_found = True
                if no_of_tasks == 1:
                    added_task1 = api.items.add(task1_to_add,
                                                project_id=project[1],
                                                due={"string": due_date})
                elif no_of_tasks == 2:
                    added_task1 = api.items.add(task1_to_add,
                                                project_id=project[1],
                                                due={"string": due_date})
                    added_task2 = api.items.add(task2_to_add,
                                                project_id=project[1],
                                                due={"string": due_date})
                elif no_of_tasks == 3:
                    added_task1 = api.items.add(task1_to_add,
                                                project_id=project[1],
                                                due={"string": due_date})
                    added_task2 = api.items.add(task2_to_add,
                                                project_id=project[1],
                                                due={"string": due_date})
                    added_task3 = api.items.add(task3_to_add,
                                                project_id=project[1],
                                                due={"string": due_date})
        if project_found == False:
            added_project = api.projects.add(target_project,
                                             due={"string": due_date})
            if no_of_tasks == 1:
                added_task1 = api.items.add(task1_to_add,
                                            project_id=added_project['id'],
                                            due={"string": due_date})
            elif no_of_tasks == 2:
                added_task1 = api.items.add(task1_to_add,
                                            project_id=added_project['id'],
                                            due={"string": due_date})
                added_task2 = api.items.add(task2_to_add,
                                            project_id=added_project['id'],
                                            due={"string": due_date})
            elif no_of_tasks == 3:
                added_task1 = api.items.add(task1_to_add,
                                            project_id=added_project['id'],
                                            due={"string": due_date})
                added_task2 = api.items.add(task2_to_add,
                                            project_id=added_project['id'],
                                            due={"string": due_date})
                added_task3 = api.items.add(task3_to_add,
                                            project_id=added_project['id'],
                                            due={"string": due_date})
    else:
        if no_of_tasks == 1:
            added_task1 = api.items.add(task1_to_add, due={"string": due_date})
        elif no_of_tasks == 2:
            added_task1 = api.items.add(task1_to_add, due={"string": due_date})
            added_task2 = api.items.add(task2_to_add, due={"string": due_date})
        elif no_of_tasks == 3:
            added_task1 = api.items.add(task1_to_add, due={"string": due_date})
            added_task2 = api.items.add(task2_to_add, due={"string": due_date})
            added_task3 = api.items.add(task3_to_add, due={"string": due_date})
    api.commit()
    return action_success_response()
コード例 #11
0
 def __init__(self, api_token, api_url):
     # initiate a todoist api instance
     self.api = TodoistAPI(api_token)
     self.api_token = api_token
     self.api_url = api_url
コード例 #12
0
class APIHandler:
    def __init__(self, api_token, api_url):
        # initiate a todoist api instance
        self.api = TodoistAPI(api_token)
        self.api_token = api_token
        self.api_url = api_url

    def get_project_list(self):
        self.api.sync()
        project_list = self.api.state['projects']
        return project_list

    def get_tasks_by_project(self, project_id):
        tasks_list = requests.get("%s/tasks" % self.api_url,
                                  params={
                                      "project_id": project_id
                                  },
                                  headers={
                                      "Authorization":
                                      "Bearer %s" % self.api_token
                                  }).json()

        return tasks_list

    def create_project(self, project_name):
        self.api.projects.add(project_name)
        self.api.commit()
        return True

    def get_all_tasks(self):
        tasks_list = requests.get("%s/tasks" % self.api_url,
                                  headers={
                                      "Authorization":
                                      "Bearer %s" % self.api_token
                                  }).json()
        return tasks_list

    def get_today_tasks(self):
        all_tasks = self.get_all_tasks()
        today_tasks = []

        today = datetime.today().date()
        for task in all_tasks:
            task_due = task.get('due')
            if task_due:
                task_due_date_string = task_due.get('date')
                task_due_date = datetime.strptime(task_due_date_string,
                                                  '%Y-%m-%d').date()
                if task_due_date == today:
                    today_tasks.append(task)

        return today_tasks

    def create_task(self, task_content):
        result = requests.post("%s/tasks" % self.api_url,
                               data=json.dumps({
                                   "content": task_content,
                               }),
                               headers={
                                   "Content-Type": "application/json",
                                   "X-Request-Id": str(uuid.uuid4()),
                                   "Authorization":
                                   "Bearer %s" % self.api_token
                               }).json()

        return result
コード例 #13
0
ファイル: nextaction.py プロジェクト: twobraids/localbin
 def __init__(self, config, logging):
     super(TodoistActionAPI, self).__init__()
     self.config = config
     self.api = TodoistAPI(token=config.api_key)
     self.api.sync()
     self.logging = logging
コード例 #14
0
ファイル: nextaction.py プロジェクト: leospol/NextAction
class NextAction(object):
    def __init__(self):
        self.args = None
        self.api = None
        self.next_label_id = None
        self.waitfor_label_id = None
        self.active_label_id = None

    def main(self):
        self.setup()
        self.loop()

    def check_label(self, label):
        # Check if the label exists
        labels = self.api.labels.all(lambda x: x['name'] == label)
        if len(labels) > 0:
            label_id = labels[0]['id']
            logging.debug('Label %s found as label id %d', label, label_id)
            return label_id
        else:
            logging.error(
                "Label %s doesn't exist.", label)
            sys.exit(1)

    def setup(self):
        self.parse_args()

        # Run the initial sync
        logging.debug('Connecting to the Todoist API')
        self.api = TodoistAPI(token=self.args.api_key)
        logging.debug('Syncing the current state from the API')
        self.api.sync()
        self.next_label_id = self.check_label(self.args.label)
        self.active_label_id = self.check_label(self.args.active)
        self.waitfor_label_id = self.check_label(self.args.waitfor)

    def loop(self):
        """
        Main loop
        """
        while True:
            try:
                self.api.sync()
            except Exception as exc:
                logging.exception('Error trying to sync with Todoist API: %s',
                                  exc)
            else:
                self.process(self.api.projects.all())

                logging.debug(
                    '%d changes queued for sync... committing if needed',
                    len(self.api.queue))
                if len(self.api.queue):
                    self.api.commit()

            if self.args.onetime:
                break
            logging.debug('Sleeping for %d seconds', self.args.delay)
            time.sleep(self.args.delay)

    def process(self, projects, parent_indent=0, parent_type=None):
        """
        Process all projects
        """
        current_type = parent_type
        while projects and parent_indent < projects[0]["indent"]:
            # dig deeper
            if projects[0]["indent"] > parent_indent + 1:
                self.process(projects, parent_indent + 1, current_type)
                continue

            project = projects.pop(0)
            current_type = self.get_project_type(project, parent_type)
            if not current_type:
                # project not marked - not touching
                continue

            logging.debug('Project %s being processed as %s',
                          project['name'], current_type)

            def item_filter(x):
                return x['project_id'] == project['id']

            all_items = self.api.items.all(item_filter)
            items = sorted(all_items, key=lambda x: x['item_order'])
            item_objs = []
            while items:
                item_objs.append(Item(items))
            self.process_items(item_objs, current_type)
            self.activate(item_objs)

    def process_items(self, items, parent_type, not_in_first=False):
        """
        Process all tasks in project
        """
        # get the first item for serial
        first = None
        if parent_type == "serial":
            not_checked = [item for item in items if not item.checked]
            if not_checked and not self.is_waitfor(not_checked[0]):
                first = not_checked[0]

        # process items
        parent_active = False
        for item in items:
            current_type = self.get_item_type(item)

            if current_type:
                logging.debug('Identified %s as %s type', item.content,
                              current_type)
            else:
                current_type = parent_type

            if item.children:
                active = self.process_items(item.children, current_type,
                                            not_in_first or
                                            first and item != first)
            else:
                active = False

            if self.check_future(item):
                continue

            active |= self.process_item(item, parent_type, first, not_in_first)
            item.active = active
            parent_active |= active
        return parent_active

    def process_item(self, item, type, first=None, not_in_first=False):
        """
        Process single item
        """
        # untag if checked
        if item.checked or not_in_first:
            return self.remove_label(item, self.next_label_id)
        # don't tag if parent with unchecked child
        elif [child for child in item.children if not child.checked]:
            return self.remove_label(item, self.next_label_id)
        # tag all parallel but not waitfors
        elif type == "parallel" and not self.is_waitfor(item):
            return self.add_label(item, self.next_label_id)
        # tag the first serial
        elif type == "serial" and item == first:
            return self.add_label(item, self.next_label_id)
        # untag otherwise
        else:
            return self.remove_label(item, self.next_label_id)

    def activate(self, items):
        """
        Mark indent 1 items as active if supposed to be
        """
        for item in items:
            if item.active:
                self.add_label(item, self.active_label_id)
            else:
                self.remove_label(item, self.active_label_id)

    def check_future(self, item):
        """
        If its too far in the future, remove the next_action tag and skip
        """
        if self.args.hide_future > 0 and item.due_date_utc:
            due_date = datetime.strptime(item.due_date_utc,
                                         '%a %d %b %Y %H:%M:%S +0000')
            future_diff = (due_date - datetime.utcnow()).total_seconds()
            if future_diff >= (self.args.hide_future * 86400):
                self.remove_label(item, self.next_label_id)
                return True

    def get_project_type(self, project_object, parent_type):
        """
        Identifies how a project should be handled
        """
        name = project_object['name'].strip()
        if name == 'Inbox':
            return self.args.inbox
        elif name[-1] == self.args.parallel_suffix:
            return 'parallel'
        elif name[-1] == self.args.serial_suffix:
            return 'serial'
        elif parent_type:
            return parent_type

    def get_item_type(self, item):
        """
        Identifies how a item with sub items should be handled
        """
        name = item.content.strip()
        if name[-1] == self.args.parallel_suffix:
            return 'parallel'
        elif name[-1] == self.args.serial_suffix:
            return 'serial'

    def add_label(self, item, label):
        if label not in item.labels:
            labels = item.labels
            logging.debug('Updating %s with label %s', item.content, label)
            labels.append(label)
            self.api.items.update(item.id, labels=labels)
        return True

    def remove_label(self, item, label):
        if label in item.labels:
            labels = item.labels
            logging.debug('Updating %s without label %s', item.content, label)
            labels.remove(label)
            self.api.items.update(item.id, labels=labels)
        return False

    def is_waitfor(self, item):
        return self.waitfor_label_id in item.labels

    @staticmethod
    def get_subitems(items, parent_item=None):
        """
        Search a flat item list for child items
        """
        result_items = []
        found = False
        if parent_item:
            required_indent = parent_item['indent'] + 1
        else:
            required_indent = 1
        for item in items:
            if parent_item:
                if not found and item['id'] != parent_item['id']:
                    continue
                else:
                    found = True
                if item['indent'] == parent_item['indent'] and item['id'] != \
                        parent_item['id']:
                    return result_items
                elif item['indent'] == required_indent and found:
                    result_items.append(item)
            elif item['indent'] == required_indent:
                result_items.append(item)
        return result_items

    def parse_args(self):
        """
        Parse command-line arguments
        """
        parser = argparse.ArgumentParser()
        parser.add_argument('-a', '--api_key', help='Todoist API Key')
        parser.add_argument('-l', '--label',
                            help='The next action label to use',
                            default='next_action')
        parser.add_argument('-c', '--active',
                            help='The active level1 parent label',
                            default='active')
        parser.add_argument('-w', '--waitfor',
                            help='The waitfor label',
                            default='waitfor')
        parser.add_argument('-d', '--delay',
                            help='Specify the delay in seconds between syncs',
                            default=5, type=int)
        parser.add_argument('--debug', help='Enable debugging',
                            action='store_true')
        parser.add_argument('--inbox',
                            help='The method the Inbox project should '
                                 'be processed',
                            default='parallel', choices=['parallel', 'serial'])
        parser.add_argument('--parallel_suffix', default='.')
        parser.add_argument('--serial_suffix', default='_')
        parser.add_argument('--hide_future',
                            help='Hide future dated next actions until the '
                                 'specified number of days',
                            default=7, type=int)
        parser.add_argument('--onetime', help='Update Todoist once and exit',
                            action='store_true')
        self.args = parser.parse_args()

        # Set debug
        if self.args.debug:
            log_level = logging.DEBUG
        else:
            log_level = logging.INFO
        logging.basicConfig(level=log_level)

        # Check we have a API key
        if not self.args.api_key:
            logging.error('No API key set, exiting...')
            sys.exit(1)
コード例 #15
0
 def __init__(self):
     self.token = os.getenv('TOKEN')
     self.api = TodoistAPI(self.token)
     self.api.sync()
     self.project_id = None
コード例 #16
0
    47: "#808080",
    38: "#158fad",
    48: "#b8b8b8",
    39: "#14aaf5",
    49: "#ccac93"
}

print(
    "Esse script gera um gráfico com suas tarefas completadas por dia e coloridas\n"
    "de acordo com o projeto a que pertenciam em um dado período de interesse")

# Recebe token do usuário
token = input("\nInsira seu token de acesso: ")

# Autentica e sincroniza os dados do Todoist
api = TodoistAPI("a24619b4c0cae7ad1c1bf43bf9bd81a0588fdd76" if len(token) ==
                 0 else token)
api.sync()


# Ensina o Python a processar as datas
def process(date):
    words = [s.strip() for s in date.split("de")]
    day, month, year = int(words[0]), month_number[words[1].lower()[:3]], \
                       "20" + words[2][-2:] if len(words) == 3 else "2020"
    return "{}-{}-{}T00:00".format(year, month, day)


# Recebe e processa o intervalo desejado
since = process(input("> Desde a data: "))
until = process(input("> Até a data  : "))[:-5] + "23:59"
コード例 #17
0
from todoist.api import TodoistAPI
from datetime import date

api = TodoistAPI('API KEY')
api.sync()

current_date = str(date.today())
items = api.state["items"]

def CheckDateLess(specDate):
    splitDate = specDate.split('-')
    
    today = date.today()

    if((int(splitDate[0]) <= today.year) and ( int(splitDate[1]) <= today.month) and (int(splitDate[2]) < today.day)):
        return 1
    else:
        return 0

def ReadAllCurrent():
    current_task_name= []
    for i in range(len(items)):
        if (items[i]['due'] != None):
            if (items[i]['due']['date'] == current_date):
                current_task_name.append(items[i]['content'])
    return current_task_name

def ReadAllOverdue():
    overdue_task_name= []
    for i in range(len(items)):
        if (items[i]['due'] != None):
コード例 #18
0
import logging

import pandas as pd
from todoist.api import TodoistAPI
logging.basicConfig(level=logging.INFO)

LOGGER = logging.getLogger("main")

TODOIST_TOKEN = os.getenv('TODOIST_TOKEN')

if TODOIST_TOKEN is None:
    LOGGER.error("TODOIST_TOKEN env is not set")
    exit(1)

LOGGER.info("Syncing Todoist ...")
api = TodoistAPI(TODOIST_TOKEN)
api.sync()
LOGGER.info("Synced...")

# The API limits 100 activities to be retrieved per call, so a loop is needed

# Items are retrieved in descending order by date.
# offset indicates how many items should be skipped
activity_list = []
limit = 100
offset = 0

while True:
    LOGGER.info(f"Getting activities, batch {int((offset+100)/100)}")
    # API call, retrieving between 0 and 100 activities
    activities = api.activity.get(limit=limit, offset=offset)
コード例 #19
0
ファイル: nextaction.py プロジェクト: aaronforward/NextAction
def main():

    parser = argparse.ArgumentParser()
    parser.add_argument('-a', '--api_key', help='Todoist API Key')
    parser.add_argument('-l', '--label', help='The next action label to use', default='next_action')
    parser.add_argument('-d', '--delay', help='Specify the delay in seconds between syncs', default=5, type=int)
    parser.add_argument('--debug', help='Enable debugging', action='store_true')
    parser.add_argument('--inbox', help='The method the Inbox project should be processed',
                        default='parallel', choices=['parallel', 'serial'])
    parser.add_argument('--parallel_suffix', default='.')
    parser.add_argument('--serial_suffix', default='_')
    parser.add_argument('--hide_future', help='Hide future dated next actions until the specified number of days',
                        default=7, type=int)
    parser.add_argument('--onetime', help='Update Todoist once and exit', action='store_true')
    args = parser.parse_args()

    # Set debug
    if args.debug:
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO
    logging.basicConfig(level=log_level)

    # Check we have a API key
    if not args.api_key:
        logging.error('No API key set, exiting...')
        sys.exit(1)

    # Run the initial sync
    logging.debug('Connecting to the Todoist API')
    api = TodoistAPI(token=args.api_key)
    logging.debug('Syncing the current state from the API')
    api.sync(resource_types=['projects', 'labels', 'items'])

    # Check the next action label exists
    labels = api.labels.all(lambda x: x['name'] == args.label)
    if len(labels) > 0:
        label_id = labels[0]['id']
        logging.debug('Label %s found as label id %d', args.label, label_id)
    else:
        logging.error("Label %s doesn't exist, please create it or change TODOIST_NEXT_ACTION_LABEL.", args.label)
        sys.exit(1)

    def get_project_type(project_object):
        """Identifies how a project should be handled"""
        name = project_object['name'].strip()
        if project['name'] == 'Inbox':
            return args.inbox
        elif name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def get_item_type(item):
        """Identifies how a item with sub items should be handled"""
        name = item['content'].strip()
        if name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def add_label(item, label):
        if label not in item['labels']:
            labels = item['labels']
            logging.debug('Updating %s with label', item['content'])
            labels.append(label)
            api.items.update(item['id'], labels=labels)

    def remove_label(item, label):
        if label in item['labels']:
            labels = item['labels']
            logging.debug('Updating %s without label', item['content'])
            labels.remove(label)
            api.items.update(item['id'], labels=labels)

    # Main loop
    while True:
        try:
            api.sync(resource_types=['projects', 'labels', 'items'])
        except Exception as e:
            logging.exception('Error trying to sync with Todoist API: %s' % str(e))
        else:
            for project in api.projects.all():
                project_type = get_project_type(project)
                if project_type:
                    logging.debug('Project %s being processed as %s', project['name'], project_type)

                    items = sorted(api.items.all(lambda x: x['project_id'] == project['id']), key=lambda x: x['item_order'])

                    for item in items:

                        # If its too far in the future, remove the next_action tag and skip
                        if args.hide_future > 0 and 'due_date_utc' in item.data and item['due_date_utc'] is not None:
                            due_date = datetime.strptime(item['due_date_utc'], '%a %d %b %Y %H:%M:%S +0000')
                            future_diff = (due_date - datetime.utcnow()).total_seconds()
                            if future_diff >= (args.hide_future * 86400):
                                remove_label(item, label_id)
                                continue

                        item_type = get_item_type(item)
                        child_items = get_subitems(items, item)
                        if item_type:
                            logging.debug('Identified %s as %s type', item['content'], item_type)

                        if item_type or len(child_items) > 0:
                            # Process serial tagged items
                            if item_type == 'serial':
                                for idx, child_item in enumerate(child_items):
                                    if idx == 0:
                                        add_label(child_item, label_id)
                                    else:
                                        remove_label(child_item, label_id)
                            # Process parallel tagged items or untagged parents
                            else:
                                for child_item in child_items:
                                    add_label(child_item, label_id)

                            # Remove the label from the parent
                            remove_label(item, label_id)

                        # Process items as per project type on indent 1 if untagged
                        else:
                            if item['indent'] == 1:
                                if project_type == 'serial':
                                    if item['item_order'] == 1:
                                        add_label(item, label_id)
                                    else:
                                        remove_label(item, label_id)
                                elif project_type == 'parallel':
                                    add_label(item, label_id)

            logging.debug('%d changes queued for sync... commiting if needed', len(api.queue))
            if len(api.queue):
                api.commit()

        if args.onetime:
            break
        logging.debug('Sleeping for %d seconds', args.delay)
        time.sleep(args.delay)
コード例 #20
0
class Task:
    """Overall class to manage behavior of pushing generated tasks to Todoist."""
    def __init__(self):
        self.api = TodoistAPI(self.get_api())

        # Get a start time and slice the string into two variables to use work_start.
        self.start_working_time = input(
            "What time will you start studying? Please input as hh:mm\n")
        self.desired_cycles = int(
            input("How many study cycles would you like to do?\n"))
        hours = self.start_working_time[:2]
        minutes = self.start_working_time[3:5]

        # Get length of each cycle to calculate timedelta from start time.
        month_of_task = int(
            input("What month? Enter as a number. Leave empty for current\n")
            or datetime.now().month)
        day_of_task = int(
            input("On what day? Enter as a number.  Leave empty for current\n")
            or datetime.now().day)

        # Calc using user values for work/break length.
        self.work_start = datetime(datetime.now().year, month_of_task,
                                   day_of_task, int(hours), int(minutes))
        self.work_duration = timedelta(
            minutes=int(input("How long will you study each cycle?\n")))
        self.break_duration = timedelta(
            minutes=int(input("How long will your breaks be?\n")))

    @staticmethod
    def get_api():
        """Either uses input api and saves it for next time or reads api used last time from file."""
        user_api = input("Paste api token.\nLeave empty for last used:\n")
        while True:
            if len(user_api) == 0:
                with open('api_token.txt', 'r') as file_object:
                    return file_object.read()
            elif len(user_api) == 40:
                with open('api_token.txt', "w") as file_object:
                    file_object.write(user_api)
                    return user_api
            else:
                print(
                    "Please paste the token as raw data with no quotation marks or whitespace."
                )

    def find_inbox_id(self):
        """Finds the id of the default 'Inbox' project."""
        for project in self.api.state['projects']:
            if project['name'] == 'Inbox':
                return project['id']

    def make_task(self):
        """Run loop that adds a new task into Todoist for as many times as user specified."""
        current_cycles = 0
        while current_cycles < self.desired_cycles:
            work_cycle = self.work_start + (
                self.work_duration + self.break_duration) * current_cycles
            print(f"{work_cycle} - {work_cycle + self.work_duration} WORK")
            self.api.items.add(
                f"WORK - {work_cycle:%H:%M} - {work_cycle + self.work_duration:%H:%M}",
                project_id=self.find_inbox_id(),
                due={"string": work_cycle})
            break_cycle = self.work_start + self.work_duration + (
                self.work_duration + self.break_duration) * current_cycles
            print(f"{break_cycle} - {break_cycle + self.break_duration} BREAK")
            self.api.items.add(
                f"BREAK - {break_cycle:%H:%M} - {break_cycle + self.break_duration:%H:%M}",
                project_id=self.find_inbox_id(),
                due={"string": break_cycle})
            current_cycles += 1

        self.api.commit()
コード例 #21
0
ファイル: nextaction.py プロジェクト: timharton/NextAction
def main():
    """Main process function."""
    parser = argparse.ArgumentParser()
    parser.add_argument('-a', '--api_key', help='Todoist API Key')
    parser.add_argument('-l', '--label', help='The next action label to use', default='next_action')
    parser.add_argument('-d', '--delay', help='Specify the delay in seconds between syncs', default=5, type=int)
    parser.add_argument('--debug', help='Enable debugging', action='store_true')
    parser.add_argument('--inbox', help='The method the Inbox project should be processed',
                        default='parallel', choices=['parallel', 'serial', 'none'])
    parser.add_argument('--parallel_suffix', default='.')
    parser.add_argument('--serial_suffix', default='_')
    parser.add_argument('--hide_future', help='Hide future dated next actions until the specified number of days',
                        default=7, type=int)
    parser.add_argument('--hide_scheduled', help='', action='store_true')  # TODO: help
    parser.add_argument('--remove_label', help='Remove next action label from unmarked projects', action='store_true')
    parser.add_argument('--onetime', help='Update Todoist once and exit', action='store_true')
    parser.add_argument('--nocache', help='Disables caching data to disk for quicker syncing', action='store_true')
    args = parser.parse_args()

    # Set debug
    if args.debug:
        log_level = logging.DEBUG
    else:
        log_level = logging.INFO
    logging.basicConfig(level=log_level)

    # Check we have a API key
    if not args.api_key:
        logging.error('No API key set, exiting...')
        sys.exit(1)

    # Run the initial sync
    logging.debug('Connecting to the Todoist API')

    api_arguments = {'token': args.api_key}
    if args.nocache:
        logging.debug('Disabling local caching')
        api_arguments['cache'] = None

    api = TodoistAPI(**api_arguments)
    logging.debug('Syncing the current state from the API')
    api.sync()

    # Check the next action label exists
    labels = api.labels.all(lambda x: x['name'] == args.label)
    if len(labels) > 0:
        label_id = labels[0]['id']
        logging.debug('Label %s found as label id %d', args.label, label_id)
    else:
        logging.error("Label %s doesn't exist, please create it or change TODOIST_NEXT_ACTION_LABEL.", args.label)
        sys.exit(1)

    def get_project_type(project_object):
        """Identifies how a project should be handled."""
        name = project_object['name'].strip()
        if name == 'Inbox' and args.inbox != 'none':
            return args.inbox
        elif name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def get_item_type(item):
        """Identifies how a item with sub items should be handled."""
        name = item['content'].strip()
        if name[-1] == args.parallel_suffix:
            return 'parallel'
        elif name[-1] == args.serial_suffix:
            return 'serial'

    def add_label(item, label):
        if label not in item['labels']:
            logging.debug('Updating %s (%d) with label', item['content'], item['id'])
            labels = item['labels']
            labels.append(label)
            api.items.update(item['id'], labels=labels)

    def remove_label(item, label):
        if label in item['labels']:
            logging.debug('Updating %s (%d) without label', item['content'], item['id'])
            labels = item['labels']
            labels.remove(label)
            api.items.update(item['id'], labels=labels)

    # Main loop
    while True:
        try:
            api.sync()
        except Exception as e:
            logging.exception('Error trying to sync with Todoist API: %s' % str(e))
        else:
            for project in api.projects.all(lambda x: not x['is_deleted'] and not x['is_archived']):
                project_type = get_project_type(project)
                items = api.items.all(
                            lambda x: x['project_id'] == project['id']
                                      and not (x['checked'] or x['is_deleted'] or x['is_archived'])
                )
                if project_type:
                    logging.debug('Project %s being processed as %s', project['name'], project_type)

                    # Get all items for the project, sort by the item_order field.
                    items = sorted(
                        items,
                        key=lambda x: x['item_order']
                    )

                    for real_order, item in enumerate(filter(lambda x: x['indent'] == 1, items)):
                        item_type = get_item_type(item)

                        if item.data.get('due_date_utc'):
                            if args.hide_scheduled and not item_type:
                                remove_label(item, label_id)
                                continue

                            # If its too far in the future, remove the next_action tag and skip
                            if args.hide_future > 0:
                                due_date = datetime.strptime(item['due_date_utc'], '%a %d %b %Y %H:%M:%S +0000')
                                future_diff = (due_date - datetime.utcnow()).total_seconds()
                                if future_diff >= (args.hide_future * 86400):
                                    remove_label(item, label_id)
                                    continue

                        child_items = get_subitems(items, item)

                        def add_indent1_label():
                            if child_items:
                                remove_label(item, label_id)
                                add_label(child_items[0], label_id)
                                func = remove_label if item_type == 'serial' else add_label
                                for child_item in child_items[1:]:
                                    func(child_item, label_id)
                            else:
                                add_label(item, label_id)

                        def remove_indent1_label():
                            remove_label(item, label_id)
                            for child_item in child_items:
                                remove_label(child_item, label_id)

                        if project_type == 'serial':
                            if real_order == 0:
                                add_indent1_label()
                            else:
                                remove_indent1_label()
                        elif project_type == 'parallel':
                            add_indent1_label()

                elif args.remove_label:
                    for item in items:
                        remove_label(item, label_id)

            if len(api.queue):
                logging.debug('%d changes queued for sync... commiting to Todoist.', len(api.queue))
                api.commit()
            else:
                logging.debug('No changes queued, skipping sync.')

        # If onetime is set, exit after first execution.
        if args.onetime:
            break

        logging.debug('Sleeping for %d seconds', args.delay)
        time.sleep(args.delay)
コード例 #22
0
ファイル: todoist.py プロジェクト: yuanyewa/home-assistant
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the Todoist platform."""
    # Check token:
    token = config.get(CONF_TOKEN)

    # Look up IDs based on (lowercase) names.
    project_id_lookup = {}
    label_id_lookup = {}

    from todoist.api import TodoistAPI
    api = TodoistAPI(token)
    api.sync()

    # Setup devices:
    # Grab all projects.
    projects = api.state[PROJECTS]

    # Grab all labels
    labels = api.state[LABELS]

    # Add all Todoist-defined projects.
    project_devices = []
    for project in projects:
        # Project is an object, not a dict!
        # Because of that, we convert what we need to a dict.
        project_data = {CONF_NAME: project[NAME], CONF_ID: project[ID]}
        project_devices.append(
            TodoistProjectDevice(hass, project_data, labels, api))
        # Cache the names so we can easily look up name->ID.
        project_id_lookup[project[NAME].lower()] = project[ID]

    # Cache all label names
    for label in labels:
        label_id_lookup[label[NAME].lower()] = label[ID]

    # Check config for more projects.
    extra_projects = config.get(CONF_EXTRA_PROJECTS)
    for project in extra_projects:
        # Special filter: By date
        project_due_date = project.get(CONF_PROJECT_DUE_DATE)

        # Special filter: By label
        project_label_filter = project.get(CONF_PROJECT_LABEL_WHITELIST)

        # Special filter: By name
        # Names must be converted into IDs.
        project_name_filter = project.get(CONF_PROJECT_WHITELIST)
        project_id_filter = [
            project_id_lookup[project_name.lower()]
            for project_name in project_name_filter
        ]

        # Create the custom project and add it to the devices array.
        project_devices.append(
            TodoistProjectDevice(hass, project, labels, api, project_due_date,
                                 project_label_filter, project_id_filter))

    add_devices(project_devices)

    # Services:
    descriptions = load_yaml_config_file(
        os.path.join(os.path.dirname(__file__), 'services.yaml'))

    def handle_new_task(call):
        """Called when a user creates a new Todoist Task from HASS."""
        project_name = call.data[PROJECT_NAME]
        project_id = project_id_lookup[project_name]

        # Create the task
        item = api.items.add(call.data[CONTENT], project_id)

        if LABELS in call.data:
            task_labels = call.data[LABELS]
            label_ids = [
                label_id_lookup[label.lower()] for label in task_labels
            ]
            item.update(labels=label_ids)

        if PRIORITY in call.data:
            item.update(priority=call.data[PRIORITY])

        if DUE_DATE in call.data:
            due_date = dt.parse_datetime(call.data[DUE_DATE])
            if due_date is None:
                due = dt.parse_date(call.data[DUE_DATE])
                due_date = datetime(due.year, due.month, due.day)
            # Format it in the manner Todoist expects
            due_date = dt.as_utc(due_date)
            date_format = '%Y-%m-%dT%H:%M'
            due_date = datetime.strftime(due_date, date_format)
            item.update(due_date_utc=due_date)
        # Commit changes
        api.commit()
        _LOGGER.debug("Created Todoist task: %s", call.data[CONTENT])

    hass.services.register(DOMAIN,
                           SERVICE_NEW_TASK,
                           handle_new_task,
                           descriptions[DOMAIN][SERVICE_NEW_TASK],
                           schema=NEW_TASK_SERVICE_SCHEMA)
コード例 #23
0
class Sorter:
    def __init__(self, api_token, project_id):
        self.token = api_token
        self.api = TodoistAPI(api_token)
        self.api.sync()

        self.project_id = project_id
        self.dbfilename = 'Todoist.db'
        self.dbtableprefix = 'Sections_'
        self.dbtablename = self.dbtableprefix + str(project_id)

    def initialize_db(self):
        conn = sqlite3.connect(self.dbfilename)
        db = conn.cursor()
        query = 'CREATE TABLE IF NOT EXISTS "{}" ("item_project" INT, "item_content" TEXT, "item_section" INT, "last_updated" TEXT)'.format(
            self.dbtablename)
        db.execute(query)
        db.close()

    def get_section_name(self, section_id):
        sectionList = self.api.state['sections']
        for section in sectionList:
            if section['id'] == section_id:
                return section['name']
        # RETURN FALSE IF NO MATCH IS FOUND
        return False

    def capitalize_item(self, item_id):
        item_content = self.api.items.get_by_id(item_id)['content']
        if not item_content[0].isupper():
            new_content = item_content[0].upper() + item_content[1:]

            # WRITE UPDATED CONTENT TO TODOIST
            item = self.api.items.get_by_id(item_id)
            item.update(content=new_content)
            self.api.commit()

    def get_historic_section(self, item_id):
        item = self.api.items.get_by_id(item_id)

        self.initialize_db()
        conn = sqlite3.connect(self.dbfilename)
        selectQuery = "SELECT item_content, item_section FROM {} WHERE item_content = '{}' LIMIT 1".format(
            self.dbtablename, item['content'].lower())
        db = conn.cursor()
        result = db.execute(selectQuery).fetchone()
        db.close()
        conn.commit()
        if result is not None:
            return result[1]
        else:
            return None

    def learn(self):
        self.initialize_db()
        conn = sqlite3.connect(self.dbfilename)
        query = ""

        itemList = self.api.state['items']
        for item in itemList:
            timestamp = datetime.datetime.now().strftime(
                "%Y-%m-%d %H:%M")  # USED TO INSERT INTO DB WHEN UPDATING
            if item['project_id'] == self.project_id and item[
                    'section_id'] is not None:

                # GET HISTORIC SECTION
                historic_section = self.get_historic_section(item['id'])
                if historic_section == item['section_id']:  # NO UPDATE NEEDED
                    pass

                if historic_section is None:  # ADD ITEM TO DB
                    query = "INSERT INTO {} (item_project, item_content, item_section, last_updated) VALUES ({},'{}',{}, '{}')".format(
                        self.dbtablename, item['project_id'],
                        item['content'].lower(), item['section_id'], timestamp)

                if historic_section is not None and historic_section != item[
                        'section_id']:  # UPDATE CURRENT SECTION
                    query = "UPDATE {} SET item_section = {}, last_updated = '{}' WHERE item_content = '{}'".format(
                        self.dbtablename, item['section_id'], timestamp,
                        item['content'].lower())

                db = conn.cursor()
                db.execute(query)
                db.close()
                query = ""

        conn.commit()

    # def adjust_item_section_UNSUPPORTED(self, item_id):
    #     # TODO WRITE UPDATED CONTENT TO TODOIST
    #     if self.get_historic_section(item_id) is not None:
    #         item = self.api.items.get_by_id(item_id)
    #         item.move(parent_id=item_id)
    #         self.api.commit()

    def adjust_item_section(self, item_id):
        # USING MANUAL REQUESTS METHOD AS SECTIONS ARENT SUPPORTED IN CURRENT VERSION OF TODOIST SYNC API-LIBRARY
        state = uuid.uuid4()
        apiUrlSync = "https://api.todoist.com/sync/v8/sync"
        commands = '[{"type": "item_move", "uuid": "' + str(
            state) + '", "args": {"id": ' + str(
                item_id) + ', "section_id": ' + str(
                    self.get_historic_section(item_id)) + '}}]'

        payload = {"token": str(self.token), 'commands': commands}
        requests.post(apiUrlSync, data=payload).json()
コード例 #24
0
 def get_task(self, id):
     api = TodoistAPI('313f6bf203b35e7ac56e39561a80633e459c9c54')
     if api.items.get_by_id(id) != None:
         return True
     else:
         return False
コード例 #25
0
ファイル: ToDoist.py プロジェクト: manujosephv/MovieScraper
 def __init__(self):
     self.api = TodoistAPI(Config.TODOIST_API_KEY)
     self.api.sync()
     self.mt = MusicTools()
コード例 #26
0
ファイル: my_todoist.py プロジェクト: h-chauhan/django-th
class ServiceTodoist(ServicesMgr):
    """
        service Todoist
    """
    def __init__(self, token=None, **kwargs):
        super(ServiceTodoist, self).__init__(token, **kwargs)
        self.AUTH_URL = 'https://todoist.com/oauth/authorize'
        self.ACC_TOKEN = 'https://todoist.com/oauth/access_token'
        self.REQ_TOKEN = 'https://todoist.com/oauth/access_token'
        self.consumer_key = settings.TH_TODOIST_KEY['client_id']
        self.consumer_secret = settings.TH_TODOIST_KEY['client_secret']
        self.scope = 'task:add,data:read,data:read_write'
        self.service = 'ServiceTodoist'
        self.oauth = 'oauth2'
        if token:
            self.token = token
            self.todoist = TodoistAPI(token)

    def read_data(self, **kwargs):
        """
            get the data from the service
            as the pocket service does not have any date
            in its API linked to the note,
            add the triggered date to the dict data
            thus the service will be triggered when data will be found

            :param kwargs: contain keyword args : trigger_id at least
            :type kwargs: dict

            :rtype: list
        """
        trigger_id = kwargs.get('trigger_id')
        date_triggered = kwargs.get('date_triggered')
        data = []
        project_name = 'Main Project'
        items = self.todoist.sync()
        try:
            for item in items.get('items'):
                date_added = arrow.get(item.get('date_added'),
                                       'ddd DD MMM YYYY HH:mm:ss ZZ')
                if date_added > date_triggered:
                    for project in items.get('projects'):
                        if item.get('project_id') == project.get('id'):
                            project_name = project.get('name')
                    title = 'From TodoIst Project {0}:'.format(project_name)
                    data.append({
                        'title': title,
                        'content': item.get('content')
                    })

                    # digester
                    self.send_digest_event(trigger_id, title, '')

            cache.set('th_todoist_' + str(trigger_id), data)
        except AttributeError:
            logger.error(items)

        return data

    def save_data(self, trigger_id, **data):
        """
            let's save the data
            :param trigger_id: trigger ID from which to save data
            :param data: the data to check to be used and save
            :type trigger_id: int
            :type data:  dict
            :return: the status of the save statement
            :rtype: boolean
        """
        title, content = super(ServiceTodoist,
                               self).save_data(trigger_id, **data)

        if self.token:
            if title or content or data.get('link'):
                content = title + ' ' + content + ' ' + data.get('link')

                self.todoist.add_item(content)

                sentence = str('todoist {} created').format(data.get('link'))
                logger.debug(sentence)
                status = True
            else:
                status = False
        else:
            logger.critical("no token or link provided for "
                            "trigger ID {} ".format(trigger_id))
            status = False
        return status
コード例 #27
0
 def list_project_tasks(self, project_id):
     api_call = TodoistAPI(self.api_key)
     api_call.sync()
     for item in range(len(api_call.state['items'])):
         if api_call.state['items'][item].data['project_id'] == project_id:
             print(api_call.state['items'][item].data['content'])
コード例 #28
0
class syncManager:
    def __init__(self, todoist_token, notion_token, notion_settings_url):
        self.api = TodoistAPI(todoist_token)
        self.client = NotionClient(token_v2=notion_token)
        self.settings = self.client.get_collection_view(notion_settings_url)

        # extract and parse settings
        self.config = {}
        self.use_groups = False
        self.sync_completed_tasks = False
        self.sync_config()

        self.tasks = self.client.get_collection_view(
            "https://www.notion.so/" + self.config["Link to task database"])
        self.projects = self.client.get_collection_view(
            "https://www.notion.so/" + self.config["Link to project database"])
        self.labels = self.client.get_collection_view(
            "https://www.notion.so/" + self.config["Link to label database"])

        # initialize todoist api jsons
        self.old_sync = None
        self.new_sync = None
        self.old_commit = None
        self.new_commit = None
        self.last_notion_sync_time = helper.add_local_tz(
            datetime(2020, 1, 1, 0, 0, 0, 0))

        # taskManager.sync_notion_to_todoist(self, full_sync=True)

    def sync_todoist_api(self):
        self.old_sync = self.new_sync
        self.new_sync = self.api.sync()

    def commit_todoist_api(self):
        self.old_commit = self.new_commit
        self.new_commit = self.api.commit()

    def update_notion_sync_time(self):
        self.last_notion_sync_time = helper.add_local_tz(datetime.now())

    def sync_notion_tasks(self):
        taskManager.sync_notion_to_todoist(self)

    def _parse_label_columns(self):
        column_list = self.config['Label column name']
        column_dict = {}
        for item in column_list.replace(" ", "").split(","):
            key, value = item.split("=")
            column_dict[key] = value
        self.config["Input label string"] = self.config['Label column name']
        self.config['Label column name'] = column_dict

    def sync_config(self):
        self.config = {
            row.title: row.value
            for row in self.settings.collection.get_rows()
        }  # extract settings
        self._parse_label_columns()
        self.use_groups = True if self.config["Use groups"].lower() in [
            "true", "yes", "y", "t"
        ] else False
        self.sync_completed_tasks = True if self.config["Sync completed tasks"].lower() in \
                                            ["true", "yes", "y", "t"] else False
        self.config['Sync completed tasks'] = self.sync_completed_tasks
        self.config['Use groups'] = self.use_groups
        print("Sync configuration updated.")
コード例 #29
0
import pandas as pd
from todoist.api import TodoistAPI

api = TodoistAPI('df864d9cbf7b4e669e50bf626fa088eef855ff5e')
api.sync()

# .data attribute retrieves a python dictionary rather than todoist.models.Project
projects = [project.data for project in api.state['projects']]

# I can easily create a DataFrame on the 'projects' list of dicts
df_projects = pd.DataFrame(projects)

df_projects.head()

tasks = [task.data for task in api.state['items']]
df_tasks = pd.DataFrame(tasks)
df_tasks.head()

df_tasks['date_added'] = pd.to_datetime((
    pd.to_datetime(df_tasks['date_added'], utc=True).dt.tz_convert(
        'Europe/Budapest')  # my current timezone
    .dt.strftime("%Y-%m-%d %H:%M:%S")))  # easier to handle format

df_tasks['due_date_utc'] = pd.to_datetime((pd.to_datetime(
    df_tasks['due_date_utc'],
    utc=True).dt.tz_convert('Europe/Budapest').dt.strftime("%Y-%m-%d %H:%M:%S")
                                           ))

df_tasks['date_completed'] = pd.to_datetime((pd.to_datetime(
    df_tasks['date_completed'],
    utc=True).dt.tz_convert('Europe/Budapest').dt.strftime("%Y-%m-%d %H:%M:%S")
コード例 #30
0
 def __init__(self):
     self.api = TodoistAPI(get_token())
     self.api.sync()
コード例 #31
0
class Project:
    def __init__(self):
        self.token = os.getenv('TOKEN')
        self.api = TodoistAPI(self.token)
        self.api.sync()
        self.project_id = None

    def create_project(self, project_name: str):
        """
        Creates a new project on todoist
        :param project_name: The name of the project
        """
        project = self.api.projects.add(project_name)
        self.api.commit()
        print('Created project:')
        print(project)
        self.project_id = project.data['id']

    def remove_project(self):
        """
        Removes the current project
        """
        if self.project_id is None:
            print('No project Created or project has been deleted')
            return
        project = self.api.projects.get_by_id(self.project_id)
        project.delete()
        self.api.commit()

    def contains_task_with_message(self, message):
        """
        Checks if the current project has a task the given message
        :param message: The message to look for
        :return: True if it does, false otherwise
        """
        print(self.api.items.all())
        print('filtered')
        print(self.project_id)
        print(
            list(
                filter(lambda task: task['content'] == message,
                       self.api.items.all())))
        return len(
            list(
                filter(lambda task: task['content'] == message,
                       self.api.items.all()))) > 0

    def reopen_task_with_message(self, message):
        """
        Reopens the task with the given message
        :param message: The message to look for, assumes it exists
        """
        item_id = list(
            filter(
                lambda task: task['content'] == message and task['project_id']
                == self.project_id, self.api.items.all()))[0]['id']

        item = self.api.items.get_by_id(item_id)
        item.uncomplete()
        self.api.commit()

    def sync(self):
        """
        Syncs the API
        """
        self.api.sync()
        time.sleep(API_WAIT_TIME)
コード例 #32
0
unix_lib_path = os.path.expanduser("~/work/pa/PersonalAssistant")
win_lib_path = 'C:\\Users\\Petr\\Desktop\\HomeAutomation\\PersonalAssistant'


def is_unix():
    val = os.path.join('_', '_')
    return val == "_/_"


if is_unix():
    if unix_lib_path not in sys.path:
        sys.path.append(unix_lib_path)
else:
    if win_lib_path not in sys.path:
        sys.path.append(win_lib_path)

import lib.stack as palib
import pyutils
import resources

# ----------------------------------------------------------------------------------------------------------------------
# 2) class TodoistAPI

from todoist.api import TodoistAPI
api = TodoistAPI(pyutils.get_token())

# ----------------------------------------------------------------------------------------------------------------------
# 3) class PersonalAssistant

pa = palib.PersonalAssistant()
コード例 #33
0
from dev.tasks import create_jira_admin_task
from dev.tasks import create_branch_subtask
from dev.tasks import create_merge_subtask
from dev.tasks import create_subtask
from dev.tasks import create_terraform_merge_subtask
from dev.ui import print_heading
from dev.ui import ui_create_root_dev_task
from dev.ui import ui_create_subtasks
from dev.ui import ui_get_jira_reference

from todoist.api import TodoistAPI
from labels import get_label_ids
from projects import ui_select_project

api_token = os.getenv('TODOIST_API_TOKEN')
api = TodoistAPI(api_token)
api.sync()


def ui_get_terraform_modules():
    print_heading("Module Selection")
    modules = [
        "terraform_cms_dns", "terraform_dcf_entrypoint",
        "terraform_dcf_networking"
    ]
    print("The following modules are available to work with:")
    count = 1
    for module in modules:
        print("{num}. {name}".format(num=count, name=module))
        count += 1
    print("Select a module or use a comma separated list to select multiple")
コード例 #34
0
from todoist.api import TodoistAPI
import sys

token = sys.argv[1]
api = TodoistAPI(token)
api.sync()

api.user.update(theme=3)


def enable_dark_mode():
    api.user.update(theme=11)


def enable_light_mode():
    api.user.update(theme=6)


def choose_theme():
    themeName = sys.argv[2]
    if themeName == 'dark':
        enable_dark_mode()
    else:
        enable_light_mode()


if __name__ == '__main__':
    choose_theme()
    api.commit()
コード例 #35
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Todoist platform."""
    token = config.get(CONF_TOKEN)

    # Look up IDs based on (lowercase) names.
    project_id_lookup = {}
    label_id_lookup = {}

    api = TodoistAPI(token)
    api.sync()

    # Setup devices:
    # Grab all projects.
    projects = api.state[PROJECTS]

    # Grab all labels
    labels = api.state[LABELS]

    # Add all Todoist-defined projects.
    project_devices = []
    for project in projects:
        # Project is an object, not a dict!
        # Because of that, we convert what we need to a dict.
        project_data = {CONF_NAME: project[NAME], CONF_ID: project[ID]}
        project_devices.append(
            TodoistProjectDevice(hass, project_data, labels, api))
        # Cache the names so we can easily look up name->ID.
        project_id_lookup[project[NAME].lower()] = project[ID]

    # Cache all label names
    for label in labels:
        label_id_lookup[label[NAME].lower()] = label[ID]

    # Check config for more projects.
    extra_projects = config[CONF_EXTRA_PROJECTS]
    for project in extra_projects:
        # Special filter: By date
        project_due_date = project.get(CONF_PROJECT_DUE_DATE)

        # Special filter: By label
        project_label_filter = project[CONF_PROJECT_LABEL_WHITELIST]

        # Special filter: By name
        # Names must be converted into IDs.
        project_name_filter = project[CONF_PROJECT_WHITELIST]
        project_id_filter = [
            project_id_lookup[project_name.lower()]
            for project_name in project_name_filter
        ]

        # Create the custom project and add it to the devices array.
        project_devices.append(
            TodoistProjectDevice(
                hass,
                project,
                labels,
                api,
                project_due_date,
                project_label_filter,
                project_id_filter,
            ))

    add_entities(project_devices)

    def handle_new_task(call):
        """Call when a user creates a new Todoist Task from Home Assistant."""
        project_name = call.data[PROJECT_NAME]
        project_id = project_id_lookup[project_name]

        # Create the task
        item = api.items.add(call.data[CONTENT], project_id=project_id)

        if LABELS in call.data:
            task_labels = call.data[LABELS]
            label_ids = [
                label_id_lookup[label.lower()] for label in task_labels
            ]
            item.update(labels=label_ids)

        if PRIORITY in call.data:
            item.update(priority=call.data[PRIORITY])

        _due: dict = {}
        if DUE_DATE_STRING in call.data:
            _due["string"] = call.data[DUE_DATE_STRING]

        if DUE_DATE_LANG in call.data:
            _due["lang"] = call.data[DUE_DATE_LANG]

        if DUE_DATE in call.data:
            due_date = dt.parse_datetime(call.data[DUE_DATE])
            if due_date is None:
                due = dt.parse_date(call.data[DUE_DATE])
                due_date = datetime(due.year, due.month, due.day)
            # Format it in the manner Todoist expects
            due_date = dt.as_utc(due_date)
            date_format = "%Y-%m-%dT%H:%M%S"
            due_date = datetime.strftime(due_date, date_format)
            _due["date"] = due_date

        if _due:
            item.update(due=_due)

        _reminder_due: dict = {}
        if REMINDER_DATE_STRING in call.data:
            _reminder_due["string"] = call.data[REMINDER_DATE_STRING]

        if REMINDER_DATE_LANG in call.data:
            _reminder_due["lang"] = call.data[REMINDER_DATE_LANG]

        if REMINDER_DATE in call.data:
            due_date = dt.parse_datetime(call.data[REMINDER_DATE])
            if due_date is None:
                due = dt.parse_date(call.data[REMINDER_DATE])
                due_date = datetime(due.year, due.month, due.day)
            # Format it in the manner Todoist expects
            due_date = dt.as_utc(due_date)
            date_format = "%Y-%m-%dT%H:%M:%S"
            due_date = datetime.strftime(due_date, date_format)
            _reminder_due["date"] = due_date

        if _reminder_due:
            api.reminders.add(item["id"], due=_reminder_due)

        # Commit changes
        api.commit()
        _LOGGER.debug("Created Todoist task: %s", call.data[CONTENT])

    hass.services.register(DOMAIN,
                           SERVICE_NEW_TASK,
                           handle_new_task,
                           schema=NEW_TASK_SERVICE_SCHEMA)
コード例 #36
0
ファイル: main.py プロジェクト: inamuu/todoist-tools
import argparse
import io
import json
import os
import requests
import sys
from todoist.api import TodoistAPI
from os.path import join, dirname
from dotenv import load_dotenv

dotenv_path = join(dirname(__file__), '.env')
load_dotenv(dotenv_path)
api = TodoistAPI(os.environ.get("APITOKEN"))
api.sync()


def projects():
    list = api.state['projects']
    print('### プロジェクト一覧')
    for name in list:
        print(name['name'])


def tasks(args):
    list = api.state['projects']
    for projects_id in list:
        if projects_id['name'] == args.tasks:
            tasks_project_id = projects_id['id']
            break

    ## 例外キャッチ: tasks_project_idがセットされていなければ終了する
コード例 #37
0
ファイル: ist_1.py プロジェクト: isZengwen/todoist-python
from todoist.api import TodoistAPI
api = TodoistAPI('d9deec7ba39852d370168e80ebb66e4b60d927df')
api.sync()
#print(api.state['projects'])
# project1 = api.projects.add('Project1')
""" api.commit()
print(project1) """
project1 = api.projects.add('Project1')
task1 = api.items.add('Task1', project_id=project1['id'])
task2 = api.items.add('Task2', project_id=project1['id'])
api.commit()
コード例 #38
0
from todoist.api import TodoistAPI

# Load environment variables
load_dotenv()

# Initialize app
app = Flask(__name__)

# Set SQLAlchemy databse URI
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DATABASE_URL")

# Initialize db
db = SQLAlchemy(app)

# Create Todoist API client
api = TodoistAPI(os.environ.get("TODOIST_API_TOKEN"))


class Item(db.Model):
    __tablename__ = "items"
    project_id: int = db.Column(db.Integer)
    responsible_uid: int = db.Column(db.Integer)
    section_id: int = db.Column(db.Integer)
    sync_id: int = db.Column(db.Integer)
    user_id: int = db.Column(db.Integer)
    added_by_uid: int = db.Column(db.Integer)
    assigned_by_uid: int = db.Column(db.Integer)
    checked: int = db.Column(db.Integer)
    child_order: int = db.Column(db.Integer)
    collapsed: int = db.Column(db.Integer)
    content: str = db.Column(db.String)
コード例 #39
0
ファイル: todoist.py プロジェクト: lexam79/home-assistant
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Todoist platform."""
    token = config.get(CONF_TOKEN)

    # Look up IDs based on (lowercase) names.
    project_id_lookup = {}
    label_id_lookup = {}

    from todoist.api import TodoistAPI
    api = TodoistAPI(token)
    api.sync()

    # Setup devices:
    # Grab all projects.
    projects = api.state[PROJECTS]

    # Grab all labels
    labels = api.state[LABELS]

    # Add all Todoist-defined projects.
    project_devices = []
    for project in projects:
        # Project is an object, not a dict!
        # Because of that, we convert what we need to a dict.
        project_data = {
            CONF_NAME: project[NAME],
            CONF_ID: project[ID]
        }
        project_devices.append(
            TodoistProjectDevice(hass, project_data, labels, api)
        )
        # Cache the names so we can easily look up name->ID.
        project_id_lookup[project[NAME].lower()] = project[ID]

    # Cache all label names
    for label in labels:
        label_id_lookup[label[NAME].lower()] = label[ID]

    # Check config for more projects.
    extra_projects = config.get(CONF_EXTRA_PROJECTS)
    for project in extra_projects:
        # Special filter: By date
        project_due_date = project.get(CONF_PROJECT_DUE_DATE)

        # Special filter: By label
        project_label_filter = project.get(CONF_PROJECT_LABEL_WHITELIST)

        # Special filter: By name
        # Names must be converted into IDs.
        project_name_filter = project.get(CONF_PROJECT_WHITELIST)
        project_id_filter = [
            project_id_lookup[project_name.lower()]
            for project_name in project_name_filter]

        # Create the custom project and add it to the devices array.
        project_devices.append(
            TodoistProjectDevice(
                hass, project, labels, api, project_due_date,
                project_label_filter, project_id_filter
            )
        )

    add_devices(project_devices)

    def handle_new_task(call):
        """Call when a user creates a new Todoist Task from HASS."""
        project_name = call.data[PROJECT_NAME]
        project_id = project_id_lookup[project_name]

        # Create the task
        item = api.items.add(call.data[CONTENT], project_id)

        if LABELS in call.data:
            task_labels = call.data[LABELS]
            label_ids = [
                label_id_lookup[label.lower()]
                for label in task_labels]
            item.update(labels=label_ids)

        if PRIORITY in call.data:
            item.update(priority=call.data[PRIORITY])

        if DUE_DATE in call.data:
            due_date = dt.parse_datetime(call.data[DUE_DATE])
            if due_date is None:
                due = dt.parse_date(call.data[DUE_DATE])
                due_date = datetime(due.year, due.month, due.day)
            # Format it in the manner Todoist expects
            due_date = dt.as_utc(due_date)
            date_format = '%Y-%m-%dT%H:%M'
            due_date = datetime.strftime(due_date, date_format)
            item.update(due_date_utc=due_date)
        # Commit changes
        api.commit()
        _LOGGER.debug("Created Todoist task: %s", call.data[CONTENT])

    hass.services.register(DOMAIN, SERVICE_NEW_TASK, handle_new_task,
                           schema=NEW_TASK_SERVICE_SCHEMA)
コード例 #40
0
ファイル: my_todoist.py プロジェクト: Koenma413/django-th
class ServiceTodoist(ServicesMgr):

    def __init__(self, token=None, **kwargs):
        super(ServiceTodoist, self).__init__(token, **kwargs)
        self.AUTH_URL = 'https://todoist.com/oauth/authorize'
        self.ACC_TOKEN = 'https://todoist.com/oauth/access_token'
        self.REQ_TOKEN = 'https://todoist.com/oauth/access_token'
        self.consumer_key = settings.TH_TODOIST['client_id']
        self.consumer_secret = settings.TH_TODOIST['client_secret']
        self.scope = 'task:add,data:read,data:read_write'
        self.service = 'ServiceTodoist'
        self.oauth = 'oauth2'
        if token:
            self.token = token
            self.todoist = TodoistAPI(token)

    def read_data(self, **kwargs):
        """
            get the data from the service
            as the pocket service does not have any date
            in its API linked to the note,
            add the triggered date to the dict data
            thus the service will be triggered when data will be found

            :param kwargs: contain keyword args : trigger_id at least
            :type kwargs: dict

            :rtype: list
        """
        trigger_id = kwargs.get('trigger_id')
        date_triggered = kwargs.get('date_triggered')
        data = []
        project_name = 'Main Project'
        items = self.todoist.sync()
        for item in items.get('items'):
            date_added = arrow.get(item.get('date_added'),
                                   'ddd DD MMM YYYY HH:mm:ss ZZ')
            if date_added > date_triggered:
                for project in items.get('projects'):
                    if item.get('project_id') == project.get('id'):
                        project_name = project.get('name')
                data.append({'title': "From TodoIst Project {0}"
                                      ":".format(project_name),
                             'content': item.get('content')})
        cache.set('th_todoist_' + str(trigger_id), data)
        return data

    def save_data(self, trigger_id, **data):
        """
            let's save the data
            :param trigger_id: trigger ID from which to save data
            :param data: the data to check to be used and save
            :type trigger_id: int
            :type data:  dict
            :return: the status of the save statement
            :rtype: boolean
        """
        kwargs = {}

        title, content = super(ServiceTodoist, self).save_data(trigger_id,
                                                               data, **kwargs)

        if self.token:
            if title or content or \
                            (data.get('link') and len(data.get('link'))) > 0:
                content = title + ' ' + content + ' ' + data.get('link')

                self.todoist.add_item(content)

                sentence = str('todoist {} created').format(data.get('link'))
                logger.debug(sentence)
                status = True
            else:
                status = False
        else:
            logger.critical("no token or link provided for "
                            "trigger ID {} ".format(trigger_id))
            status = False
        return status