Parcourir la source

Coté serveur

François Gautrais il y a 7 ans
Parent
commit
64092a3305

+ 43 - 0
server/Errors.js

@@ -0,0 +1,43 @@
+module.exports = {
+
+
+  SUCCESS:            0,
+  EPERM:              1,
+  ENOENT:             2,
+  EINVAL:             22,
+
+  UNKNWON:            -1,
+  BAD_USER:           -2,
+  USER_EXISTS:        -3,
+  BAD_PROJECT:        -4,
+  PROJECT_EXISTS:     -5,
+  BAD_RES:            -6,
+  RES_EXISTS:         -7,
+  AUTH_FAILED:        -8,
+
+  messages :
+  {
+    '0' :             ["Success", 200],
+    '1':              ["Opération interdite", 403],
+    '2':              ["Fichier introuvable", 404],
+    '22':             ["Mauvais argument(s)",400],
+
+    '-1':             ["Erreur inconnue", 400],
+    '-2':             ["Utilisateur inconnu", 400],
+    '-3':             ["Utilisateur déja existant", 400],
+    '-4':             ["Projet inconnu", 400],
+    '-6':             ["Ressource inconnue", 400],
+    '-7':             ["Ressource déjà existant", 400],
+    '-5':             ["Projet déjà existant", 400],
+    '-8':             ["Echec de l'authentification", 403]
+  },
+
+  check : function(x)
+  {
+    if(x==undefined || x==null || ( Number.isInteger(x) && x!=0) )
+      return false;
+    return true;
+  }
+
+
+}

+ 132 - 0
server/Project.js

@@ -0,0 +1,132 @@
+var SavableData = require("./SavableData");
+var global = require('./global')
+var E = require("./Errors");
+var fs = require("fs");
+var Resource = require("./Resource");
+var utils = require('./utils');
+
+module.exports = class Project extends SavableData {
+  constructor()
+  {
+    super();
+    this.stages = [];
+    this.map = "";
+    this.name = "";
+    this.exclude = ["basePath"];
+    this.location = null;
+    this.basePath = "";
+    this.user=null;
+    this.resources = {}
+  }
+
+
+  load(user, name)
+  {
+    this.name=name;
+    this.basePath = global.pathToProjectDir(user, name);
+    this.path = global.pathToProjectFile(user, name);
+
+    try {
+      var obj = JSON.parse(fs.readFileSync(this.path));
+      if(obj!=null) Object.assign(this, obj);
+    } catch (e) {
+      return E.ENOENT;
+    }
+
+    return this;
+  }
+
+  getResource(user, project, resName)
+  {
+    var res = new Resource();
+    return  res.load(user, project, resName);
+  }
+
+
+  createResource(user, project, res)
+  {
+    var old = this.getResource(user, project, res);
+    if(E.check(old))
+      return E.PROJECT_EXISTS;
+
+    var p = new Resource();
+    p.name=res;
+    p.save(global.pathToResourceFile(user, project, res));
+    this.resources[res] = true;
+
+    this.save();
+    return E.SUCCESS;
+  }
+
+  renameResource(user, project, oldName, newName)
+  {
+
+    var n = this.getResource(user, project, oldName);
+    n.name=newName;
+
+    var dir = global.pathToResourceDir(user, project);
+    var oldPath = global.pathToResourceFile(user, project, oldName);
+    var newPath = global.pathToResourceFile(user, project, newName);
+    try {
+      utils.mv(oldPath, newPath);
+      if(this.location!=null)
+      {
+        var oldResPath=this.location.path;
+        this.location.path=dir+newName+this.location.ext;
+        utils.mv(oldResPath, this.location.path);
+      }
+    } catch (e) {
+      console.log(e);
+      return E.UNKNWON;
+    }
+
+    delete this.resources[oldName];
+
+    this.resources[newName] = true;
+
+
+    n.save(newPath);
+    this.save(global.pathToProjectFile(user, project));
+
+    return E.SUCCESS;
+  }
+
+  removeResource(user, project, res)
+  {
+    var x = this.getResource(user, project, res);
+    if(!E.check(x))
+      return E.BAD_RES;
+
+    delete this.resources[res];
+    utils.rm(global.pathToResourceFile(user, project, res));
+    if(this.location!=null)
+      utils.rm(this.location.path);
+    this.save(global.pathToProjectFile(user, project));
+    return E.SUCCESS;
+  }
+
+  editResource(user, project, name, data)
+  {
+    if(data.name!=undefined && data.name!=name)
+    {
+      var t = this.renameResource(user, project, name, data.name);
+      if( !E.check(t) )
+        return t;
+      name=data.name;
+    }
+
+    var res = this.getResource(user, project, name);
+    if(!E.check(res))
+      return res;
+
+    Object.assign(res, data);
+
+    res.save(global.pathToResourceFile(user, project, name));
+    return E.SUCCESS;
+  }
+
+
+
+
+
+}

