GithubHelp home page GithubHelp logo

todoist-habitrpg's Introduction

Todist - HabitRPG sync

Build Status

This is a small utility to help you keep your Todoist tasks in sync with HabitRPG.

Installation

Ensure that you have NodeJS installed.

Then run: npm install -g todoist-habitrpg

Windows Troubleshooting

Currently the Windows NodeJS installer has a bug in it. If you encounter an Error: ENOENT, stat 'C:\Users\.....' error, just create a folder at the path specified and re-run the above command.

Running

From the terminal or command prompt enter the command below and replace habitRpgUserId, habitRpgApiToken, and todoistApiToken with the correct values. You can find directions on how to find these values in the Locating Your API Tokens section.

todoist-habitrpg -u habitRpgUserId -t habitRpgApiToken -a todoistApiToken

Locating your API Tokens

HabitRPG

Your User ID (habitRpgUserId) and API Token (habitRpgApiToken) can be located at your HabitRPG settings page.

Todoist

Your API Token (todoistApiToken) can be located by following these steps:

  1. Login to your account at todoist.com
  2. Click the "Gear" icon in the top right corner
  3. Click "Todoist Settings"
  4. Click the "Account" header inside the modal.
  5. Your API Token is located on this page.

Choosing the directory where the sync history is stored

Pass a -f flag followed by the directory where you want your file to be stored, relative to your home directory. For example, if you want the json file stored in ~/foo/bar/.todoist-habitrpg.json, you'd write the following at the end of your terminal command

-f ~/foo/bar

Assigning Attribute Labels

Once you've reached level 10 in HabitRPG, you start gaining skill points and can choose to allocate those skill points based on the kind of task you do. You can choose what kind of task it is by applying labels in Todoist. Below is a list of valid labels for each attribute.

Attribute Name Valid Labels
Strength str, strength, physical, phy
Intelligence int, intelligence, mental, men
Constitution con, constitution, social, soc
Perception per, perception, other, oth

If more than one valid label is assigned to a task in todoist, the first valid label will be assigned to the task in HabitRPG.

Updating to new versions

Periodically new versions will be published. You can install these updates with the command below.

npm update -g todoist-habitrpg

Command Line Help

todoist-habitrpg --help

Cron Usage - Linux/Mac Only

I would recommend setting this up as a cron job for automatic syncing.

  1. crontab -e
  2. Set your $HOME variable: HOME=/home/username
  3. */10 * * * * todoist-habitrpg -u habitRpgUserId -t habitRpgApiToken -a todoistApiToken
  4. Verify it was saved with crontab -l

Troubleshooting: If this doesn't work for you, please use absolute paths or adjust the PATH for your cron.

Current Limitations

  • Only supports syncing from Todoist -> HabitRPG.
  • Only supports basic task syncing. Subtasks get synced as a toplevel task in HabitRPG
  • Sync History file is hardcoded to be at $HOME/.todoist-habitrpg.json

Roadmap

  • Support Windows
  • Support specifying where the sync history file is.
  • If a task has a subtask, then create the item on HabitRPG as a checklist
  • If a task belongs to a project, on HabitRPG create a tag with that project name
  • If a task is a daily task then create it as a daily on HabitRPG
  • If a tasks is a repeating task then create it as a habit on HabitRPG
  • Support syncing from HabitRPG -> Todoist
  • Write up instructions on setting this up to run with the Windows Task Scheduler

todoist-habitrpg's People

Contributors

crookedneighbor avatar kusold avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

todoist-habitrpg's Issues

Cron not triggering syncing

I have followed the Cron Usage section and I can't seem to get this tool working. When I run the command directly, it has no problem running and returning a successful sync message, but when cron attempts to run the command, nothing happens. I've confirmed in the syslog that the following has run

Dec 20 04:40:01 ilp CRON[4074]: (laike) CMD (todoist-habitrpg -u _-_-****_-__-***** -t ******-__-__-__-_***** -a ************ -f ~/HabitRPG)

but nothing is actually happening. I've censored out the API keys of course. I've tried to swap the command for a bash script to see if I can get it to return some error message or anything, but I can't seem to get anything back. I am stumped.

Attribute labels not syncing

I went through and tagged all my tasks in todoist as per Assigning Attribute Labels in the README:

  • physical
  • mental
  • social
  • other

All tasks created in Habitica were still tagged Strength. Even deleted all tasks in Habitica and removed the sync history file to recreate everything. Still no attributes set.

