UNPKG

imdone

Version:

A task board and wiki in one!

502 lines (437 loc) 14.8 kB
/* * imdone * https://github.com/piascikj/imdone * * Copyright (c) 2012 Jesse Piascik * Licensed under the MIT license. */ //ARCHIVE:450 Implement hide functionality to hide a list from board // Nodejs libs. var fs = require('fs'); var path = require('path'); var events = require('events'); var program = require("commander"); var wrench = require('wrench'); var _ = require('lodash'); var marked = require('marked'); var open = require('open'); var request = require('request'); var express = require('express'); var bodyParser = require('body-parser'); var cookieParser = require('cookie-parser'); var http = require('http'); var server = require("./server"); var Search = require('imdone-core').Search; var async = require('async'); var Keen = require('keen.io'); var tree = require('./util/tree'); var log = require('debug')('imdone:imdone'); var core = require("imdone-core"); var Repo = require('imdone-core/lib/watched-repository'); var Project = require('imdone-core/lib/fs-project'); var tools = core.Tools; var sanitize; var imdone = module.exports = {pause:{}}; var pkginfo = require('pkginfo')(module); var PROJECT_NOT_FOUND = imdone.PROJECT_NOT_FOUND = "Project not found"; var DIR_NOT_FOUND = imdone.DIR_NOT_FOUND = "Directory not found"; var keen = Keen.configure({ projectId: "5550efecd2eaaa7efde1f138", writeKey: "57032d04b2b29b693ef0e06aa3c7f295ead6daf33f51696b99dffdc1ad3e52898a22578b58a2f2138d370e626c497a93ecbb6629ec4dc6f7d4b34a64158121afeec493adef9a069b4385ead8861e852acd66489a049084e75dbb72e1cea5dfc0f584eac15dd91ca7a58c357656cb36eb" }); _.templateSettings = { interpolate: /\{\{(.+?)\}\}/g }; imdone.config = { port: process.env.IMDONE_PORT || 8080, cliPort: process.env.IMDONE_CLI_PORT || 8899 }; imdone.projects = {}; imdone.server = server; /* `imdone` will add the current working directory to imdone projects and start imdone if not already up `imdone stop` will stop imdone */ imdone.startFromCLI = function(dir) { program .usage("[options]") .version(imdone.version) .option('-o, --open', 'Open imdone in the default browser') .option('-s, --stop', 'Stop imdone server') .option('-d, --dirs <directories>', 'A comma separated list of project directories', function list(val) { return val.split(','); }); program.on('--help', function(){ console.log(' Examples:'); console.log(''); console.log(' Open imdone in a browser with the current working directory as the project root'); console.log(''); console.log(' $ imdone -o'); console.log(''); console.log(' Open imdone in a browser with list of project directories'); console.log(''); console.log(' $ imdone -o -d projects/imdone,projects/myproject'); }); console.log(" _ __ __ _____ "); console.log(" (_) | \\/ | | __ \\ "); console.log(" _ | \\ / | | | | | ___ _ __ ___ "); console.log(" | | | |\\/| | | | | | / _ \\ | '_ \\ / _ \\"); console.log(" | | | | | | | |__| | | (_) | | | | | | __/"); console.log(" |_| |_| |_| |_____/ \\___/ |_| |_| \\___|"); program.parse(process.argv); var dirs = _.map(program.dirs || [dir], function(dir) { return path.resolve(dir); } ); if (program.stop) { imdone.cliStop(); } else { imdone.start(dirs, program.open); } }; imdone.isInitialized = function() { return imdone.inititalized; }; imdone.start = function(dirs, _open, noServer, cb) { keen.addEvent("imdone started", { openCLI: _open ? true :false }, function(err, result) { }); if (_.isFunction(noServer)) { cb = noServer; noServer = null; } cb = _.isFunction(cb) ? cb : _.noop; if (imdone.isInitialized()) return cb(); // Merge dirs with dirs in config dirs = _.union(imdone.getConfig().projects, dirs); function init() { // DONE:40 Should be able to start without server if (!noServer) server.start(imdone); var funcs = []; _.each(dirs, function(d) { funcs.push(function(cb) { imdone.addProject(d, cb); }); }); async.parallel(funcs, function(err, result) { log('All projects initialized'); if (_open) open('http://localhost:' + imdone.config.port); imdone.initialized = true; cb(err, result); }); } if (noServer) init(); else { log('Begin initializing projects'); imdone.checkCLIService(function() { console.log("iMDone service is already running!"); if (_open) imdone.cliOpen(); cb(); _.each(dirs, function(d) { imdone.cliAddProject(d); }); }, function() { imdone.startCLIService(function() { init(); }); }); } }; // PLANNING:80 Use axon-rpc for cli service and move to it's own module imdone.startCLIService = function(callback) { //Start a service on 8899 for cli to interact with //Access imdone data through getters and setters that require project path var app = imdone.cliService = express(); var xserver = http.createServer(app); app.use(cookieParser()); app.use(bodyParser()); //Start the api and static content server app.get("/cli", function(req, res) { res.send({ok:imdone.up}); }); app.post("/cli/project", function(req, res) { imdone.addProject(req.body.cwd, function(err, project) { res.send(project.getName()); }); }); app.delete("/cli/project", function(req, res) { res.send(imdone.removeProject(req.body.cwd)); }); app.post("/cli/stop", function(req, res) { res.send({ok:true}); process.exit(); }); app.post("/cli/open", function(req, res) { open('http://localhost:' + imdone.config.port); res.send({ok:true}); }); xserver.on('listening', function() { imdone.up = true; if (callback) callback(); }); xserver.listen(imdone.config.cliPort); }; imdone.cliOpen = function() { request.post({ url:"http://localhost:" + imdone.config.cliPort + "/cli/open" }, function(error, res, body) { if (!res) { console.log("failed to open browser"); } }); }; imdone.cliAddProject = function(dir) { request.post({ url:"http://localhost:" + imdone.config.cliPort + "/cli/project", json:{cwd:dir} }, function(error, res, body) { if (!res) { console.log("failed to add project"); } else { console.log('Added project:', body); } }); }; imdone.cliRemoveProject = function(dir) { request.delete({ url:"http://localhost:" + imdone.config.cliPort + "/cli/project", json:{cwd:dir} }, function(error, res, body) { if (!res) { console.log("failed to remove project"); } else { console.log('Removed project:', body.path); } }); }; imdone.cliStop = function() { request.post({ url:"http://localhost:" + imdone.config.cliPort + "/cli/stop" }, function(error, res, body) { if (!res) { console.log("failed to stop imdone service"); } else { console.log("imdone service has been stopped"); } }); }; imdone.checkCLIService = function(success, failure) { request.get({ url:"http://localhost:" + imdone.config.cliPort + "/cli", }, function(error, res, body) { if (!res) { failure(); } else { success(); } }); }; imdone.addProject = function(dir, cb) { cb = _.isFunction(cb) ? cb : _.noop; var name = dir.replace(/^([A-Za-z]:(\\)?|\/?)/, "").split(path.sep).join("-"); console.log("Adding project at:" + dir); if (imdone.projects[name]) delete imdone.projects[name]; if (!fs.existsSync(dir)) wrench.mkdirSyncRecursive(dir); var repo = new Repo(dir); var project = imdone.projects[name] = new Project(tools.user(), name, [repo]); project.on('project.initialized', function(data) { imdone.emitter.emit('project.initialized', data); }); project.on('project.modified', function(data) { imdone.emitter.emit('project.modified', data); }); project.on('files.processed', function(data) { imdone.emitter.emit('files.processed', data); }); project.init(function(err) { if (!err) imdone.addProjectToConfig(dir); cb(err,project); }); }; imdone.getConfigFile = function() { var dir = path.join(tools.userHome(), '.imdone'); if (!fs.existsSync(dir)) wrench.mkdirSyncRecursive(dir); var file = path.join(dir, 'config.json'); if (!fs.existsSync(file)) fs.writeFileSync(file, JSON.stringify({projects:[]}, null, 2)); return file; }; imdone.getConfig = function() { var json = fs.readFileSync(this.getConfigFile()); return JSON.parse(json); }; imdone.addProjectToConfig = function(dir) { var config = this.getConfig(); config.projects = _.without(config.projects, dir); config.projects.push(dir); fs.writeFileSync(this.getConfigFile(), JSON.stringify(config, null, 2)); }; imdone.removeProjectFromConfig = function(dir) { var config = this.getConfig(); config.projects = _.without(config.projects, dir); fs.writeFileSync(this.getConfigFile(), JSON.stringify(config, null, 2)); }; // PLANNING:40 Set a default project in config to be opened when iMDone starts imdone.removeProject = function(name) { console.log("Removing project with name:" + name); var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); var repo = imdone.getRepo(name); this.removeProjectFromConfig(repo.getPath()); project.destroy(); delete imdone.projects[name]; } imdone.emitter.emit("project.removed", {project:name}); }; imdone.getProject = function(name) { return imdone.projects[name] || undefined; }; imdone.getKanban = function(name) { var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); return { lists: project.getTasks(null, true), readme: imdone.getRepo(project).getDefaultFile() }; } }; imdone.moveTasks = function(name, tasks, newList, newPos, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.moveTasks(tasks, newList, newPos, cb); } }; imdone.moveList = function(name, list, pos, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.moveList(list, pos, cb); } }; imdone.removeList = function(name, list, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.removeList(list, cb); } }; imdone.renameList = function(name, list, newList, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.renameList(list, newList, cb); } else cb(new Error(PROJECT_NOT_FOUND)); }; imdone.hideList = function(name, list, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.hideList(list, cb); } else cb(new Error(PROJECT_NOT_FOUND)); }; imdone.showList = function(name, list, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.showList(list, cb); } else cb(new Error(PROJECT_NOT_FOUND)); }; imdone.md = function(name, _path, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { var repo = imdone.getRepo(project); repo.md(repo.getFile(_path), cb); } else return cb("Project is undefined"); }; imdone.getFile = function(name, _path, line, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); var repoId = imdone.getRepo(project).getId(); var file = project.getFileWithContent(repoId, _path); if (file) { cb(null, { repoId: file.getRepoId(), src:file.getContent(), line:line, lang:file.getLang().name, ext:file.getExt(), project:project.path, path:file.getPath() }); } else { project.saveFile(repoId, _path, "", function(err, file) { if (err) return cb(err); cb(null,{ repoId: file.getRepoId(), src:"", line:line, lang:file.getLang().name, ext:file.getExt(), project:project.path, path:file.getPath() }); }); } } else cb(new Error(PROJECT_NOT_FOUND)); }; imdone.saveFile = function(name, repoId, _path, src, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); project.saveFile(repoId, _path, src, cb); } else cb(new Error(PROJECT_NOT_FOUND)); }; imdone.removeFile = function(name, _path, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); if (project) { if (project.isBusy()) throw new Error("Project Busy"); var repoId = imdone.getRepo(project).getId(); project.deleteFile(repoId, _path, function(err, file) { cb(err, {file:file, deleted:true}); }); } else cb(new Error(PROJECT_NOT_FOUND)); }; imdone.getFiles = function(name) { var project = imdone.getProject(name); var files; if (project) { return project.getFileTree(imdone.getRepo(project).getId()); } else throw new Error(PROJECT_NOT_FOUND); }; imdone.getDirs = function(_path) { var files = tree.getFiles(_path); if (files) { return files; } else throw new Error(DIR_NOT_FOUND); }; imdone.doSearch = function(name, query, offset, limit) { var opts = {project:imdone.getProject(name)}; if (query) opts.query = query; if (limit) opts.limit = limit; if (offset) opts.offset = offset; var s = new Search(opts); s.execute(); return s; }; imdone.addList = function(name, list, cb) { cb = _.isFunction(cb) ? cb : _.noop; var project = imdone.getProject(name); project.addList(list, cb); }; imdone.getRepo = function(name) { if (name instanceof Project) return name.getRepos()[0]; return imdone.getProject(name).getRepos()[0]; }; imdone.getProjects = function() { return _.keys(imdone.projects); }; imdone.emitter = new events.EventEmitter();