+ 3 - 0
server/README.md

@@ -0,0 +1,3 @@
+Dépendances:
+
+express multer  body-parser

+ 62 - 0
server/Resource.js

@@ -0,0 +1,62 @@
+var SavableData = require("./SavableData");
+var global = require("./global")
+var E = require("./Errors");
+var utils = require('./utils');
+var fs = require("fs");
+
+module.exports = class Resource extends SavableData {
+  constructor()
+  {
+    super();
+    this.name = "";
+    this.model = null;
+    this.position = [0, 0, 0];
+    this.rotation = [0, 0, 0];
+    this.scale = [1, 1, 1];
+    this.comment = "";
+    this.type = Resource.TYPE_IMAGE();
+    this.title = "";
+
+    //this.location = { path: null, ext: null};
+    this.location = null;
+
+  }
+
+  static TYPE_AUDIO()   { return "audio"; }
+  static TYPE_VIDEO()   { return "video"; }
+  static TYPE_3D()      { return "3d"; }
+  static TYPE_IMAGE()   { return "aimage"; }
+
+  exportToString()
+  {
+    var exclude = [""]
+    var obj = {};
+    Object.assign(obj, this);
+  }
+
+  load(user, project, name)
+  {
+    this.name=name;
+    this.basePath = global.pathToResourceDir(user, name);
+    this.path = global.pathToResourceFile(user, project, name);
+
+    try {
+      var obj = JSON.parse(fs.readFileSync(this.path));
+      if(obj!=null) Object.assign(this, obj);
+    } catch (e) {
+      console.log(e);
+      return E.ENOENT;
+    }
+
+    return this;
+  }
+
+
+
+
+
+
+
+
+
+}

+ 61 - 0
server/Response.js

@@ -0,0 +1,61 @@
+var error = require("./Errors");
+
+module.exports = class Response {
+  constructor(code, msg, data)
+  {
+    this.code=0;
+    this.message="Success";
+    this.data=null;
+    if(code!=undefined) this.code=code;
+    if(code!=undefined) this.message=msg;
+    if(data!=undefined) this.data=data;
+  }
+
+  getCode() {return this.code;}
+  getMessage() {return this.message;}
+  getData() {return this.data;}
+
+  setCode(c){ this.code = c; }
+  setMessage(c){ this.message = c; }
+  setData(c){ this.data = c; }
+
+  toString()
+  {
+    return JSON.stringify(this);
+  }
+
+  static fromError(code, data)
+  {
+    var msg = error.messages[code][0];
+    var r = new Response(code, msg, data)
+    if(data==undefined)  delete r.data;
+    return r;
+  }
+
+  static writeResponse(res, err, data)
+  {
+    res.setHeader("Content-Type", "application/json");
+    console.log("1 : "+err);
+    res.status(error.messages[err][1]);
+    res.end(JSON.stringify(Response.fromError(err, data)));
+    if(error.messages[err][1]>=400) return null;
+    return true;
+  }
+
+  //std error
+  static success(data) { return  Response.fromError(error.ESUCCESS, data); }
+  static noent(data) { return  Response.fromError(error.ENOENT, data); }
+  static perm(data) {  return Response.fromError(error.EPERM, data); }
+  static badArgs(data) { return Response.fromError(error.EINVAL, data);}
+
+
+  static badUser(data) { return  Response.fromError(error.BAD_USER, data); }
+  static userExists(data) { return  Response.fromError(error.USER_EXISTS, data); }
+
+  static badProject(data) { return  Response.fromError(error.BAD_PROJECT, data); }
+  static projectExists(data) { return  Response.fromError(error.PROJECT_EXISTS, data); }
+
+  static badRes(data) { return  Response.fromError(error.BAD_RES, data); }
+  static resExists(data) { return  Response.fromError(error.RES_EXISTS, data); }
+
+}

+ 52 - 0
server/SavableData.js