Tried renaming labels in Todoist and now all syncs crash:
/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/lib/apiv3.js:189 if(apiVersion === 'v2' && res.body) { ^ TypeError: Cannot read property 'body' of undefined at formatResponse (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/lib/apiv3.js:189:32) at /usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/lib/apiv3.js:61:7 at Request.callback (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/node_modules/superagent/lib/node/index.js:660:30) at ClientRequest.<anonymous> (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/node_modules/superagent/lib/node/index.js:628:10) at ClientRequest.emit (events.js:95:17) at CleartextStream.socketErrorListener (http.js:1547:9) at CleartextStream.emit (events.js:95:17) at Socket.onerror (tls.js:1440:17) at Socket.emit (events.js:117:20) at net.js:440:14

Slight Problem with Dailies

Just discovered that if you edit a completed task that is synced as Daily on Habit, it'll uncheck it on Habit. Here's what I did:

  1. Marked task as complete on Todoist, synced to Habit
  2. Decided to add a label to task in Todoist
  3. Todoist-Habitrpg saw that the task had been updated and synced it to Habit, including the new unchecked status.

@kusold Do you have ideas for how to handle this?

Debug output includes API keys

Ummm... I have debug output from a error, but it contains all my API keys so I can't post it? Perhaps those should be censored from the output?

Yearly todoist entry created as daily in habitica

I have a couple of yearly tasks in todoist, something like Pay Insurance every Sept 28. Each of them sync into Habitica a daily, not a to-do entry.

I also tried Pay Insurance yearly on Sept 28 but they also appeared as a daily.

Give Outlook and Postbox mail tasks human-readable titles

Hi there. I just installed the Todoist Outlook extension today at work and noticed that todoist-habitrpg syncs these but the title of the task goes all wonky. If possible, I would like to request an enhancement for a future version that strips the Outlook markup from the title so it is more legible in the HabitRPG to-do list. Thank you.

Here is the data from one of mine in case it helps for testing purposes.

{
  "text": "[[outlook=id3=aWQ9MDAwMDAwMDBCOTYzOTQ4N0Y2RDQ2QTQ5OTVBMzM4QjdEMTdDQ0U2NzA3MDA1Q0I1QUY4OTNFQjYyRDRCOEVEOTQ4NkI2QURCNjlERTAwMDAwMDg4Q0Q3NzAwMDA1Q0I1QUY4OTNFQjYyRDRCOEVEOTQ4NkI2QURCNjlERTAwMDAwMEFGNTAyQjAwMDA7bWlkPTxGM0UxNERBOUM5MTQ4NzRGODQ3RjkwRDNFRkJBRkYzQzE1QjE4Q0BNRVItRVhDSDIubmFwaWVyLmFjLnVrPg==, Update doc: Procedure documents - External's access to libraries - Membership Cards]]",
  "challenge": {},
  "attribute": "str",
  "priority": 1,
  "value": 0,
  "tags": {},
  "notes": "",
  "dateCreated": "2015-01-16T15:01:12.000Z",
  "id": "eaca11ea-c772-45ce-ae71-2c8c88d0904d",
  "checklist": [],
  "collapseChecklist": false,
  "completed": false,
  "type": "todo"
}

ETA: the Todoist Postbox extension does the same thing, only with [[thunderbird]].

Daily or to-do automatically turned into a habit and deleted name

Hi, all. I'm sorry to open another issue, but here I am.

I created either a daily or to-do today that was somehow turned into a habit. I have been revamping my tasks in Todoist today so I'm not sure which one it is, and its name was deleted. Here is its info:

{
  "text": "5baf4c65-ba28-425f-9932-ded840b97665",
  "challenge": {},
  "attribute": "str",
  "priority": 1,
  "value": 1,
  "tags": {},
  "notes": "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task.",
  "dateCreated": "2015-01-15T15:29:05.273Z",
  "id": "5baf4c65-ba28-425f-9932-ded840b97665",
  "down": true,
  "up": true,
  "history": [
    {
      "date": 1421335745282,
      "value": 1
    }
  ],
  "type": "habit"
}

I'm not using any "third-party service" aside from this one so I'm not sure what happened here.

Sync not working (as of Sept 7 2017)

I have the issue where I can successfully run the sync, and get a "Sync completed successfully" message, but nothing on Habitica changes. I run this every 10 minutes with crontab and the last change on Habitica was on Sept 7th, so it appears to have stopped working around that time.

Any ideas?

Convert Todoist Text Formatting

Todoist has some text formatting options, some of which are actually documented. In addition to bold, italic and links, you can also highlight %(hl) foo% and underline %(u) bar%.

Markdown doesn't do underlines, I don't think, but highlighting could be used for code.

Would be great to convert bold, italic, highlighting and links from Todoist's way of doing them to markdown, so the formatting persists in Habit RPG.

Here's a checklist of things:

  • Highlights %(hl) foo%
  • Underlines %(u) bar%
  • Links: http://google.com/ (Google)
  • Italic: __Italic text__
  • Bold: !!Bold text!!
  • Outlook Link: [[outlook=id3=aWQ9MDAwMDAwMDBCOTYzOTQ4N0Y2RDQ2QTQ5OTVBMzM4QjdEMTdDQ0U2NzA3MDA1Q0I1QUY4OTNFQjYyRDRCOEVEOTQ4NkI2QURCNjlERTAwMDAwMDg4Q0Q3NzAwMDA1Q0I1QUY4OTNFQjYyRDRCOEVEOTQ4NkI2QURCNjlERTAwMDAwMEFGNTAyQjAwMDA7bWlkPTxGM0UxNERBOUM5MTQ4NzRGODQ3RjkwRDNFRkJBRkYzQzE1QjE4Q0BNRVItRVhDSDIubmFwaWVyLmFjLnVrPg==, Actual Text goes here]]

Version reported by -V is incorrect

The -V switch doesn't report the correct version:

aclark@bristlenose 0 ~ $ todoist-habitrpg -V
0.0.1
aclark@bristlenose 0 ~ $ npm show todoist-habitrpg | grep latest
  'dist-tags': { latest: '1.1.1' },
aclark@bristlenose 0 ~ $

Sync only tasks with due dates?

How could I modify this to only sync tasks that have a set due date in Todoist? I put a lot of tasks in there that won't be prioritized or done for a while, and they'll probably get really red in HabitRPG. Thanks!

Difficulty

@kusold

I'm working on syncing up the difficulty setting between Todoist and HabitRPG. Habit marks the difficulty using the priority key: 1 for easy, 1.5 for medium and 2 for hard.

To sync them, I could use Todoist's priority system (though that's a 4 level system, instead of a 3 level system) or the label system (mark at is @HARd to give it a priority of 2). Or both, giving preference to one over the other.

