Пример #1
0
    def test_stop_simple(self):
        # empty time entry raises an exception
        self.assertRaises(Exception, self.entry.stop)

        # non-running entry raises an exception
        self.entry.set('duration', 10)
        self.assertRaises(Exception, self.entry.stop)

        # missing an id raises an exception
        self.entry.set('duration', -10)
        self.assertRaises(Exception, self.entry.stop)

        # start an entry now
        self.entry = toggl.TimeEntry(description=desc('stop'))
        self.entry.start()

        # find it
        entry = self.find_time_entry(desc('stop'))
        self.assertIsNotNone(entry)

        # stop it
        entry.stop()

        # find it again
        entry = self.find_time_entry(desc('stop'))

        # make sure duration is positive. we can't be more specific because
        # we don't know the lag between us and toggl.
        self.assertGreaterEqual(entry.get('duration'), 0)
Пример #2
0
def resync_to_toggl(session, date_start, date_end):
    q = session.query(entry, toggl_id_map)
    if date_start:
        q = q.filter(entry.end_time >= totimestamp(date_start))
    if date_end:
        q = q.filter(entry.start_time <= totimestamp(date_end))
    q = q.filter(entry.id == toggl_id_map.entry_id)
    q = q.order_by(sqlalchemy.desc(entry.start_time))
    for result in q:
        e = result.entry
        e_map = result.toggl_id_map
        tags = [w for w in e.description.split() if w and w[0] in '+@']
        project = get_project(e.sheet, [tag[1:] for tag in tags if tag.startswith('+')])
        if project is None:
            logging.warning("Could not work out project name for %s: not updating", e.description)
            continue
        toggl_data = {'description': e.description, 'pid': project['id'], 'created_with': 'tb-toggl',
                      'start': fd(e.start), 'stop': fd(e.end), 'duration': e.duration.seconds,
                      'tags': tags, 'id': e_map.toggl_id}
        toggl_entry = toggl.TimeEntry(data_dict=toggl_data)
        toggl_entry.data['create_with'] = 'tb-toggl'
        try:
            r = toggl.toggl("%s/time_entries/%s" % (toggl.TOGGL_URL, toggl_entry.data['id']), 'put', data=toggl_entry.json())
        except Exception, error:
            logging.error("Error synchronizing: %s with data %r", error, toggl_data)
            continue
        toggl_dict = json.loads(r)["data"]
        toggl_id, toggl_at = toggl_dict['id'], toggl_dict['at']
        if toggl_id != e_map.toggl_id:
            logging.warning("map mismatch: %r %r", toggl_dict, e_map)
        else:
            e_map.toggl_at = toggl_at
            logging.info("Updated toggl id %s from entry %s (%s to %s) at %s: %s", toggl_id, e.id, e.start, e.end, toggl_at, e.description)
        session.commit()
Пример #3
0
def send_to_toggl(session, date_start, date_end):
    q = session.query(entry)
    if date_start:
        q = q.filter(entry.end_time >= totimestamp(date_start))
    if date_end:
        q = q.filter(entry.start_time <= totimestamp(date_end))
    synced_entries = session.query(toggl_id_map.entry_id)
    q = q.filter(~entry.id.in_(synced_entries))
    q = q.order_by(sqlalchemy.desc(entry.start_time))
    for e in q:
        if e.description is None:
            logging.warning("Entry id %s from %s to %s has no description: not adding", e.id, e.start, e.end)
            continue
        tags = [w for w in e.description.split() if w and w[0] in '+@']
        project = get_project(e.sheet, [tag[1:] for tag in tags if tag.startswith('+')])
        if project is None:
            logging.warning("Could not work out project name for id %s (%s to %s) - description %s: not adding", e.id, e.start, e.end, e.description)
            continue
        toggl_data = {'description': e.description, 'pid': project['id'], 'start': fd(e.start), 'stop': fd(e.end), 'duration': e.duration.seconds, 'tags': tags}
        toggl_entry = toggl.TimeEntry(data_dict=toggl_data)
        toggl_entry.data['create_with'] = 'tb-toggl'
        try:
            r = toggl_entry.add()
        except Exception, error:
            logging.error("Error synchronizing: %s with data %r", error, toggl_data)
            continue
        if r is None:
            logging.error("Error adding (None returned): %r", toggl_data)
            continue
        toggl_dict = json.loads(r)["data"]
        toggl_id, toggl_at = toggl_dict['id'], toggl_dict['at']
        new_map = toggl_id_map(entry_id=e.id, toggl_id=toggl_id, toggl_at=toggl_at)
        session.add(new_map)
        session.commit()
        logging.info("Mapped entry %s (%s to %s) to toggl id %s: %s", e.id, e.start, e.end, toggl_id, e.description)