@@ -0,0 +1,52 @@
+
+var fs = require("fs");
+
+module.exports = class SavableData {
+  constructor()
+  {
+      this.path="null";
+      this.exclude=[];
+  }
+
+  load(path)
+  {
+
+    if(path!=undefined) this.path=path;
+    try{
+
+      var str = fs.readFileSync(this.path);
+      var obj = JSON.parse(str);
+
+      if(obj!=null) Object.assign(this, obj);
+    }catch(e)
+    {
+
+    }
+
+    return this;
+  }
+
+  save(p)
+  {
+    if( p!=undefined ) this.path=p;
+    fs.writeFileSync(this.path, this.toString());
+  }
+
+  toString()
+  {
+    return JSON.stringify(this, null, 2);
+  }
+
+  exportToString()
+  {
+    var obj = {};
+    Object.assign(obj, this);
+    for(var i=0; i<this.exclude.length; i++)
+      delete obj[this.exclude[i]];
+    delete this.path;
+    delete this.exclude;
+
+    return JSON.stringify(obj, null, 2);
+  }
+
+}

+ 379 - 0
server/Server.js

@@ -0,0 +1,379 @@
+var Response = require("./Response");
+var R= Response;
+var E = require("./Errors");
+
+var fs = require("fs");
+var UserManager = require("./users");
+
+
+var AUTH_USER="auth_user"
+var AUTH_PASSWORD="auth_password"
+var USER = "user";
+var PASSWORD = "password";
+var PROJECT = "project";
+var DATA = "data";
+var RESOURCE = "res";
+
+function send(res, err, data, log)
+{
+  if(err!=0)
+  {
+    var stack = new Error().stack;
+    console.log(stack);
+  }
+  if(log != undefined)
+  {
+    console.log(log);
+  }
+  Response.writeResponse(res, err, data)
+}
+
+function sendSuccess(res, data)
+{
+   return send(res, E.SUCCESS, data);
+}
+
+function getQueryParam(req, param)
+{
+  if (req.method == "POST") {
+    return req.body[param];
+  }
+  else
+  {
+    return req.query[param];
+  }
+}
+
+module.exports = class Server {
+  constructor()
+  {
+      this.users=new UserManager();
+  }
+
+  /*
+  ** Utils
+  */
+  getUserQuery(req, res)
+  {
+    var name = getQueryParam(req, AUTH_USER);
+    if(typeof name != 'string' || name.length<1 )
+      return send(res, E.AUTH_FAILED, AUTH_USER);
+
+    var user = this.users.getUser(name);
+    if(user==null) return null;
+    return user;
+  }
+
+  getUser(req, res)
+  {
+    var name = req.params[USER];
+    if(typeof name != 'string' || name.length<1 )
+      return send(res, E.EINVAL, USER);
+
+    var user = this.users.getUser(name);
+    if(user==null) return null;
+    return user;
+  }
+
+  getProject(req, res)
+  {
+      var user = this.getUser(req);
+      if(user.code != undefined) return user;
+
+      var pro = req.params[PROJECT];
+      if(typeof pro != 'string' || pro.length<1 )
+        return send(res, E.EINVAL, PROJECT);
+
+      var projet = user.getProject(pro);
+      if(!E.check(projet))
+        return send(res, projet, pro);
+
+      return projet;
+  }
+
+  getResource(req, res)
+  {
+      var projet = this.getProject(req, res);
+      if(projet.code != undefined) return user;
+
+      var pro = req.params[RESOURCE];
+      if(typeof pro != 'string' || pro.length<1 )
+        return send(res, E.EINVAL, RESOURCE);
+
+      var ress = projet.getResource(req.params[USER], req.params[PROJECT], pro);
+      if(!E.check(ress))
+        return send(res, ress, pro);
+
+      return ress;
+  }
+
+  authentification(req, res)
+  {
+    return E.SUCCESS;
+    var password = getQueryParam(req, AUTH_PASSWORD);
+    var urlUser = this.getUserQuery(req, res);
+
+    if(urlUser.password==password) return E.SUCCESS;
+    return send(res, E.AUTH_FAILED, "Login ou mot de passe incorrect");
+  }
+
+
+
+  /*
+  ** Users
+  */
+  serveUser(req, res)
+  {
+    //if(this.authentification(req, res)==null) return null;
+    var user = this.getUser(req, res);
+    if(user==null) return;
+    return sendSuccess(res, user);
+  }
+
+  listUsers(req, res)
+  {
+    //if(this.authentification(req, res)==null) return null;
+    sendSuccess(res, this.users.getUserList());
+  }
+
+  createUser(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var u = getQueryParam(req, USER);
+    var p =getQueryParam(req, PASSWORD);
+
+    if(u==undefined) return send(res, E.BAD_USER, USER);
+    if(p==undefined) return send(res, E.EINVAL, PASSWORD);
+
+    var ret = this.users.createUser(u, p);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, E.USER_EXISTS, u);
+  }
+
+  renameUser(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var oldName = req.params[USER];
+    var newName = getQueryParam(req, "newName");
+
+    var ret = this.users.renameUser(oldName, newName);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret, newName);
+  }
+
+  removeUser(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var name = req.params[USER];
+    var ret = this.users.removeUser(name);
+
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret, name);
+  }
+
+
+  /*
+  POST: { user: "ptitcois", password:"xxxx", data: { [contenu] }}
+  */
+  editUser(req, res)
+  {
+    if(this.authentification(req)==null) return null;
+    var name = req.params[USER];
+    var data = getQueryParam(req, DATA);
+
+
+    if(name==undefined) return send(res, E.EINVAL, USER);
+    if(data==undefined) return send(res, E.EINVAL, DATA);
+
+    var ret = this.users.editUser(name, data);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  /*
+  ** Projects
+  */
+  serveProject(req, res)
+  {
+    //if(this.authentification(req, res)==null) return null;
+    var project = this.getProject(req, res);
+    if(project==null) return;
+    return sendSuccess(res, project);
+  }
+
+  listProjects(req, res)
+  {
+    //if(this.authentification(req, res)==null) return null;
+    var user = this.getUser(req, res);
+    if(user==null) return;
+    sendSuccess(res, user.projects);
+  }
+
+  createProject(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var user = this.getUser(req, res);
+    if(user==null) return;
+
+    var proName = getQueryParam(req, PROJECT);
+    if(proName==undefined) return send(res, E.BAD_USER, PROJECT);
+
+    var ret = user.createProject(proName);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, E.PROJECT_EXISTS, u);
+  }
+
+  renameProject(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var user = this.getUser(req, res);
+    if(user==null) return;
+
+    var oldName = req.params[PROJECT];
+    var newName = getQueryParam(req, "newName");
+
+    var ret = user.renameProject(oldName, newName);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret, newName);
+  }
+
+  removeProject(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var user = this.getUser(req, res);
+    if(user==null) return;
+
+    var name = req.params[PROJECT];
+    var ret = user.removeProject(name);
+
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret, name);
+  }
+
+
+  /*
+  POST: { user: "ptitcois", password:"xxxx", data: { [contenu] }}
+  */
+  editProject(req, res)
+  {
+    if(this.authentification(req)==null) return null;
+    var user = this.getUser(req, res);
+    if(user==null) return;
+
+    var name = req.params[PROJECT];
+    var data = getQueryParam(req, DATA);
+
+
+    if(name==undefined) return send(res, E.EINVAL, PROJECT);
+    if(data==undefined) return send(res, E.EINVAL, DATA);
+
+    var ret = user.editProject(name, data);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret);
+  }
+
+
+
+
+
+
+  //
+  //  Resources
+  //
+  serveResource(req, res)
+  {
+    //if(this.authentification(req, res)==null) return null;
+    var r = this.getResource(req, res);
+    if(r==null) return;
+    return sendSuccess(r, project);
+  }
+
+  listResources(req, res)
+  {
+    //if(this.authentification(req, res)==null) return null;
+    var pro = this.getProject(req, res);
+    if(pro==null) return;
+    sendSuccess(res, user.resources);
+  }
+
+  createResource(req, res)
+  {
+    console.log("A");
+    if(this.authentification(req, res)==null) return null;
+    var pro = this.getProject(req, res);
+    if(pro==null) return;
+
+      console.log("B");
+    var resName = getQueryParam(req, RESOURCE);
+
+      console.log("C");
+    if(resName==undefined) return send(res, E.BAD_USER, RESOURCE);
+
+      console.log("D");
+    var ret = pro.createResource(req.params[USER], req.params[PROJECT], resName);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, E.PROJECT_EXISTS, resName);
+  }
+
+  renameResource(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var pro = this.getProject(req, res);
+    if(pro==null) return;
+
+    var oldName = req.params[RESOURCE];
+    var newName = getQueryParam(req, "newName");
+
+    var ret = pro.renameResource(req.params[USER], req.params[PROJECT], oldName, newName);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret, newName);
+  }
+
+  removeResource(req, res)
+  {
+    if(this.authentification(req, res)==null) return null;
+    var pro = this.getProject(req, res);
+    if(pro==null) return;
+
+    var name = req.params[RESOURCE];
+    var ret = pro.removeResource(req.params[USER], req.params[PROJECT], name);
+    console.log("string : "+JSON.stringify(ret));
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret, name);
+  }
+
+
+  /*
+  POST: { user: "ptitcois", password:"xxxx", data: { [contenu] }}
+  */
+  editRescource(req, res)
+  {
+    console.log("ICIIIIIIIIIIIIIIII")
+    if(this.authentification(req, res)==null) return null;
+    var pro = this.getProject(req, res);
+    if(pro==null) return;
+
+    var name = req.params[RESOURCE];
+    var data = getQueryParam(req, DATA);
+    console.log(JSON.stringify(req.body))
+
+    if(name==undefined) return send(res, E.EINVAL, RESOURCE);
+    if(data==undefined) return send(res, E.EINVAL, DATA, "Parametre 'data' no présent");
+
+    var ret = pro.editResource(req.params[USER], req.params[PROJECT], name, data);
+    if(E.check(ret)) return  sendSuccess(res);
+    return send(res, ret);
+  }
+
+}

