Skip to content

Support Folderless Clickup Tasks #4

@mjm128

Description

@mjm128

Currently the module doesn't support a task list that isn't in a folder.

Here's the updated fix that supports the scenario where the task is not in a folder in a workspace.

File: node_helper.js

/* Magic Mirror Module
 * By: Andrew Matayka
 * Module: MMM-ClickUPv2
 * Version: 0.01
 */

const NodeHelper = require("node_helper");
const request = require("request");
const fs = require("fs");

let accessToken = undefined;

module.exports = NodeHelper.create({
	//Ran on the start of the node helper
	start: function () {
		console.log("%cMMM-ClickUPv2 (node): Node Helper Started!", "color: yellow;");
	},

	//Ran when receiving notification from the module
	socketNotificationReceived: function (notification, payload) {
		if (notification === "Request_AccessToken") {
			this.config = payload;

			if (this.config.debug) console.log("\n%cMMM-ClickUPv2 (node): Request Access Token Notification Received!", "color: yellow;");

			this.requestAccessToken();
		} else if (notification === "Request_TasksList") {
			this.config = payload;

			if (true) console.log("\n%cMMM-ClickUPv2 (node): Request Tasks List Notification Received!", "color: green;");

			this.requestTasks();
		}
	},

	requestAccessToken: function () {
		const self = this;

		const path = self.path;
		let aTFData = "";

		//Find out if AccessToken is already found and in file. If not find the Access Token
		if (accessToken === undefined) {
			return new Promise(resolve => {
				fs.readFile(path + '/accessToken', 'UTF-8', (error, data) => {
					if (error) {
						self.sendSocketNotification("Error", {
							error: error
						});

						//if(data.includes("no such")) {
						let fd = fs.open(path + '/accessToken', 'w', (err, file) => {
							if (err) {
								throw err;
							}

							console.log("File is created.");
						});
						// fd.close(); // This was an error in the original, closing it immediately. Left as-is.

						this.requestAccessToken();
						//	return;
						//}

						return console.error("MMM-ClickUPv2 (node): " + error);
					}
					aTFData = data;

					//If the AccessToken file does not contain the Access Token, or does not exist.
					if (aTFData.length === 0) {
						if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Requesting Access Token!", "color: yellow;")

						request({
								url: "https://api.clickup.com/api/v2/oauth/token",
								method: "POST",
								headers: {
									"content-type": "application/json",
									"cache-control": "no-cache"
								},
								form: {
									client_id: self.config.clientID,
									client_secret: self.config.clientSecret,
									code: self.config.accessCode
								}
							},
							function (error, response, body) {
								if (error) {
									self.sendSocketNotification("Error", {
										error: error
									});
									return console.error("MMM-ClickUPv2 (node): " + error);
								}
								if (response.statusCode === 200) {
									let responseJson = JSON.parse(body);
									accessToken = responseJson.access_token;
									if (self.config.debug) console.log("%cMMM-ClickUPv2 (node): Access Token Received: '" + accessToken + "'!", "color: yellow;");

									fs.appendFile(path + '/accessToken', accessToken, (err) => {
										if (err) {
											console.log(err)
										}
										if (self.config.debug) console.log("%cMMM-ClickUPv2 (node): Writing Access Token to file!", "color: yellow;")
									});

									resolve(accessToken);
								} else {
									if (self.config.debug) console.log("%cMMM-ClickUPv2 (node): ClickUP api request status - '" + response.statusCode + "'!", "color: yellow;");
									if (self.config.debug) console.log("%cMMM-ClickUPv2 (node): ClickUP api request response - '" + response.body + "'!", "color: yellow;");

									self.sendSocketNotification("Error", {
										error: response.body,
										statusCode: response.statusCode
									});
								}
							});
					} else { //If the Access Token is found in the accessToken file
						if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Read Access Token from file: '" + aTFData + "'!", "color: yellow;");
						resolve(aTFData);
					}
				});
			}).then(value => {
				accessToken = value;
				self.config.accessToken = value;
				self.sendSocketNotification("AccessToken", value);
			});
		} else {
			console.log("Found Access Token! No need to request!");
			self.config.accessToken = accessToken;
			self.sendSocketNotification("AccessToken", accessToken);
		}
	},

	requestTasks: function () {
		const self = this;

		if (accessToken !== undefined) {
			try {
				console.log("Got Access Token, ALL GOOD!");
				return new Promise(resolve => {
					if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Requesting Teams ID!", "color: green;");
					request({
						url: "https://api.clickup.com/api/v2/team",
						method: "GET",
						headers: {
							Authorization: accessToken
						}
					}, function (error, response, body) {
						if (!error) {
							resolve(JSON.parse(body).teams[0].id);
						} else {
							console.error(error);
							resolve(error)
						}
					});
				}).then(value => {
					if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Received Teams ID: " + value, "color: green;");

					return new Promise(function (resolve) {
						request({
							url: 'https://api.clickup.com/api/v2/team/' + value + '/space',
							method: "GET",
							headers: {
								Authorization: accessToken
							},
						}, function (error, response, body) {
							if (!error)
								resolve(JSON.parse(body).spaces[0].id);
							else {
								console.error(error);
								resolve(error);
							}
						});
					});
				}).then(value => {
					if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Received Spaces ID: " + value, "color: green;");
					const spaceId = value; // Store Space ID for use in both branches

					// --- START: MODIFIED LOGIC ---
					// This check handles if folderName is null, undefined, or an empty string ""
					if (self.config.folderName) {
						// --- FOLDER PATH ---
						if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): folderName is set. Looking for folder '" + self.config.folderName + "'", "color: yellow;");

						return new Promise(function (resolve) {
							request({
								url: 'https://api.clickup.com/api/v2/space/' + spaceId + '/folder',
								method: "GET",
								headers: {
									Authorization: accessToken
								},
							}, function (error, response, body) {
								if (!error) {
									let folders = JSON.parse(body).folders;
									let found = false;
									folders.forEach(folder => {
										if (self.config.folderName === folder.name) {
											resolve(folder.id);
											found = true;
										}
									});
									if (!found) {
										console.error("MMM-ClickUPv2 (node): Could not find folder named '" + self.config.folderName + "'");
										resolve(null); // Resolve with null to stop the chain
									}
								} else {
									console.error(error);
									resolve(error)
								}
							});
						}).then(value => {
							if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Received Folders ID: " + value, "color: green;")
							if (!value) return new Promise(resolve => resolve(null)); // Stop chain if folder wasn't found

							return new Promise(function (resolve) {
								request({
									url: 'https://api.clickup.com/api/v2/folder/' + value + '/list',
									method: "GET",
									headers: {
										Authorization: accessToken
									},
								}, function (error, response, body) {
									if (!error) {
										let lists = JSON.parse(body).lists;
										let found = false;
										lists.forEach(list => {
											if (self.config.listName === list.name) {
												resolve(list.id);
												found = true;
											}
										});
										if (!found) {
											console.error("MMM-ClickUPv2 (node): Could not find list '" + self.config.listName + "' in folder '" + self.config.folderName + "'");
											resolve(null);
										}
									} else {
										console.error(error);
										resolve(error);
									}
								});
							});
						});

					} else {
						// --- FOLDERLESS PATH ---
						if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): folderName is null/empty/missing. Looking for folderless list '" + self.config.listName + "'", "color: yellow;");

						return new Promise(function (resolve) {
							request({
								url: 'https://api.clickup.com/api/v2/space/' + spaceId + '/list',
								method: "GET",
								headers: {
									Authorization: accessToken
								},
							}, function (error, response, body) {
								if (!error) {
									let lists = JSON.parse(body).lists;
									let found = false;
									lists.forEach(list => {
										if (self.config.listName === list.name) {
											resolve(list.id);
											found = true;
										}
									});
									if (!found) {
										console.error("MMM-ClickUPv2 (node): Could not find folderless list named '" + self.config.listName + "'");
										resolve(null);
									}
								} else {
									console.error(error);
									resolve(error);
								}
							});
						});
					}
					// --- END: MODIFIED LOGIC ---

				}).then(value => {
					if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Received Lists ID: " + value, "color: green;");
					if (!value) return; // If value is null (list not found), stop here.

					return new Promise(function (resolve) {
						request({
							url: 'https://api.clickup.com/api/v2/list/' + value + '/task?archived=false&subtasks=true&include_closed=true&order_by=due_date',
							method: "GET",
							headers: {
								Authorization: accessToken
							},
						}, function (error, response, body) {
							if (!error)
								resolve(JSON.parse(body));
							else
								resolve(error);
						});
					}).then(value => {
						if (!value) return; // Stop if previous promise failed
						if (this.config.debug) console.log("%cMMM-ClickUPv2 (node): Received Tasks!", "color: green;");

						self.sendSocketNotification("Tasks_List", value);
					});
				});
			} catch (e) {
				console.log(e);
			}
		} else {
			if (this.config.debug) console.log("%cMMM-ClickUPv2: No Access Token Found!!!", "color: cyan;");
		}
		console.log("Still here");
	}
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions