Skip to content
This repository has been archived by the owner on Mar 6, 2022. It is now read-only.

Feature/update wunderlist api #23

Merged
merged 20 commits into from Jul 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
252 changes: 128 additions & 124 deletions MMM-Wunderlist.js
@@ -1,4 +1,4 @@
"use strict"
"use strict";
/* global Module */

/* Magic Mirror
Expand All @@ -9,127 +9,131 @@
*/

Module.register("MMM-Wunderlist", {

defaults: {
maximumEntries: 10,
order: "normal",
lists: ["inbox"],
interval: 60,
fade: true,
fadePoint: 0.25,
showDeadline: false,
showAssignee: false,
deadlineFormat: 'L',
},

// Override socket notification handler.
socketNotificationReceived: function (notification, payload) {
if (notification === "TASKS") {
this.tasks = payload
this.updateDom(3000);
}
else if (notification === "STARTED") {
console.log(notification);
this.sendSocketNotification("addLists", this.config.lists);
if (this.config.showAssignee) {
this.started = true;
this.sendSocketNotification("getUsers");
}
}
else if (notification === "users") {
this.users = payload;
if (this.tasks && this.tasks.length > 0) {
this.updateDom(3000);
}
}
},

start: function () {
this.tasks = [];

// Use global language per default
if (this.config.language == null) {
this.config.language = config.language;
}

this.sendSocketNotification("CONFIG", this.config);
this.sendSocketNotification("CONNECTED");
Log.info("Starting module: " + this.name);
},

getTodos: function () {
var tasksShown = [];

for (var i = 0; i < this.config.lists.length; i++) {
if (typeof this.tasks[this.config.lists[i]] != "undefined") {
var list = this.tasks[this.config.lists[i]];

for (var todo in list) {
if (this.config.order == "reversed") {
tasksShown.push(list[todo]);
}
else {
tasksShown.unshift(list[todo]);
}
}
}
}
return tasksShown.slice(0, this.config.maximumEntries);
},

getScripts: function () {
return [
'String.format.js'
];
},
getStyles: function () {
return ["font-awesome.css"];
},

html: {
table: '<thead>{0}</thead><tbody>{1}</tbody>',
row: '<tr><td>{0}</td><td>{1}</td><td class="title bright">{2}</td><td>{3}</td></tr>',
star: '<i class="fa fa-star" aria-hidden="true"></i>',
assignee: '<div style="display: inline-flex; align-items: center; justify-content: center; background-color: #aaa; color: #666; min-width: 1em; border-radius: 50%; vertical-align: middle; padding: 2px; text-transform: uppercase;">{0}</div>',
},

getDom: function () {
if (this.config.showAssignee && this.started && !this.users) {
this.sendSocketNotification("getUsers");
}
var self = this;
var wrapper = document.createElement("table");
wrapper.className = "normal small light";

var todos = this.getTodos();

var rows = []
todos.forEach(function (todo, i) {
rows[i] = self.html.row.format(
self.config.showDeadline && todo.due_date ? todo.due_date : '',
todo.starred ? self.html.star : '',
todo.title,
self.config.showAssignee && todo.assignee_id && self.users ? self.html.assignee.format(self.users[todo.assignee_id]) : ''
)

// Create fade effect
if (self.config.fade && self.config.fadePoint < 1) {
if (self.config.fadePoint < 0) {
self.config.fadePoint = 0;
}
var startingPoint = todos.length * self.config.fadePoint;
if (i >= startingPoint) {
wrapper.style.opacity = 1 - (1 / todos.length - startingPoint * (i - startingPoint));
}
}
});

wrapper.innerHTML = this.html.table.format(
this.html.row.format('', '', '', ''),
rows.join('')
)

return wrapper;
},

defaults: {
maximumEntries: 10,
order: "normal",
lists: ["inbox"],
interval: 60,
fade: true,
fadePoint: 0.25,
showDeadline: false,
showAssignee: false,
deadlineFormat: "L"
},

notificationReceived: function(notification, payload, sender) {
if (notification === "ALL_MODULES_STARTED") {
this.sendSocketNotification("ALL_MODULES_STARTED");
}
},

// Override socket notification handler.
socketNotificationReceived: function(notification, payload) {
if (notification === "RETRIEVED_TODOS") {
this.lists = payload;
this.updateDom(3000);
} else if (
notification === "RETRIEVED_LIST_IDS" &&
payload.id == this.identifier
) {
this.listIDs = payload.displayedListIDs;
this.started = true
} else if (notification === "users") {
this.users = payload;
if (this.tasks && this.tasks.length > 0) {
this.updateDom(3000);
}
}
},

start: function() {
this.lists = [];
this.listIDs = [];

// Use global language per default
if (this.config.language == null) {
this.config.language = config.language;
}

var payload = {
id: this.identifier,
config: this.config
};
this.sendSocketNotification("REGISTER_INSTANCE", {
id: this.identifier,
config: this.config
});
Log.info("Starting module: " + this.name + this.identifier);
},

getTodos: function() {
var tasksShown = [];
for (var i = 0; i < this.listIDs.length; i++) {
if (typeof this.lists[this.listIDs[i]] != "undefined") {
var list = this.lists[this.listIDs[i]];
for (var todo in list) {
if (this.config.order == "reversed") {
tasksShown.push(list[todo]);
} else {
tasksShown.unshift(list[todo]);
}
}
}
}
return tasksShown.slice(0, this.config.maximumEntries);
},

getScripts: function() {
return ["String.format.js"];
},
getStyles: function() {
return ["font-awesome.css"];
},

html: {
table: "<thead>{0}</thead><tbody>{1}</tbody>",
row:
'<tr><td>{0}</td><td>{1}</td><td class="title bright">{2}</td><td>{3}</td></tr>',
star: '<i class="fa fa-star" aria-hidden="true"></i>',
assignee:
'<div style="display: inline-flex; align-items: center; justify-content: center; background-color: #aaa; color: #666; min-width: 1em; border-radius: 50%; vertical-align: middle; padding: 2px; text-transform: uppercase;">{0}</div>'
},

getDom: function() {
var self = this;
var wrapper = document.createElement("table");
wrapper.className = "normal small light";

var todos = this.getTodos();

var rows = [];
todos.forEach(function(todo, i) {
rows[i] = self.html.row.format(
self.config.showDeadline && todo.due_date ? todo.due_date : "",
todo.starred ? self.html.star : "",
todo.title,
self.config.showAssignee && todo.assignee_id && self.users
? self.html.assignee.format(self.users[todo.assignee_id])
: ""
);
// Create fade effect
if (self.config.fade && self.config.fadePoint < 1) {
if (self.config.fadePoint < 0) {
self.config.fadePoint = 0;
}
var startingPoint = todos.length * self.config.fadePoint;
if (i >= startingPoint) {
wrapper.style.opacity =
1 - (1 / todos.length - startingPoint * (i - startingPoint));
}
}
});

wrapper.innerHTML = this.html.table.format(
this.html.row.format("", "", "", ""),
rows.join("")
);

return wrapper;
}
});
21 changes: 19 additions & 2 deletions README.md
@@ -1,5 +1,8 @@
# MMM-Wunderlist
This an extension for the [MagicMirror](https://github.com/MichMich/MagicMirror). It can display your Wunderlist todos. You can add multiple instances with different lists. Only one account supported.
This an extension for the [MagicMirror](https://github.com/MichMich/MagicMirror). It can display your Wunderlist todos. You can add multiple instances from different accounts with different lists.

![MMM-Wunderlist Screenshot](screenshots/screen_cap1.png?raw=true "Title")


## Installation
1. Navigate into your MagicMirror's `modules` folder and execute `git clone https://github.com/paviro/MMM-Wunderlist.git`. A new folder will appear navigate into it.
Expand All @@ -21,6 +24,18 @@ modules: [
]
````

## Retrieving API Token
*FYI: There is no additional registration required, you may use your Wunderlist Creds*

Go to [Developer.Wunderlist](https://developer.wunderlist.com/apps/new). It does not really matter what you type in here, so you may go with:
```
Name: MMM-Wunderlist
APP URL: http://localhost
AUTH CALLBACK URL: http://localhost
```

Hit *save* and you'll be displayed your `clientID`. Click on *create access token*
and you'll get the `accessToken`.
## Configuration options

The following properties can be configured:
Expand Down Expand Up @@ -129,7 +144,9 @@ The following properties can be configured:
- [Moment](https://www.npmjs.com/package/moment) (installed via `npm install`)

## Known issues
- some of requests for users list returns 404 error
- After changing your password you'll have to generate a new API-Token
- When you grant access to a new user and set `showAssignee: true` , you might have to restart MM to correctly display the assignees
- Some of requests for users list returns 404 error

The MIT License (MIT)
=====================
Expand Down
16 changes: 8 additions & 8 deletions String.format.js
@@ -1,11 +1,11 @@
"use strict"
"use strict";

// add string format method
if (!String.prototype.format) {
String.prototype.format = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
};
}
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != "undefined" ? args[number] : match;
});
};
}
63 changes: 63 additions & 0 deletions api_debug_client.js
@@ -0,0 +1,63 @@
var Wunderlist = require("./wunderlist-api");
require("request-promise").debug = true;

const accessToken = "";
const clientID = "";

function retrieveTodos(wunderlist, listID) {
wunderlist
.retrieveTodos(listID)
.then(function(resp) {
console.log(JSON.stringify(resp));
})
.catch(function(err) {
console.log(err);
});
}

function retrieveUsers(wunderlist) {
wunderlist
.retrieveUsers()
.then(function(resp) {
console.log(JSON.stringify(resp));
})
.catch(function(err) {
console.log(err);
});
}

function retrieveList(wunderlist, listID) {
wunderlist
.retrieveList(listID)
.then(function(resp) {
console.log(JSON.stringify(resp));
})
.catch(function(err) {
console.log(err);
});
}

function retrieveLists(wunderlist) {
return new Promise(function(resolve, reject) {
wunderlist
.retrieveLists()
.then(function(resp) {
console.log(JSON.stringify(resp));
resolve(resp);
})
.catch(function(err) {
console.log(err);
reject();
});
});
}

var wunderlist = new Wunderlist(clientID, accessToken);
retrieveLists(wunderlist)
.then(function(lists) {
retrieveTodos(wunderlist, lists[0].id);
retrieveList(wunderlist, lists[0].id);

})
.catch();
retrieveUsers(wunderlist);