+ 8 - 0
server/data/users.json

@@ -0,0 +1,8 @@
+{
+  "path": "data/users.json",
+  "exclude": [],
+  "index": 1,
+  "users": {
+    "0": "ptitcois1"
+  }
+}

+ 16 - 0
server/data/users/ptitcois1/MonProjet/project.json

@@ -0,0 +1,16 @@
+{
+  "path": "data/users/ptitcois1/MonProjet/project.json",
+  "exclude": [
+    "basePath"
+  ],
+  "stages": [],
+  "map": "",
+  "name": "MonProjet",
+  "location": null,
+  "basePath": "",
+  "user": null,
+  "resources": {
+    "MaDeuxiemeRes": true,
+    "Nouvelle": true
+  }
+}

+ 26 - 0
server/data/users/ptitcois1/MonProjet/resources/MaDeuxiemeRes.json

@@ -0,0 +1,26 @@
+{
+  "path": "data/users/ptitcois1/MonProjet/resources/MaDeuxiemeRes.json",
+  "exclude": [],
+  "name": "MaDeuxiemeRes",
+  "model": null,
+  "position": [
+    1,
+    2,
+    3
+  ],
+  "rotation": [
+    0,
+    0,
+    0
+  ],
+  "scale": [
+    1,
+    1,
+    1
+  ],
+  "comment": "Bonjour !",
+  "type": "aimage",
+  "title": "",
+  "location": null,
+  "basePath": "data/users/ptitcois1/MaDeuxiemeRes/resources/"
+}