Do you have thoughts?

Config

Originally brought up in #9.

The module could benefit from having a config file that would allow a user to configure certain settings, without having to type them all out on the command line. Maybe todoist-habitrpg -c path/to/config.json to specify the location of the config?

Here's a sampling of some basic configs

{
"habit-uuid" : "asdf-1234-asdf-1234",
"habit-token" : "asdf-1234-asdf-1234",
"todoist-key" : "asdf-1234-asdf-1234",
"history-location" : "~/path/to/history",
"sync-only": "all", // defaults to all, otherwise, an array of values. Some ideas: todos with due dates, inbox, #projectid, @labelid
"exclude-projects" : ["array", "of", "project", "ids"], 
"exclude-labels" : ["array", "of", "label", "ids"],
"sync-priority" : "label", // defaults to false. uses @hard, @med/@medium, @easy labels. Maybe an array of 3 values long could allow people to specify tags? Can also choose "priority" to use built in priority system
}

It'd be nice for the sync-only, exclude-projects, and exclude-labels to be able to use names of projects/labels, but since the id is what's unique, and how it's referenced in the api, that may be what needs to happen.

Maybe include a /bin directory with some small utilities, like generating a table showing the name of the project/label and it's associated id for all the projects/labels.

It also might be helpful to group things together, like so:

"credentials" : {
    "habit-uuid" : "asdf",
    "habit-token" : "adsf",
    "todoist-key" : "asdf"
},
"exclusions" : {
    "projects" : ["array"],
    "labels" : ["array"]
}

Anyway, just some thoughts. I'm sure more things could be configured, and not everything I listed needs to be configured.

error: { [Error: cannot POST /api/v3/tasks/user (404)] status: 404, method: 'POST', path: '/api/v3/tasks/user' },

Habitica API appears to have changed. All tasks fail to sync with a 404 message.

This seems to be an issue in the habitrpg-api library. I updated line 14 of /usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api to:

this.apiUrl = apiUrl || 'https://habitica.com/api/v3';

And the tasks seem to be syncing correctly again.

It does seem to be possible to set the apiURL without editing the library. I'll see if I cna track down where to make that change.

No exp/gold for recurring tasks

When I found this I migrated my dailies to Todoist for stuff like every other day functionality, and I've noticed I don't get any exp or gold for recurring tasks - it just changes the due date instead of completing it and adding a new one.

Can it create tasks with default difficulty?

All tasks are created in habitrpg with "easy" difficulty. Have a way to change it to another default? Like medium, hard...?

