Source: index.js

'use strict';

const web = require('axios')

//<editor-fold desc="USER">
/**
 * Creates an User object.
 * @constructor
 * @param {string} name - name of the user
 * @param {function} del - function to delete the user
 * @param {function} getProjects - function to get the projects of the user
 * @param {function} addProject - function to add a project
 * @param {function} deleteProject - function to delete a project
 */
var User = function (name, del, getProjects, addProject, deleteProject) {
    if (typeof(name) !== 'string' || typeof(del) !== 'function' || typeof(getProjects) !== 'function'
        || typeof(addProject) !== 'function' || typeof(deleteProject) !== 'function') {
        throw new Error('False arguments')
    }

    /**
     * name of the User
     * @type {string}
     */
    this.name = name

    /**
     * Deletes the user.
     * @method
     * @returns {Promise.<void, error>}
     */
    this.delete = del

    /**
     * Get the projects of the user.
     * @method
     * @returns {Promise.<Project[], error>}
     */
    this.getProjects = getProjects

    /**
     * Adds a project.
     * @method
     * @param {string} projectname - name of the new project
     * @returns {Promise.<Project, error>}
     */
    this.addProject = addProject

    /**
     * Deletes a project.
     * @method
     * @param {string} projectname - name of the project
     * @returns {Promise.<void, error>}
     */
    this.deleteProject = deleteProject
}
//</editor-fold>

//<editor-fold desc="Project">
/**
 * Creates a Project object.
 * @constructor
 * @param {string} name - name of the project
 * @param {string} user - owner of the project
 * @param {function} del - function to delete the project
 * @param {function} compile - function to compile the project
 * @param {function} getInformation - function to get project information
 */
var Project = function (name, user, del, compile, getInformation) {
    if (typeof(name) !== 'string' || typeof(user) !== 'string' || typeof(del) !== 'function'
        || typeof(getInformation) !== 'function') {
        throw new Error('False arguments')
    }

    /**
     * name of the project
     * @type {string}
     */
    this.name = name

    /**
     * owner of the project
     * @type {string}
     */
    this.user = user

    /**
     * Deletes the project.
     * @method
     * @returns {Promise.<void, error>}
     */
    this.delete = del

    /**
     * Compiles the project.
     * @method
     * @returns {Promise.<{stdout: string, stderr: string}, error>}
     */
    this.compile = compile

    /**
     * Gets information about the project.
     * @method
     * @returns {Promise.<ProjectInfo, error>}
     */
    this.getInformation = getInformation
}
//</editor-fold>

//<editor-fold desc="ProjectInfo">
/**
 * Creates a ProjectInfo object.
 * @constructor
 * @param {File[]} include - array of include files
 * @param {File[]} source - array of source files
 * @param {File[]} data - array of data files
 * @param {function} addFile - function to add a file
 */
var ProjectInfo = function (include, source, data, addFile) {
    if (typeof(include) !== 'object' || typeof(source) !== 'object' || typeof(data) !== 'object' || typeof(addFile) !== 'function') {
        throw new Error("False arguments")
    }
    /**
     * array of include files
     * @type {File[]}
     */
    this.include = include

    /**
     * Array of source files
     * @type {File[]}
     */
    this.source = source

    /**
     * Array of data files
     * @type {File[]}
     */
    this.data = data

    /**
     * Adds a file to the project.
     * @method
     * @param {string} dir - name of the directory
     * @param {string} name - name of the file
     * @returns {Promise.<File, error>}
     */
    this.addFile = addFile
}
//</editor-fold>

//<editor-fold desc="File">
/**
 * Creates a File object.
 * @constructor
 * @param {string} name - name of the file
 * @param {string} path - path to the file
 * @param {function} load - function to load the file
 * @param {function} del - function to delete the file
 * @param {function} save - function to save new content to the file
 */
var File = function (name, path, load, del, save) {
    if (typeof(name) !== 'string' || typeof(path) !== 'string' || typeof(load) !== 'function'
        || typeof(del) !== 'function' || typeof(save) !== 'function') {
        throw new Error("False arguments")
    }
    /**
     * name of the file
     * @type {string}
     */
    this.name = name

    /**
     * path of the file
     * @type {string}
     */
    this.path = path

    /**
     * Loads the content of the File.
     * @method
     * @returns {Promise.<string, error>}
     */
    this.load = load

    /**
     * Deletes the file.
     * @method
     * @returns {Promise.<void, error>}
     */
    this.delete = del

    /**
     * Saves content to the file.
     * @method
     * @param {string} content - new content
     * @returns {Promise.<void, error>}
     */
    this.save = save
}
//</editor-fold>

//<editor-fold desc="HarrogateClient">
/**
 * Creates a HarrogateClient object
 * @constructor
 * @param {string} ip - The ip adress/url of the Harrogate Server
 */