+ 26 - 0
server/data/users/ptitcois1/MonProjet/resources/Nouvelle.json

@@ -0,0 +1,26 @@
+{
+  "path": "data/users/ptitcois1/MonProjet/resources/Nouvelle.json",
+  "exclude": [],
+  "name": "Nouvelle",
+  "model": null,
+  "position": [
+    4,
+    5,
+    6
+  ],
+  "rotation": [
+    0,
+    0,
+    0
+  ],
+  "scale": [
+    1,
+    1,
+    1
+  ],
+  "comment": "Au revoir !",
+  "type": "aimage",
+  "title": "",
+  "location": null,
+  "basePath": "data/users/ptitcois1/AutreRes/resources/"
+}

+ 12 - 0
server/data/users/ptitcois1/user.json

@@ -0,0 +1,12 @@
+{
+  "path": "null",
+  "exclude": [],
+  "name": "ptitcois1",
+  "password": "azerty",
+  "groups": {
+    "user": true
+  },
+  "projects": {
+    "MonProjet": true
+  }
+}

+ 38 - 0
server/global.js

@@ -0,0 +1,38 @@
+const path = require('path');
+
+
+module.exports.userPath = "data/users/";
+module.exports.pathToUserDir = function (u)
+{
+  return  module.exports.userPath+u+"/";
+}
+
+module.exports.pathToUserFile = function (u)
+{
+  return  module.exports.pathToUserDir(u)+"user.json";
+}
+
+module.exports.pathToProjectDir = function (u, p)
+{
+  return module.exports.pathToUserDir(u) + p+"/";
+}
+
+
+module.exports.pathToProjectFile = function (u, p)
+{
+  return module.exports.pathToProjectDir(u, p)+"project.json";
+}
+
+module.exports.pathToResourceDir = function (u, p)
+{
+  return module.exports.pathToProjectDir(u, p)+"resources/";
+}
+module.exports.pathToResourceFile = function (u, p, r)
+{
+  return module.exports.pathToResourceDir(u, p)+r+".json";
+}
+
+module.exports.groups = {
+  user: "user",
+  admin: "admin"
+}