Пример #4
0
    def test_start_simple(self):
        # test with simpliest entry
        self.entry = toggl.TimeEntry(description=desc('start'))
        self.entry.start()
        orig_start = self.entry.get('start')

        # fetch the entry from toggl and compare with what we created
        entry = self.find_time_entry(desc('start'))
        self.assertIsNotNone(entry)
Пример #5
0
    def test_start_simple(self):
        # empty time entry raises an exception
        self.assertRaises(Exception, self.entry.start)

        # test with simpliest entry
        self.entry = toggl.TimeEntry(description=desc('start'))
        self.entry.start()
        orig_duration = int(self.entry.get('duration'))
        entry = self.find_time_entry(desc('start'))
        self.assertIsNotNone(entry)
        # round duration to nearest integer
        self.assertEqual(entry.get('duration'), orig_duration)
Пример #6
0
    def test_start_complex(self):
        # test with preset start time one hour ago UTC
        one_hour_ago = pytz.UTC.localize(datetime.datetime.utcnow() - datetime.timedelta(hours=1))
        self.entry = toggl.TimeEntry(description=desc('start2'),
            start_time=one_hour_ago)
        self.entry.start()
        orig_duration = self.entry.get('duration')

        # see what toggl has
        entry = self.find_time_entry(desc('start2'))
        self.assertIsNotNone(entry)

        # toggl duration should be 1 hour
        self.assertGreaterEqual(entry.normalized_duration(), 3600)
Пример #7
0
    def test_add(self):
        # time entry has no data, raises an exception
        self.assertRaises(Exception, self.entry.add)

        # create basic entry and add it
        start_time = toggl.DateAndTime().now()
        self.entry = toggl.TimeEntry(description=desc('add'),
            start_time=start_time, duration=10)
        self.entry.add()

        # make sure it shows up in the list
        entry = self.find_time_entry(desc('add'))
        self.assertIsNotNone(entry)
        self.assertEquals(entry.get('duration'), 10)
Пример #8
0
    def test_delete(self):
        # start a time entry
        self.entry = toggl.TimeEntry(description=desc('delete'))
        self.entry.start()

        # deleting an entry without an id is an error
        self.assertRaises(Exception, self.entry.delete)

        # make sure it shows up in the list, this also fetches the id
        entry = self.find_time_entry(desc('delete'))
        self.assertIsNotNone(entry)

        # delete it
        entry.delete()

        # make sure it shows up in the list
        entry = self.find_time_entry(desc('delete'))
        self.assertIsNone(entry)
Пример #9
0
    def test_stop_complex(self):
        # start an entry now
        self.entry = toggl.TimeEntry(description=desc('stop2'))
        self.entry.start()

        # find it
        entry = self.find_time_entry(desc('stop2'))
        self.assertIsNotNone(entry)

        # stop it an hour from now
        one_hour_ahead = pytz.UTC.localize(datetime.datetime.utcnow() + datetime.timedelta(hours=1))
        entry.stop(one_hour_ahead)

        # find it again
        entry = self.find_time_entry(desc('stop2'))
        self.assertIsNotNone(entry)

        # make sure duration is at least 1 hour (3600 seconds)
        self.assertGreaterEqual(entry.get('duration'), 3600)
Пример #10
0
 def setUp(self):
     self.entry = toggl.TimeEntry()
     # force timezone to be UTC
     toggl.DateAndTime.tz = pytz.UTC
Пример #11
0
def deserialize_entries(dicts):
    '''Deserialize a list of dicts into a list of TimeEntries'''
    return [toggl.TimeEntry(d) for d in dicts]