var HarrogateClient = function (ip) {
    //<editor-fold desc="HarrogateClient.url">
    if (typeof(ip) !== 'string') {
        throw new Error('Ip must be a String')
    }
    /**
     * url of the Harrogate Server
     * @type {string}
     */
    this.url = 'http://' + ip.replace('http://', '').replace('https://', '')
    //</editor-fold>

    //<editor-fold desc="HarrogateConnector.users">
    /**
     * Gets an array of all users.
     * @returns {Promise.<User[], error>}
     */
    this.getUsers = function () {
        return new Promise(function (resolve, reject) {
            web.get(this.url + '/api/projects/users').then(function (res) {
                var names = Object.keys(res.data)
                var end = []
                for (var i = 0; i < names.length; i++) {
                    end.push(new User(names[i],
                        this.deleteUser.bind(this, names[i]),
                        this.getProjects.bind(this, names[i]),
                        this.addProject.bind(this, names[i]),
                        this.deleteProject.bind(this, names[i])))
                }
                resolve(end)
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Adds a new Uuer.
     * @param {string} username - name of the user
     * @returns {Promise.<User, error>}
     */
    this.addUser = function (username) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string') {
                reject(new Error('Username must be a string'))
            }
            web.put(this.url + '/api/projects/users/' + username).then(function () {
                resolve(new User(username,
                    this.deleteUser.bind(this, username),
                    this.getProjects.bind(this, username),
                    this.addProject.bind(this, username),
                    this.deleteProject.bind(this, username)))
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Deletes an user.
     * @param {string} username - name of the user
     * @returns {Promise.<void, error>}
     */
    this.deleteUser = function (username) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string') {
                reject(new Error('Username must be a string'))
            }
            web.delete(this.url + '/api/projects/users/' + username).then(resolve).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }
    //</editor-fold>

    //<editor-fold desc="HarrogateConnector.projects">
    /**
     * Gets the projects of all users.
     * @returns {Promise.<Project[], error>}
     */
    this.allProjects = function () {
        return new Promise(function (resolve, reject) {
            this.getUsers().then(function (users) {
                var promises = []
                for (var i = 0; i < users.length; i++) {
                    promises.push(users[i].getProjects())
                }
                Promise.all(promises).then(function (values) {
                    var end = []
                    for (var i = 0; i < values.length; i++) {
                        end = end.concat(values[i])
                    }
                    resolve(end)
                }).catch(function (err) {
                    reject(err)
                })
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Gets the projects of a specific user.
     * @param {string} username - name of the user
     * @returns {Promise<Project[], error>}
     */
    this.getProjects = function (username) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string') {
                reject(new Error('Username must be a string'))
            }
            web.get(this.url + '/api/projects/' + username).then(function (res) {
                var projects = []
                res.data.projects.forEach(function (p) {
                    projects.push(new Project(p.name,
                        username,
                        this.deleteProject.bind(this, username, p.name),
                        this.compile.bind(this, username, p.name),
                        this.getProjectInformation.bind(this, username, p.name)))
                }.bind(this))
                resolve(projects)
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Adds a project.
     * @param {string} username - name of the user
     * @param {string} projectname - name of the new project
     * @returns {Promise<Project, error>}
     */
    this.addProject = function (username, projectname) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string' || typeof(projectname) !== 'string') {
                reject(new Error('False Arguments'))
            }
            web.post(this.url + '/api/projects/', {
                    language: 'C',
                    name: projectname,
                    src_file_name: 'main.c',
                    user: username
                }
            ).then(function () {
                resolve(new Project(projectname,
                    username,
                    this.deleteProject.bind(this, username, projectname),
                    this.compile.bind(this, username, projectname),
                    this.getProjectInformation.bind(this, username, projectname)))
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Deletes a project.
     * @param {string} username - name of the user
     * @param {string} projectname - name of the project
     * @returns {Promise<void, error>}
     */
    this.deleteProject = function (username, projectname) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string' || typeof(projectname) !== 'string') {
                reject(new Error('False Arguments'))
            }
            web.delete(this.url + '/api/projects/' + username + '/' + projectname).then(resolve).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Compiles a project.
     * @param {string} username - name of the user
     * @param {string} projectname - name of the project
     * @returns {Promise<{stdout: string, stderr: string}, error>}
     */
    this.compile = function (username, projectname) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string' || typeof(projectname) !== 'string') {
                reject(new Error('False Arguments'))
            }
            web.post(this.url + '/api/compile', {
                name: projectname,
                user: username
            }).then(function (res) {
                delete res.data.result["error"]
                resolve(res.data.result)
            }).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Gets information of a project.
     * @param {string} username - name of the user
     * @param {string} project - name of the project
     * @returns {Promise<ProjectInfo, error>}
     */
    this.getProjectInformation = function (username, project) {
        return new Promise(function (resolve, reject) {
            if (typeof(username) !== 'string' || typeof(project) !== 'string') {
                reject(new Error('False Arguments'))
            }
            web.get(this.url + '/api/projects/' + username + '/' + project).then(function (res) {
                var include = [], src = [], data = []
                res.data.include_files.forEach(function (file) {
                    src.push(new File(file.name,
                        file.path,
                        this.loadFilePath.bind(this, file.path),
                        this.deleteFilePath.bind(this, file.path),
                        this.saveFilePath.bind(this, file.path)))
                }.bind(this))
                res.data.source_files.forEach(function (file) {
                    src.push(new File(file.name,
                        file.path,
                        this.loadFilePath.bind(this, file.path),
                        this.deleteFilePath.bind(this, file.path),
                        this.saveFilePath.bind(this, file.path)))
                }.bind(this))
                res.data.data_files.forEach(function (file) {
                    src.push(new File(file.name,
                        file.path,
                        this.loadFilePath.bind(this, file.path),
                        this.deleteFilePath.bind(this, file.path),
                        this.saveFilePath.bind(this, file.path)))
                }.bind(this))
                resolve(new ProjectInfo(include, src, data, this.addFile.bind(this, username, project)))
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }
    //</editor-fold>

    //<editor-fold desc="HarrogateConnector.files">
    /**
     * Loads the content of a file.
     * @param {string} username - name of the user
     * @param {string} project - name of the project
     * @param {string} dir - name of the directory
     * @param {string} name - name of the file
     * @returns {Promise.<string, error>}
     */
    this.loadFile = function (username, project, dir, name) {
        return this.loadFilePath('/root/Documents/KISS/' + username + '/' + project + '/' + dir + '/' + name)
    }

    /**
     * Loads the content of a file.
     * @param {string} filepath - path of the file
     * @returns {Promise.<string, error>}
     */
    this.loadFilePath = function (filepath) {
        return new Promise(function (resolve, reject) {
            if (typeof(filepath) !== 'string') {
                reject(new Error('False Arguments'))
            }
            web.get(this.url + '/api/fs' + filepath).then(function (res) {
                resolve(new Buffer(res.data.content, 'base64').toString('ascii'))
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Adds a file.
     * @param {string} username - name of the user
     * @param {string} project - name of the project
     * @param {string} dir - name of the directory
     * @param {string} name - name of the file
     * @returns {Promise.<File, error>}
     */
    this.addFile = function (username, project, dir, name) {
        return new Promise(function (resolve, reject) {
            web.post(this.url + '/api/fs/root/Documents/KISS/' + username + '/' + project + '/' + dir + '/', {
                name: name,
                type: 'file',
                content: ''
            }).then(function () {
                var path = '/root/Documents/KISS/' + username + '/' + project + '/' + dir + '/' + name
                resolve(new File(name,
                    path,
                    this.loadFilePath.bind(this, path),
                    this.deleteFilePath.bind(this, path),
                    this.saveFilePath.bind(this, path)))
            }.bind(this)).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Adds a file.
     * @param {string} filepath - path of the file
     * @returns {Promise.<File, error>}
     */
    this.addFilePath = function (filepath) {
        var split = filepath.split('/')
        split = split.splice(temp.length - 4, 4)
        return this.addFile(split[0], split[1], split[2], split[3]);
    }

    /**
     * Deletes a file.
     * @param {string} username - name of the user
     * @param {string} project - name of the project
     * @param {string} dir - name of the directory
     * @param {string} name - name of the file
     * @returns {Promise.<void, error>}
     */
    this.deleteFile = function (username, project, dir, name) {
        return this.deleteFilePath('/root/Documents/KISS/' + username + '/' + project + '/' + dir + '/' + name)
    }

    /**
     * Deletes a file.
     * @param {string} filepath - path of the file
     * @returns {Promise.<void, error>}
     */
    this.deleteFilePath = function (filepath) {
        return new Promise(function (resolve, reject) {
            web.delete(this.url + '/api/fs' + filepath).then(resolve).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }

    /**
     * Saves a file.
     * @param {string} username - name of the user
     * @param {string} project - name of the project
     * @param {string} dir - name of the directory
     * @param {string} name - name of the file
     * @param {string} content - contant to save
     * @returns {Promise.<void, error>}
     */
    this.saveFile = function (username, project, dir, name, content) {
        return this.saveFilePath('/root/Documents/KISS/' + username + '/' + project + '/' + dir + '/' + name, content)
    }

    /**
     * Saves a file.
     * @param {string} filepath - path of the file
     * @param {string} content - contant to save
     * @returns {Promise.<void, error>}
     */
    this.saveFilePath = function (filepath, content) {
        return new Promise(function (resolve, reject) {
            web.put(this.url + '/api/fs' + filepath, {
                content: new Buffer(content, 'ascii').toString('base64'),
                encoding: 'ascii'
            }).then(resolve).catch(function (err) {
                reject(err)
            })
        }.bind(this))
    }
    //</editor-fold>
}
//</editor-fold>

module.exports = HarrogateClient