+ 111 - 0
server/main.js

@@ -0,0 +1,111 @@
+var express = require('express');
+var app = express();
+var UserManager = require("./users");
+var Response = require("./Response");
+var multer = require("multer");
+var path = require("path");
+var crypto = require("crypto");
+var mime = require("mime");
+var Server  = require("./Server");
+var utils  = require("./utils");
+var upload = multer({
+  dest: 'tmp/' // this saves your file into a directory called "uploads"
+});
+
+
+var bodyParser = require('body-parser')
+app.use( bodyParser.json() );       // to support JSON-encoded bodies
+app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
+  extended: true
+}));
+
+const prefix = "";
+const apiprefix = prefix+"/api";
+const appprefix = prefix+"/app";
+
+var server = new Server();
+
+
+var storage = multer.diskStorage({
+  destination: function(req, file, cb) {
+      cb(null, 'tmp/')
+  },
+  filename: function(req, file, cb) {
+      crypto.pseudoRandomBytes(16, function(err, raw) {
+          cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype));
+      });
+    }
+});
+
+var upload = multer({
+  storage: storage
+});
+
+var userList = new UserManager();
+
+
+//users
+app.get(apiprefix+'/createUser', function (a, b) {server.createUser(a, b)});
+app.get(apiprefix+'/users', function (a, b) {server.listUsers(a, b)});
+app.get(apiprefix+'/user/:user', function (a, b) {server.serveUser(a, b)});
+app.post(apiprefix+'/createUser', function (a, b) {server.createUser(a, b)});
+app.post(apiprefix+'/users', function (a, b) {server.listUsers(a, b)});
+app.post(apiprefix+'/user/:user', function (a, b) {server.serveUser(a, b)});
+
+app.post(apiprefix+'/user/:user/edit', function (a, b) {server.editUser(a, b)});
+app.get(apiprefix+'/user/:user/rename', function (a, b) {server.renameUser(a, b)});
+app.post(apiprefix+'/user/:user/rename', function (a, b) {server.renameUser(a, b)});
+app.get(apiprefix+'/user/:user/remove', function (a, b) {server.removeUser(a, b)});
+app.post(apiprefix+'/user/:user/remove', function (a, b) {server.removeUser(a, b)});
+
+
+//Projects
+app.get(apiprefix+'/user/:user/createProject', function (a, b) {console.log("_1"); server.createProject(a, b)});
+app.get(apiprefix+'/user/:user/projects', function (a, b) {server.listProjects(a, b)});
+
+app.get(apiprefix+'/user/:user/:project', function (a, b) { server.serveProject(a, b)});
+app.post(apiprefix+'/user/:user/:project/edit', function (a, b) {server.editProject(a, b)});
+app.get(apiprefix+'/user/:user/:project/rename', function (a, b) {server.renameProject(a, b)});
+app.post(apiprefix+'/user/:user/:project/rename', function (a, b) {server.renameProject(a, b)});
+app.get(apiprefix+'/user/:user/:project/remove', function (a, b) {server.removeProject(a, b)});
+app.post(apiprefix+'/user/:user/:project/remove', function (a, b) {server.removeProject(a, b)});
+
+
+
+//resources
+app.get(apiprefix+'/user/:user/:project/createResource', function (a, b) {console.log("_1"); server.createResource(a, b)});
+app.get(apiprefix+'/user/:user/:project/resources', function (a, b) {server.listResources(a, b)});
+
+app.get(apiprefix+'/user/:user/:project/:res', function (a, b) { server.serveResource(a, b)});
+app.post(apiprefix+'/user/:user/:project/:res/edit', function (a, b) {server.editRescource(a, b)});
+app.get(apiprefix+'/user/:user/:project/:res/rename', function (a, b) {server.renameResource(a, b)});
+app.post(apiprefix+'/user/:user/:project/:res/rename', function (a, b) {server.renameResource(a, b)});
+app.get(apiprefix+'/user/:user/:project/:res/remove', function (a, b) {server.removeResource(a, b)});
+app.post(apiprefix+'/user/:user/:project/:res/remove', function (a, b) {server.removeResource(a, b)});
+
+
+/*
+app.post(apiprefix+'/user/:user/:project/:resource', upload.single("image"), function(req, res) {
+  res.send('<img src="'+apiprefix+'/upload/' + req.file.filename + '" />');
+});
+
+app.get(apiprefix+'/upload/:file', function(req, res) {
+  res.sendFile(path.join(__dirname + '/tmp/'+req.params.file));
+});
+
+
+app.get(appprefix+'/:file', function (req, res) {
+  res.sendFile(path.join(__dirname + '/../www/'+req.params.file));
+});
+
+
+app.get(apiprefix+'/user/:name', function (req, res) { server.serveUser(req, res);});*/
+
+
+var rest = app.listen(8081, function () {
+
+  var host = rest.address().address
+  var port = rest.address().port
+  console.log("Example app listening at http://%s:%s", host, port)
+
+})