Ty vm!

Congratulations for this excelent add to habitica!! Perfect!!

Friday-only dailies won't complete.

Hi there. I seem to have found a bug with my every-Friday Todoist tasks that import as dailies. I have attached a screenshot of one; as you can see, there is no "Repeat" for this task even though it is definitely in the Dailies column.

This bug does not occur with Todoist tasks imported as dailies that occur on two days (every Saturday and Sunday, for example).

Completing these tasks in Todoist does not complete them in HabitRPG.

screenshot 2014-12-12 22 51 56

completed To-Dos are not given a dateCompleted value

I am not certain this issue is being caused by todoist-habitrpg, but I think it's likely based on this conversation with @cygnoir.

The issue is that some To-Dos that have been marked as completed do not have a dateCompleted attribute. Every completed To-Do should be given this attribute and its value should be the time at which the To-Do was ticked off. If a completed To-Do is later marked as uncompleted, the attribute needs to be removed.

This is important because HabitRPG uses the dateCompleted value to determine when a To-Do should be archived (currently, three days after completion; and archived To-Dos are not included amongst those shown in the browser). Without this information, all the user's completed To-Dos will keep on appearing in the user's completed To-Do tab and the browser performance will get worse and worse over time as the number of tasks increases.

Here is a full example of a completed To-Do:

        {
            "text": ":red_circle: Tidying: bathroom: +1",
            "dateCompleted": "2015-01-12T11:01:44.148Z",
            "challenge": {},
            "attribute": "str",
            "priority": 1,
            "value": 1,
            "tags": {
                "50155ebc-26d5-4e2f-8f23-38a518399ff1": true
            },
            "notes": "",
            "dateCreated": "2015-01-11T21:18:30.197Z",
            "id": "9616f71a-a3ec-4d7c-878e-501e16671c7a",
            "checklist": [],
            "collapseChecklist": false,
            "completed": true,
            "type": "todo"
        },

Could you please check todoist-habitrpg to see if it is causing this issue? If it is, could you please adjust the module?

Also, if todoist-habitrpg is causing this, do you have any way of reliably fixing all existing completed To-Dos for all your users so that they are all given a dateCompleted value? Please tell me if you are not able to do that so that I can write a script to modify the tasks in HabitRPG's own database. Obviously, the dateCompleted value you/I give to the tasks won't be accurate, but it would be enough to give it a value for the current date and time.

Deleted Tasks

If you delete a task in Todoist, it is not also deleted in HabitRPG.

daily in todoist not recognised in habitica

I created a task in todoist to be repeated daily and it showed up as a to-do in habitica, not a daily.

Deleting it can changing the repeat to every day and it showed up correctly in habitica.

Merging old HabitRPG dailies to avoid losing progress stats?

I have a couple of HabitRPG dailies with long streaks (one is at 668) that I'd like to sync up with Todoist so I don't have to go to HabitRPG to check them off. However, when I make a task in Todoist named exactly the same thing, it just creates a new daily in HabitRPG.

Is there any way to merge the two so I don't want to lose the HabitRPG progress stats?

Cannot read property 'type' of undefined

I'm running into issues trying to sync my Todoist and Habitica via Terminal on Mac:

`/usr/local/lib/node_modules/todoist-habitrpg/habitSync.js:218
if(res.body.type == "daily") {
^

TypeError: Cannot read property 'type' of undefined
at /usr/local/lib/node_modules/todoist-habitrpg/habitSync.js:218:20
at fn (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:638:34)
at Immediate._onImmediate (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:554:34)
at processImmediate as _immediateCallback`

both the command itself and 'sudo' command aren't working.

ERROR: Body is undefined. Please file an issue with this.