+ 119 - 0
server/user.js

@@ -0,0 +1,119 @@
+
+
+var DataSavable = require("./SavableData");
+var Project = require("./Project");
+var E = require("./Errors");
+var utils = require('./utils');
+var global = require("./global");
+var fs = require("fs");
+
+module.exports = class User extends DataSavable{
+    constructor(name, password)
+    {
+      super();
+      this.name="";
+      this.password="";
+      this.groups={ user: true };
+      this.projects={}; // { name= path}
+      if(name!=undefined) this.name=name;
+      if(password!=undefined) this.password=password;
+
+    }
+
+    getProject(projectName)
+    {
+      var project = new Project();
+      return  project.load(this.name, projectName);
+    }
+
+    save()
+    {
+      fs.writeFileSync(global.pathToUserFile(this.name), this.toString());
+    }
+
+    load(name)
+    {
+      if( name!=undefined ) this.path=global.pathToUserFile(name);
+      var obj = JSON.parse(fs.readFileSync(this.path));
+      if(obj!=null) Object.assign(this, obj);
+      return this;
+    }
+
+
+
+
+    createProject(project)
+    {
+      var old = this.getProject(project);
+      if(E.check(old))
+        return E.PROJECT_EXISTS;
+
+      utils.mkdir(global.pathToProjectDir(this.name, project));
+      utils.mkdir(global.pathToResourceDir(this.name, project));
+      var p = new Project();
+      p.name=project;
+      p.save(global.pathToProjectFile(this.name, project));
+      this.projects[project] = true;
+
+      this.save();
+      return E.SUCCESS;
+    }
+
+    renameProject(oldName, newName)
+    {
+
+      var n = this.getProject(oldName);
+      n.name=newName;
+
+      var oldPath = global.pathToProjectDir(this.name, oldName);
+      var newPath = global.pathToProjectDir(this.name, newName);
+      try {
+        utils.mv(oldPath, newPath);
+      } catch (e) {
+        return E.UNKNWON;
+      } finally {
+      }
+
+      delete this.projects[oldName];
+      this.projects[newName] = true;
+
+      n.save(global.pathToProjectFile(this.name, newName));
+      this.save();
+
+
+      return E.SUCCESS;
+    }
+
+    removeProject(project)
+    {
+      var x = this.getProject(project);
+      if(!E.check(x))
+        return E.BAD_PROJECT;
+
+      delete this.projects[project];
+      utils.rmdir(global.pathToProjectDir(this.name, project));
+      this.save(global.pathToUserFile(this.name));
+    }
+
+    editProject(name, data)
+    {
+      if(data.name!=undefined && data.name!=name)
+      {
+        var t = this.renameProject(name, data.name);
+        if( !E.check(t) )
+          return t;
+        this.save();
+        name=data.name;
+      }
+
+      var pro = this.getProject(name);
+      if(!E.check(pro))
+        return pro;
+
+      Object.assign(pro, data);
+
+      pro.save(global.pathToProjectFile(this.name, name));
+      return E.SUCCESS;
+    }
+
+}

+ 129 - 0
server/users.js

@@ -0,0 +1,129 @@
+var User = require("./user");
+var DataSavable = require("./SavableData");
+var E = require("./Errors");
+var utils = require('./utils');
+var global = require("./global");
+var fs = require("fs");
+
+
+
+module.exports = class UserManager extends DataSavable{
+  constructor()
+  {
+    super();
+    utils.mkdir(global.userPath);
+    this.index=0;
+    this.users={}; // id: name
+    this.path = "data/users.json";
+    this.load();
+  }
+
+  createUser(name, password)
+  {
+    console.log("createUser('"+name+"', '"+password+"')")
+    if(this.findIdByName(name)>=0) return -1;
+    var u = new User( name, password);
+    this.users[this.index]=name;
+    this.index++;
+    utils.mkdir(global.pathToUserDir(name));
+    u.save();
+    this.save();
+    return u;
+  }
+
+  removeUser(name)
+  {
+    var user = this.getUser(name);
+    if(!E.check(user))
+      return user;
+
+    var id = this.findIdByName(name);
+    delete this.users[id];
+    console.log("-- "+global.pathToUserDir(name)+" --")
+    utils.rmdir(global.pathToUserDir(name));
+
+    this.save();
+    return E.SUCCESS;
+  }
+
+  renameUser(oldName, newName)
+  {
+
+
+    var oldPath = global.pathToUserDir(oldName);
+    var newPath = global.pathToUserDir(newName);
+
+    console.log(oldPath+" -> "+newPath);
+    try {
+      utils.mv(oldPath, newPath);
+    } catch (e) {
+      return E.UNKNWON;
+    } finally {
+    }
+
+    var id = this.findIdByName(oldName);
+    this.users[id]=newName;
+    this.save();
+
+
+    var user = this.getUser(newName);
+    if(!E.check(user))
+      return user;
+
+    user.name=newName;
+    user.save();
+    return E.SUCCESS;
+  }
+
+  editUser(name, data)
+  {
+
+    console.log("\n\n'"+data.name+"' "+"'"+name+"'")
+    if(data.name!=undefined && data.name!=name)
+    {
+      var t = this.renameUser(name, data.name);
+      if( !E.check(t) )
+        return t;
+      this.save();
+      name=data.name;
+    }
+
+    var user = this.getUser(name);
+    if(!E.check(user))
+      return user;
+
+            console.log("\n\ndata: "+JSON.stringify(data));
+                  console.log("avant: "+JSON.stringify(user));
+    Object.assign(user, data);
+          console.log("apres: "+JSON.stringify(user));
+    user.save();
+    return E.SUCCESS;
+  }
+
+
+
+
+  findIdByName(name)
+  {
+    var keys = Object.keys(this.users);
+    for(var i=0; i<keys.length; i++)
+      if(this.users[keys[i]]==name)
+        return keys[i];
+    return -1;
+  }
+
+  getUser(name)
+  {
+    var id = this.findIdByName(name);
+    if(id<0) return E.BAD_USER;
+    var user = new User();
+    return user.load(name);
+  }
+
+  getUserList()
+  {
+    return  Object.values(this.users);
+  }
+
+
+}

+ 55 - 0
server/utils.js

@@ -0,0 +1,55 @@
+const fs = require('fs');
+const path = require('path');
+
+
+
+
+function mkdir(targetDir, {isRelativeToScript = false} = {}) {
+  const sep = path.sep;
+  const initDir = path.isAbsolute(targetDir) ? sep : '';
+  const baseDir = isRelativeToScript ? __dirname : '.';
+
+  targetDir.split(sep).reduce((parentDir, childDir) => {
+    const curDir = path.resolve(baseDir, parentDir, childDir);
+    try {
+      fs.mkdirSync(curDir);
+    } catch (err) {
+      if (err.code !== 'EEXIST') {
+        throw err;
+      }
+    }
+
+    return curDir;
+  }, initDir);
+}
+
+
+function rmdir(p) {
+  console.log("path = "+p);
+  if (fs.existsSync(p)) {
+    fs.readdirSync(p).forEach(function(file, index){
+      var curPath = p + "/" + file;
+      if (fs.lstatSync(curPath).isDirectory()) { // recurse
+        rmdir(curPath);
+      } else { // delete file
+        fs.unlinkSync(curPath);
+      }
+    });
+    fs.rmdirSync(p);
+  }
+};
+
+function mv(old, ne) {
+  console.log("old: '"+old+"'   new = '"+ne+"'")
+  return fs.renameSync(old, ne);
+};
+
+function rm(file)
+{
+  fs.unlinkSync(file);
+}
+
+module.exports.mkdir = mkdir;
+module.exports.rmdir = rmdir;
+module.exports.mv = mv;
+module.exports.rm = rm;