ERROR: Body is undefined. Please file an issue with this. res:{ req:
   { domain: null,
     _events: { drain: [Function], error: [Function], response: [Function] },
     _maxListeners: 10,
     output: [],
     outputEncodings: [],
     writable: true,
     _last: true,
     chunkedEncoding: false,
     shouldKeepAlive: false,
     useChunkedEncodingByDefault: true,
     sendDate: false,
     _headerSent: true,
     _header: 'PUT /api/v3/tasks/2f6cee3a-8435-4d2f-863d-203d8724aef7 HTTP/1.1\r\nHost: habitrpg.com\r\nAccept-Encoding: gzip, deflate\r\nCookie: \r\nContent-Type: application/json\r\nx-api-user: U-KEY\r\nx-api-key: T-KEY\r\nAccept: application/json\r\nContent-Length: 210\r\nConnection: close\r\n\r\n',
     _hasBody: true,
     _trailer: '',
     finished: true,
     _hangupClose: false,
     socket:
      { _readableState: [Object],
        readable: false,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: true,
        pair: [Object],
        _pending: null,
        _pendingEncoding: '',
        _pendingCallback: null,
        _doneFlag: false,
        _retryAfterPartial: false,
        _halfRead: false,
        _sslOutCb: null,
        _resumingSession: false,
        _reading: true,
        _destroyed: true,
        _ended: true,
        _finished: true,
        _opposite: [Object],
        _buffer: [Object],
        _handle: [Object],
        socket: [Object],
        encrypted: [Object],
        authorized: true,
        _controlReleased: true,
        parser: null,
        _httpMessage: [Circular],
        ondata: null,
        onend: null,
        npnProtocol: undefined },
     connection:
      { _readableState: [Object],
        readable: false,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: true,
        pair: [Object],
        _pending: null,
        _pendingEncoding: '',
        _pendingCallback: null,
        _doneFlag: false,
        _retryAfterPartial: false,
        _halfRead: false,
        _sslOutCb: null,
        _resumingSession: false,
        _reading: true,
        _destroyed: true,
        _ended: true,
        _finished: true,
        _opposite: [Object],
        _buffer: [Object],
        _handle: [Object],
        socket: [Object],
        encrypted: [Object],
        authorized: true,
        _controlReleased: true,
        parser: null,
        _httpMessage: [Circular],
        ondata: null,
        onend: null,
        npnProtocol: undefined },
     agent: false,
     socketPath: undefined,
     method: 'PUT',
     path: '/api/v3/tasks/2f6cee3a-8435-4d2f-863d-203d8724aef7',
     _headers:
      { host: 'habitrpg.com',
        'accept-encoding': 'gzip, deflate',
        cookie: '',
        'content-type': 'application/json',
        'x-api-user': 'U-KEY',
        'x-api-key': 'T-KEY',
        accept: 'application/json',
        'content-length': 210 },
     _headerNames:
      { host: 'Host',
        'accept-encoding': 'Accept-Encoding',
        cookie: 'Cookie',
        'content-type': 'Content-Type',
        'x-api-user': 'x-api-user',
        'x-api-key': 'x-api-key',
        accept: 'Accept',
        'content-length': 'Content-Length' },
     parser: null,
     res:
      { _readableState: [Object],
        readable: false,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        socket: [Object],
        connection: [Object],
        httpVersion: '1.1',
        complete: true,
        headers: [Object],
        trailers: {},
        _pendings: [],
        _pendingIndex: 0,
        url: '',
        method: null,
        statusCode: 503,
        client: [Object],
        _consuming: true,
        _dumped: false,
        httpVersionMajor: 1,
        httpVersionMinor: 1,
        upgrade: false,
        req: [Circular],
        text: '<!DOCTYPE html>\n\t<html>\n\t  <head>\n\t\t<meta charset="utf-8">\n\t\t<title>Application Error | Heroku</title>\n\t\t<link rel="shortcut icon" type="image/x-icon" href="https://www.herokucdn.com/favicon.ico">\n\t\t<style media="screen">\n\t\t  html,body,iframe {\n\t\t\tmargin: 0;\n\t\t\tpadding: 0;\n\t\t  }\n\t\t  html,body {\n\t\t\theight: 100%;\n\t\t\toverflow: hidden;\n\t\t  }\n\t\t  iframe {\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tborder: 0;\n\t\t  }\n\t\t</style>\n\t  </head>\n\t  <body>\n\t\t<iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>\n\t  </body>\n\t</html>',
        pipe: [Function],
        addListener: [Function: addListener],
        on: [Function: addListener],
        pause: [Function],
        resume: [Function],
        read: [Function],
        body: undefined } },
  res:
   { _readableState:
      { highWaterMark: 16384,
        buffer: [],
        length: 0,
        pipes: null,
        pipesCount: 0,
        flowing: false,
        ended: true,
        endEmitted: true,
        reading: false,
        calledRead: true,
        sync: true,
        needReadable: true,
        emittedReadable: false,
        readableListening: false,
        objectMode: false,
        defaultEncoding: 'utf8',
        ranOut: false,
        awaitDrain: 0,
        readingMore: false,
        oldMode: true,
        decoder: [Object],
        encoding: 'utf8' },
     readable: false,
     domain: null,
     _events:
      { end: [Object],
        data: [Object],
        readable: [Function],
        close: [Function],
        error: [Function] },
     _maxListeners: 10,
     socket:
      { _readableState: [Object],
        readable: false,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: true,
        pair: [Object],
        _pending: null,
        _pendingEncoding: '',
        _pendingCallback: null,
        _doneFlag: false,
        _retryAfterPartial: false,
        _halfRead: false,
        _sslOutCb: null,
        _resumingSession: false,
        _reading: true,
        _destroyed: true,
        _ended: true,
        _finished: true,
        _opposite: [Object],
        _buffer: [Object],
        _handle: [Object],
        socket: [Object],
        encrypted: [Object],
        authorized: true,
        _controlReleased: true,
        parser: null,
        _httpMessage: [Object],
        ondata: null,
        onend: null,
        npnProtocol: undefined },
     connection:
      { _readableState: [Object],
        readable: false,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: true,
        pair: [Object],
        _pending: null,
        _pendingEncoding: '',
        _pendingCallback: null,
        _doneFlag: false,
        _retryAfterPartial: false,
        _halfRead: false,
        _sslOutCb: null,
        _resumingSession: false,
        _reading: true,
        _destroyed: true,
        _ended: true,
        _finished: true,
        _opposite: [Object],
        _buffer: [Object],
        _handle: [Object],
        socket: [Object],
        encrypted: [Object],
        authorized: true,
        _controlReleased: true,
        parser: null,
        _httpMessage: [Object],
        ondata: null,
        onend: null,
        npnProtocol: undefined },
     httpVersion: '1.1',
     complete: true,
     headers:
      { connection: 'close',
        server: 'Cowboy',
        date: 'Sat, 19 Nov 2016 00:55:25 GMT',
        'content-length': '538',
        'content-type': 'text/html; charset=utf-8',
        'cache-control': 'no-cache, no-store' },
     trailers: {},
     _pendings: [],
     _pendingIndex: 0,
     url: '',
     method: null,
     statusCode: 503,
     client:
      { _readableState: [Object],
        readable: false,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: true,
        pair: [Object],
        _pending: null,
        _pendingEncoding: '',
        _pendingCallback: null,
        _doneFlag: false,
        _retryAfterPartial: false,
        _halfRead: false,
        _sslOutCb: null,
        _resumingSession: false,
        _reading: true,
        _destroyed: true,
        _ended: true,
        _finished: true,
        _opposite: [Object],
        _buffer: [Object],
        _handle: [Object],
        socket: [Object],
        encrypted: [Object],
        authorized: true,
        _controlReleased: true,
        parser: null,
        _httpMessage: [Object],
        ondata: null,
        onend: null,
        npnProtocol: undefined },
     _consuming: true,
     _dumped: false,
     httpVersionMajor: 1,
     httpVersionMinor: 1,
     upgrade: false,
     req:
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        output: [],
        outputEncodings: [],
        writable: true,
        _last: true,
        chunkedEncoding: false,
        shouldKeepAlive: false,
        useChunkedEncodingByDefault: true,
        sendDate: false,
        _headerSent: true,
        _header: 'PUT /api/v3/tasks/2f6cee3a-8435-4d2f-863d-203d8724aef7 HTTP/1.1\r\nHost: habitrpg.com\r\nAccept-Encoding: gzip, deflate\r\nCookie: \r\nContent-Type: application/json\r\nx-api-user: U-KEY\r\nx-api-key: T-KEY\r\nAccept: application/json\r\nContent-Length: 210\r\nConnection: close\r\n\r\n',
        _hasBody: true,
        _trailer: '',
        finished: true,
        _hangupClose: false,
        socket: [Object],
        connection: [Object],
        agent: false,
        socketPath: undefined,
        method: 'PUT',
        path: '/api/v3/tasks/2f6cee3a-8435-4d2f-863d-203d8724aef7',
        _headers: [Object],
        _headerNames: [Object],
        parser: null,
        res: [Circular] },
     text: '<!DOCTYPE html>\n\t<html>\n\t  <head>\n\t\t<meta charset="utf-8">\n\t\t<title>Application Error | Heroku</title>\n\t\t<link rel="shortcut icon" type="image/x-icon" href="https://www.herokucdn.com/favicon.ico">\n\t\t<style media="screen">\n\t\t  html,body,iframe {\n\t\t\tmargin: 0;\n\t\t\tpadding: 0;\n\t\t  }\n\t\t  html,body {\n\t\t\theight: 100%;\n\t\t\toverflow: hidden;\n\t\t  }\n\t\t  iframe {\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tborder: 0;\n\t\t  }\n\t\t</style>\n\t  </head>\n\t  <body>\n\t\t<iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>\n\t  </body>\n\t</html>',
     pipe: [Function],
     addListener: [Function: addListener],
     on: [Function: addListener],
     pause: [Function],
     resume: [Function],
     read: [Function],
     body: undefined },
  links: {},
  text: '<!DOCTYPE html>\n\t<html>\n\t  <head>\n\t\t<meta charset="utf-8">\n\t\t<title>Application Error | Heroku</title>\n\t\t<link rel="shortcut icon" type="image/x-icon" href="https://www.herokucdn.com/favicon.ico">\n\t\t<style media="screen">\n\t\t  html,body,iframe {\n\t\t\tmargin: 0;\n\t\t\tpadding: 0;\n\t\t  }\n\t\t  html,body {\n\t\t\theight: 100%;\n\t\t\toverflow: hidden;\n\t\t  }\n\t\t  iframe {\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tborder: 0;\n\t\t  }\n\t\t</style>\n\t  </head>\n\t  <body>\n\t\t<iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>\n\t  </body>\n\t</html>',
  body: undefined,
  files: {},
  buffered: true,
  headers:
   { connection: 'close',
     server: 'Cowboy',
     date: 'Sat, 19 Nov 2016 00:55:25 GMT',
     'content-length': '538',
     'content-type': 'text/html; charset=utf-8',
     'cache-control': 'no-cache, no-store' },
  header:
   { connection: 'close',
     server: 'Cowboy',
     date: 'Sat, 19 Nov 2016 00:55:25 GMT',
     'content-length': '538',
     'content-type': 'text/html; charset=utf-8',
     'cache-control': 'no-cache, no-store' },
  statusCode: 503,
  status: 503,
  statusType: 5,
  info: false,
  ok: false,
  redirect: false,
  clientError: false,
  serverError: true,
  error:
   { [Error: cannot PUT /api/v3/tasks/2f6cee3a-8435-4d2f-863d-203d8724aef7 (503)]
     status: 503,
     method: 'PUT',
     path: '/api/v3/tasks/2f6cee3a-8435-4d2f-863d-203d8724aef7' },
  accepted: false,
  noContent: false,
  badRequest: false,
  unauthorized: false,
  notAcceptable: false,
  forbidden: false,
  notFound: false,
  charset: 'utf-8',
  type: 'text/html',
  setEncoding: [Function],
  redirects: [] }

Says it synced but didn't

Since the project has not been updated for a while I am not sure if it still is maintained. I get successful Sync notifications whether the used Tokens are right or wrong. The Sync Log tells me it didn't sync

Test Version 3 of the API

We're looking for Habitica developers to try out the upcoming version 3 of the API. We are hoping that we will be ready to start testing within the next two weeks, but we're collecting testers now so that we can hit the ground running. Thanks very much for considering it, and feel free to let me know if you have any questions!

Sign Up!

Obfuscate or don't sync tasks with certain labels

I don't want work tasks in habitrpg.

I put in a kludge in my copy of habitSync.prototype.syncItemsToHabitRpg under your check for the labels length:

var myworkID = 136886;
for(var i in item.todoist.labels) {
   if (item.todoist.lables[i] == myworkID) {
      task.text = "work [" + task.text[0] + ".." + task.text[task.text.length -1] + "]";
   }
}

So for me, tasks with label of @work such as "Foo the bar" become "work [F..r]"
Presumably would be nicer to have a CLI param to specify the text of the label, but this got me unblocked.

Deleted tasks don't sync

Deleting a task in Todoist doesn't always sync to Habitica. This can leave stale dailies causing damage.

Do not send "undefined" to HabitRPG

There is a bad issue ( See #23 ) involving having an undefined date_string.

Also, I have a task with an undefined id. In general I think it is a good idea not to send this value (or null) at all since it is not valid JSON.

TypeError: Cannot read property 'body' of undefined in apiv3.js

Last night my cron job failed with:

/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/lib/apiv3.js:189
  if(apiVersion === 'v2' && res.body) {
                               ^

TypeError: Cannot read property 'body' of undefined
    at formatResponse (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/lib/apiv3.js:189:32)
    at /usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/lib/apiv3.js:61:7
    at Request.callback (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/node_modules/superagent/lib/node/index.js:660:30)
    at ClientRequest.<anonymous> (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/habitrpg-api/node_modules/superagent/lib/node/index.js:628:10)
    at emitOne (events.js:77:13)
    at ClientRequest.emit (events.js:169:7)
    at TLSSocket.socketErrorListener (_http_client.js:256:9)
    at emitOne (events.js:77:13)
    at TLSSocket.emit (events.js:169:7)
    at connectErrorNT (net.js:997:8)

Trying to rerun the sync fails with:

/usr/local/lib/node_modules/todoist-habitrpg/habitSync.js:218
        if(res.body.type == "daily") {
                   ^

TypeError: Cannot read property 'type' of undefined
    at /usr/local/lib/node_modules/todoist-habitrpg/habitSync.js:218:20
    at fn (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:638:34)
    at Immediate._onImmediate (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:554:34)
    at processImmediate [as _immediateCallback] (timers.js:383:17)

Previous syncs have worked fine.

sync only one time

Hi. I have tested and all inbox tasks in todoit go to habitica perfectly.

but, I think they have blocked me? Cause I have addeded very much new tasks (todoist) and turn others checked (in todoist) and it is not showing in habitica.

No errors when run the command. It says: synced with success but not happens in habitica.

JS error in habitSync.parseTodoistRepeatingDate

/home/me/node-v0.10.35-linux-x86/lib/node_modules/todoist-habitrpg/habitSync.js:292
var noStartDate = !(dateString.match(/(after|starting|last|\d+(st|nd|rd|th)|
^
TypeError: Cannot call method 'match' of null
at habitSync.parseTodoistRepeatingDate (/home/me/node-v0.10.35-linux-x86/lib/node_modules/todoist-habitrpg/habit
Sync.js:292:34)
at async.waterfall.history.tasks.(anonymous function).todoist (/home/me/node-v0.10.35-linux-x86/lib/node_modules
/todoist-habitrpg/habitSync.js:154:29)
at fn (/home/me/node-v0.10.35-linux-x86/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:641:34
)
at Object._onImmediate (/home/me/node-v0.10.35-linux-x86/lib/node_modules/todoist-habitrpg/node_modules/async/li
b/async.js:557:34)
at processImmediate as _immediateCallback

Here's 292:

habitSync.prototype.parseTodoistRepeatingDate = function(dateString) {
var type = "todo";
var repeat;

var noStartDate = !(dateString.match(/(after|starting|last|\d+(st|nd|rd|th)|(first|second|third))/i));

Using launchd instead of crontab?

Hi. Does anyone with experience using launchd instead of crontab have a minute to help me set this up? I use launchd to schedule jobs on my Mac but have had no luck doing so with todoist-habitrpg yet.

Sorry, I know this isn't really an issue ... if only I would get over myself and learn vim. :)

Cannot Read Property 'type' of Undefined

The latest build of the script is throwing an error. Any idea on what's going on?

Edit: Seems like I accidentally ticked a repeating monthly task off in Habitica. Deleting that task in Todoist and remaking it solved the problem.

/usr/local/lib/node_modules/todoist-habitrpg/habitSync.js:218
        if(res.body.type == "daily") {
                   ^
TypeError: Cannot read property 'type' of undefined
    at /usr/local/lib/node_modules/todoist-habitrpg/habitSync.js:218:20
    at fn (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:638:34)
    at Object._onImmediate (/usr/local/lib/node_modules/todoist-habitrpg/node_modules/async/lib/async.js:554:34)
    at processImmediate [as _immediateCallback] (timers.js:330:15)

Doing Dailies early: Habit VS Todoist

I noticed a difference between how Habit handles dailies and how Todoist handles them.

In Habit, I can create a daily that is due on Monday and Thursday. If I do the daily on Wednesday, it's still going to be due on Thursday.

In Todoist, however, if I create a daily for Mon & Thurs, and mark it as completed on Wednesday, it won't be due again until Monday.

If this was for Todos, I wouldn't think it's a big deal, but since Habit calculates damage based on undone dailies, I'd hate to see someone take damage for doing their task early and not realizing that it was still due in Habit.

Sync fails with timeout

When I attempt to sync, I get a timeout error:

$ todoist-habitrpg -u [uid] -t [token] -a [token]
Sync failed with error: Error: connect ETIMEDOUT 54.243.175.97:443
Sync completed successfully.
$

Repeated attempts just result in Habitica lists the same To-dos multiple times, sometimes getting further through the sync, but always failing.

Various hosts are reported. Thus far I've seen:

Sync failed with error: Error: connect ETIMEDOUT 54.235.146.150:443
Sync failed with error: Error: connect ETIMEDOUT 54.243.175.97:443
Sync failed with error: Error: connect ETIMEDOUT 50.16.225.80:443
Sync failed with error: Error: connect ETIMEDOUT 50.16.225.80:443
Sync failed with error: Error: connect ETIMEDOUT 52.200.13.212:443

I can't find a log file anywhere, regardless of whether I point -f to a directory as indicated in the README or a file as indicated in the --help blurb.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.