Commit 0e5d90f3 by Arturo Montejo Ráez

Merge branch 'develop'

parents 2739a393 a9098263
Showing with 368 additions and 119 deletions
...@@ -90,7 +90,7 @@ public class PCBDBHelper extends SQLiteOpenHelper { ...@@ -90,7 +90,7 @@ public class PCBDBHelper extends SQLiteOpenHelper {
private void setCurrentUser(User user) { private void setCurrentUser(User user) {
this.currentUser = user; this.currentUser = user;
PCBcontext.getDevice().setLastStuId(user.get_id_stu()); PCBcontext.getDevice().setLastStuId(user.get_id_stu());
PCBcontext.getDevice().setLastSupId(user.get_id_sup()); if (user.is_supervisor()) PCBcontext.getDevice().setLastSupId(user.get_id_sup());
} }
/** /**
......
package com.yottacode.pictogram.net; package com.yottacode.pictogram.net;
import android.content.Intent;
import android.util.Log; import android.util.Log;
import com.yottacode.net.RestapiWrapper; import com.yottacode.net.RestapiWrapper;
...@@ -98,6 +99,10 @@ public class NetService implements Runnable { ...@@ -98,6 +99,10 @@ public class NetService implements Runnable {
PCBcontext.unset_user(); PCBcontext.unset_user();
this.device.restart_app(); this.device.restart_app();
} }
public void restart_app(Intent intent) {
PCBcontext.unset_user();
this.device.restart_app(intent);
}
/** /**
* ping to the server by using a restapi call. If ok, the call will return the empty set * ping to the server by using a restapi call. If ok, the call will return the empty set
......
package com.yottacode.pictogram.net; package com.yottacode.pictogram.net;
import android.content.Intent;
/** /**
* Created by Fernando on 12/08/2016. * Created by Fernando on 12/08/2016.
*/ */
...@@ -9,4 +11,5 @@ public interface iNetServiceDevice { ...@@ -9,4 +11,5 @@ public interface iNetServiceDevice {
public void notifyStatus(boolean updated); public void notifyStatus(boolean updated);
public void closeNotifyStatus(); public void closeNotifyStatus();
public void restart_app(); public void restart_app();
public void restart_app(Intent intent);
} }
...@@ -209,8 +209,8 @@ INSTEAD OF INSERT ON users_detail ...@@ -209,8 +209,8 @@ INSTEAD OF INSERT ON users_detail
FOR EACH ROW FOR EACH ROW
WHEN NEW.pwd_stu IS NULL WHEN NEW.pwd_stu IS NULL
BEGIN BEGIN
INSERT OR REPLACE INTO student(id,nickname, name, surname, url_img, gender, lang, attributes) INSERT OR REPLACE INTO student(id,nickname, pwd, name, surname, url_img, gender, lang, attributes)
VALUES (NEW.id_stu, NEW.nickname_stu, NEW.name_stu, NEW.surname_stu, NEW.url_img_stu, NEW.gender_stu, NEW.lang_stu, NEW.attributes_stu); VALUES (NEW.id_stu, NEW.nickname_stu, (SELECT pwd FROM student WHERE id=NEW.id_stu), NEW.name_stu, NEW.surname_stu, NEW.url_img_stu, NEW.gender_stu, NEW.lang_stu, NEW.attributes_stu);
INSERT OR REPLACE INTO supervisor VALUES (NEW.id_sup, NEW.email_sup, NEW.pwd_sup, NEW.name_sup, NEW.surname_sup, NEW.url_img_sup, NEW.gender_sup, NEW.lang_sup, NEW.tts_engine_sup); INSERT OR REPLACE INTO supervisor VALUES (NEW.id_sup, NEW.email_sup, NEW.pwd_sup, NEW.name_sup, NEW.surname_sup, NEW.url_img_sup, NEW.gender_sup, NEW.lang_sup, NEW.tts_engine_sup);
INSERT OR REPLACE INTO users VALUES (NEW.id_stu,NEW.id_sup); INSERT OR REPLACE INTO users VALUES (NEW.id_stu,NEW.id_sup);
END END
......
...@@ -6,6 +6,7 @@ import android.content.ClipData; ...@@ -6,6 +6,7 @@ import android.content.ClipData;
import android.content.ClipDescription; import android.content.ClipDescription;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
...@@ -31,6 +32,7 @@ import android.widget.ImageButton; ...@@ -31,6 +32,7 @@ import android.widget.ImageButton;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.Toast; import android.widget.Toast;
import com.yottacode.pictogram.dao.User;
import com.yottacode.pictogram.net.iImgDownloaderListener; import com.yottacode.pictogram.net.iImgDownloaderListener;
import com.yottacode.pictogram.tablet.R; import com.yottacode.pictogram.tablet.R;
import com.yottacode.pictogram.action.PictosAction; import com.yottacode.pictogram.action.PictosAction;
...@@ -43,18 +45,22 @@ import com.yottacode.pictogram.net.PictoUploader; ...@@ -43,18 +45,22 @@ import com.yottacode.pictogram.net.PictoUploader;
import com.yottacode.pictogram.tools.Img; import com.yottacode.pictogram.tools.Img;
import com.yottacode.pictogram.tools.PCBcontext; import com.yottacode.pictogram.tools.PCBcontext;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
public class PictogramActivity extends Activity implements iVocabularyListener, TextToSpeech.OnInitListener { public class PictogramActivity extends Activity implements iVocabularyListener, TextToSpeech.OnInitListener {
public static final String PREFS_NAME = "MyPrefsFile";
// Main layout for this activity // Main layout for this activity
RelativeLayout mainLayout; RelativeLayout mainLayout;
// Adapter for de grid showing the categories grid (and main pictos) // Adapter for de grid showing the categories grid (and main pictos)
...@@ -739,8 +745,49 @@ public class PictogramActivity extends Activity implements iVocabularyListener, ...@@ -739,8 +745,49 @@ public class PictogramActivity extends Activity implements iVocabularyListener,
count_deletelong++; count_deletelong++;
if (count_deletelong >= 3) { if (count_deletelong >= 3) {
//TODO: COMPROBAR SI LOS USUARIOS QUE BUSCO EXISTEN: SI NO PONER LOS DATOS POR DEFECTO*******************************************************************/
//Cojo los id del ultimo estudiante y el ultimo supervisor
int lastIdStu = PCBcontext.getDevice().getLastStuId();
User actual = PCBcontext.getPcbdb().getCurrentUser();
User usuario_anterior;
String lastUserName = null;
String lastPassword= null;
if (actual.is_supervisor()) //Si el que habia es supervisor busco el ultimo niño
try {
usuario_anterior = PCBcontext.getDevice().findUser(lastIdStu,User.NO_SUPERVISOR);
if(usuario_anterior!=null){
lastUserName = usuario_anterior.get_nickname_stu();
lastPassword = usuario_anterior.get_pwd_stu();
}
} catch (JSONException e) {
e.printStackTrace();
}
else {
int lastIdSup = PCBcontext.getDevice().getLastSupId();
try {
usuario_anterior = PCBcontext.getDevice().findUser(lastIdStu,lastIdSup);
if(usuario_anterior!=null){
lastUserName = usuario_anterior.get_email_sup();
lastPassword = usuario_anterior.get_pwd_sup();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Intent serialActivity = new Intent(getBaseContext(), SerialActivity.class);
if (lastUserName!=null) {
Log.i(this.getClass().getCanonicalName(), "Switch user to "+ lastUserName);
serialActivity.putExtra("switch_usr", lastUserName);
serialActivity.putExtra("switch_pwd", lastPassword);
}
PictogramActivity.this.finish(); PictogramActivity.this.finish();
PCBcontext.getNetService().restart_app(); PCBcontext.getNetService().restart_app(serialActivity);
} }
return false; return false;
} }
......
...@@ -4,6 +4,7 @@ import android.app.Activity; ...@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.Window; import android.view.Window;
...@@ -25,12 +26,24 @@ public class SerialActivity extends Activity { ...@@ -25,12 +26,24 @@ public class SerialActivity extends Activity {
// String constant for logs // String constant for logs
private final String LOG_TAG = this.getClass().getSimpleName(); // Or .getCanonicalName() private final String LOG_TAG = this.getClass().getSimpleName(); // Or .getCanonicalName()
public static void resetDefaultUser() {
SharedPreferences settings = PCBcontext.getContext().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("username", "");
editor.putString("password", "");
/**
* Return the default user+pwd when login.The policy is
* 1. switch user
* 2. last user
* @return user+pwd to be used
*/
private String[] loginUserPolicy() {
Intent intent=getIntent();
String username = intent.getStringExtra("switch_usr");
String password = intent.getStringExtra("switch_pwd");
if (username==null) {
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
username = settings.getString("username", "");
password = settings.getString("password", "");
}
return new String[]{username,password};
} }
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
...@@ -38,21 +51,25 @@ public class SerialActivity extends Activity { ...@@ -38,21 +51,25 @@ public class SerialActivity extends Activity {
requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_serial); setContentView(R.layout.activity_serial);
Intent intent=getIntent();
final EditText mSerialViewMail = (EditText) findViewById(R.id.serialmail); final EditText mSerialViewMail = (EditText) findViewById(R.id.serialmail);
final EditText mSerialViewPass = (EditText) findViewById(R.id.serialpass); final EditText mSerialViewPass = (EditText) findViewById(R.id.serialpass);
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); String default_user[]=loginUserPolicy();
String username = settings.getString("username", ""); String username=default_user[0];
String password = intent.getBooleanExtra("resetPrevUser", true) ? "" : settings.getString("password", ""); String password=default_user[1];
// Escribo el último valor indicado de username
mSerialViewMail.setText(username);
mSerialViewPass.setText(password);
// Escribo el último valor indicado de username // Escribo el último valor indicado de username
mSerialViewMail.setText(username); mSerialViewMail.setText(username);
if (!username.equals("") && !password.equals("")) new UserLogin().login(username, password,SerialActivity.this, PictogramActivity.class, LoginActivity.class);; if (!username.equals("") && !password.equals("") && !getIntent().getBooleanExtra("resetPrevUser", true)) new UserLogin().login(username, password,SerialActivity.this, PictogramActivity.class, LoginActivity.class);
Button mEntrarButton = (Button) findViewById(R.id.entrar_button); Button mEntrarButton = (Button) findViewById(R.id.entrar_button);
mEntrarButton.setOnClickListener(new OnClickListener() { mEntrarButton.setOnClickListener(new OnClickListener() {
...@@ -66,6 +83,7 @@ public class SerialActivity extends Activity { ...@@ -66,6 +83,7 @@ public class SerialActivity extends Activity {
editor.putString("username", username); editor.putString("username", username);
editor.putString("password", password); editor.putString("password", password);
editor.commit(); editor.commit();
if (!username.equals("") && !password.equals(""))
new UserLogin().login(username, password,SerialActivity.this, PictogramActivity.class, LoginActivity.class); new UserLogin().login(username, password,SerialActivity.this, PictogramActivity.class, LoginActivity.class);
} }
}); });
......
...@@ -4,6 +4,7 @@ import android.app.NotificationManager; ...@@ -4,6 +4,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.TaskStackBuilder; import android.app.TaskStackBuilder;
import android.content.Intent; import android.content.Intent;
import android.support.v4.app.Fragment;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
...@@ -68,15 +69,13 @@ public class NetServiceTablet implements iNetServiceDevice { ...@@ -68,15 +69,13 @@ public class NetServiceTablet implements iNetServiceDevice {
* the app. The most frequent reason is a password change while the user have been logged * the app. The most frequent reason is a password change while the user have been logged
* offline * offline
*/ */
public void restart_app() { public void restart_app(Intent serialActivity) {
StackTraceElement trace[] = Thread.currentThread().getStackTrace(); StackTraceElement trace[] = Thread.currentThread().getStackTrace();
Log.i(this.getClass().getCanonicalName(),"App restarted from "+trace[0]+"->"+trace[1]+"..."+ Log.i(this.getClass().getCanonicalName(),"App restarting");
trace[trace.length-2]+"->"+trace[trace.length-1]); if (serialActivity==null) serialActivity = new Intent(PCBcontext.getContext(), SerialActivity.class);
SerialActivity.resetDefaultUser();
Intent serialActivity = new Intent(PCBcontext.getContext(), SerialActivity.class);
serialActivity.putExtra("resetPrevUser", true); serialActivity.putExtra("resetPrevUser", true);
PCBcontext.getContext().startActivity(serialActivity); PCBcontext.getContext().startActivity(serialActivity);
} }
public void restart_app() {restart_app(null);}
} }
...@@ -47,8 +47,8 @@ public class MainActivity extends Activity { ...@@ -47,8 +47,8 @@ public class MainActivity extends Activity {
} }
private void login() { private void login() {
final String username="faf0001"; final String username="faf0002";
final String password="faf0001"; final String password="faf0002";
new UserLogin().login(username,password,this, MainActivity.class,null); new UserLogin().login(username,password,this, MainActivity.class,null);
} }
} }
...@@ -43,7 +43,11 @@ public class NetServiceWatch implements iNetServiceDevice { ...@@ -43,7 +43,11 @@ public class NetServiceWatch implements iNetServiceDevice {
* offline * offline
*/ */
public void restart_app() { public void restart_app() {
Intent intent= new Intent(PCBcontext.getContext(), Activity); restart_app(new Intent(PCBcontext.getContext(), Activity));
}
@Override
public void restart_app(Intent intent) {
intent.putExtra("resetPrevUser", true); intent.putExtra("resetPrevUser", true);
PCBcontext.getContext().startActivity(intent); PCBcontext.getContext().startActivity(intent);
} }
......
...@@ -138,6 +138,7 @@ COMMENT="Methods predefined in the platform or stored by users for cloning"; ...@@ -138,6 +138,7 @@ COMMENT="Methods predefined in the platform or stored by users for cloning";
CREATE TABLE IF NOT EXISTS `office` ( CREATE TABLE IF NOT EXISTS `office` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, `name` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
`logo_url` varchar(240) COLLATE utf8_unicode_ci NOT NULL,
`address` varchar(180) COLLATE utf8_unicode_ci NOT NULL, `address` varchar(180) COLLATE utf8_unicode_ci NOT NULL,
`country` varchar(2) COLLATE utf8_unicode_ci NOT NULL, `country` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
`lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL, `lang` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
...@@ -308,8 +309,7 @@ CREATE TABLE IF NOT EXISTS `stu_picto` ( ...@@ -308,8 +309,7 @@ CREATE TABLE IF NOT EXISTS `stu_picto` (
`attributes` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'JSON object describing the properties of the picto', `attributes` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'JSON object describing the properties of the picto',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `fk_picto` (`id_pic`), KEY `fk_picto` (`id_pic`),
KEY `id_stu` (`id_stu`), KEY `id_stu` (`id_stu`)
UNIQUE `uq_stupicto` (`id_stu`,`id_pic`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1
COMMENT="This table relates a student with the pictos in her vocabulary"; COMMENT="This table relates a student with the pictos in her vocabulary";
......
...@@ -53,6 +53,16 @@ thisTrigger: BEGIN ...@@ -53,6 +53,16 @@ thisTrigger: BEGIN
current_students=current_students+1 current_students=current_students+1
WHERE WHERE
office.id=new.id_off; office.id=new.id_off;
INSERT INTO stu_picto(id_stu,id_pic,attributes)
SELECT new.id,id_pic, concat('{"id_cat":', if (id_cat_pic is null, 'null',id_cat_pic),
',"coord_x":',coord_x,
',"coord_y":',coord_y,
',"status":"invisible"',
',"highlight":false',
',"color":', if (color is null, 'null',concat('"',color,'"')),
'}') as attributes
FROM picto_core P;
END;; END;;
-- Integrity rule 3: office.current_enrolments and supervisor assigments updating. -- Integrity rule 3: office.current_enrolments and supervisor assigments updating.
......
...@@ -89,7 +89,9 @@ thisTrigger: BEGIN ...@@ -89,7 +89,9 @@ thisTrigger: BEGIN
NOW(3) NOW(3)
) )
ON DUPLICATE KEY UPDATE id_stu=idstu, id_sup=idsup, id_ws=NEW.id_ws, id_opentry=NEW.id; ON DUPLICATE KEY UPDATE id_stu=idstu, id_sup=idsup, id_ws=NEW.id_ws, id_opentry=NEW.id;
END;; END;;
-- --
-- It deletes current try for a given session -- It deletes current try for a given session
DROP PROCEDURE IF EXISTS deleteOpenTry; DROP PROCEDURE IF EXISTS deleteOpenTry;
...@@ -117,6 +119,7 @@ AFTER INSERT ON working_session ...@@ -117,6 +119,7 @@ AFTER INSERT ON working_session
FOR EACH ROW FOR EACH ROW
thisTrigger: BEGIN thisTrigger: BEGIN
DECLARE idstu INT; DECLARE idstu INT;
DECLARE ins_begin DATE;
IF ((@TRIGGER_CHECKS = FALSE) IF ((@TRIGGER_CHECKS = FALSE)
OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE)) OR (@TRIGGER_AFTER_INSERT_CHECKS = FALSE))
...@@ -125,9 +128,25 @@ thisTrigger: BEGIN ...@@ -125,9 +128,25 @@ thisTrigger: BEGIN
LEAVE thisTrigger; LEAVE thisTrigger;
END IF; END IF;
SELECT begin INTO ins_begin
FROM instruction
WHERE id = NEW.id_ins;
IF (ins_begin IS NULL) THEN
UPDATE instruction UPDATE instruction
SET status='started' SET
WHERE id=new.id_ins; begin = NOW(3),
end = NOW(3)
WHERE
id = NEW.id_ins;
END IF;
UPDATE instruction
SET
status='started',
end = NOW(3)
WHERE
id = NEW.id_ins;
INSERT INTO try(`id_ws`) INSERT INTO try(`id_ws`)
VALUES (new.id); VALUES (new.id);
...@@ -150,6 +169,16 @@ thisTrigger: BEGIN ...@@ -150,6 +169,16 @@ thisTrigger: BEGIN
LEAVE thisTrigger; LEAVE thisTrigger;
END IF; END IF;
-- end date for related instruction is updated
IF (OLD.end < NEW.end) THEN
UPDATE instruction
SET
end = NEW.end
WHERE
id = NEW.id_ins;
END IF;
-- remove open try
IF ((old.end IS NULL) and (new.end IS NOT NULL)) THEN IF ((old.end IS NULL) and (new.end IS NOT NULL)) THEN
CALL deleteOpenTry(new.id); CALL deleteOpenTry(new.id);
END IF; END IF;
...@@ -335,6 +364,8 @@ thisTrigger: BEGIN ...@@ -335,6 +364,8 @@ thisTrigger: BEGIN
WHERE id = NEW.id_ws; WHERE id = NEW.id_ws;
END IF; END IF;
END;; END;;
......
...@@ -50,6 +50,25 @@ module.exports = { ...@@ -50,6 +50,25 @@ module.exports = {
}, },
/** /**
* Get basic informacion (logo_url and name) about an office identified by a code
*/
getBasic: function (req, res) {
// We simply remove first 3 characters
var id = req.params.code.substr(3, req.params.code.length-1);
Office.findOne({ id: id }).populate('admin').then(function (office) {
if (office) {
res.ok({logo_url: office.logo_url, name: office.name});
} else {
res.notFound();
}
})
.catch(function () {
res.badRequest();
});
},
/**
* Return all offices * Return all offices
* @param {request} req {} * @param {request} req {}
* @param {response} res * @param {response} res
......
...@@ -158,7 +158,7 @@ module.exports = { ...@@ -158,7 +158,7 @@ module.exports = {
Student.create(params) Student.create(params)
.then(function(created) { .then(function(created) {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created)); sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
return res.ok({ student: created }); return res.ok(created);
}) })
.error(function(err) { .error(function(err) {
if (err.message.search("Maximum number of enrolments reached") > 0) { if (err.message.search("Maximum number of enrolments reached") > 0) {
...@@ -169,8 +169,8 @@ module.exports = { ...@@ -169,8 +169,8 @@ module.exports = {
return res.serverError(err.message); return res.serverError(err.message);
} }
else { else {
sails.log.debug(err); sails.log.debug(err.message);
return res.serverError(err); return res.serverError(err.message);
} }
}); });
}, },
......
...@@ -31,6 +31,11 @@ module.exports = { ...@@ -31,6 +31,11 @@ module.exports = {
type: "string", type: "string",
size: 80 size: 80
}, },
logo_url: {
required: true,
type: "string",
size: 240
},
contactPerson: { contactPerson: {
columnName: "contact_person", columnName: "contact_person",
required: true, required: true,
......
...@@ -238,53 +238,6 @@ module.exports = { ...@@ -238,53 +238,6 @@ module.exports = {
}, },
/** /**
* Sets initial vocabulary of students to Picto Core
* @param {Object} attrs All student properties stored
* @param {Function} next Function to be executed when the check process
* has been completed (an error object will be passed
* to the function if necesary)
*/
afterCreate: function (attrs, next) {
// Assign the initial collection of pictos to the student
PictoCore.find()
.then(function(pictoCore) {
var i;
// Every picto from 'picto_core_cat' is going to be created
// in 'stu_picto'
for (var i = 0; i < pictoCore.length; i++) {
StuPicto.create({
student: created.id,
picto: pictoCore[i].picto,
attributes: {
id_cat: pictoCore[i].category,
coord_x: pictoCore[i].coord_x,
coord_y: pictoCore[i].coord_y,
status: 'invisible', // Default, the pictos don't appear to the user
color: pictoCore[i].color
}
})
.then(function (stuPictoError, added) {
if (added) {
sails.log.debug(
'Picto ' + added.picto +
' added to student ' + created.id +
' with attributes: ' + JSON.stringify(added.attributes));
}
})
.error(function(err) {
sails.log.debug('StuPicto.create: ' + err);
throw err;
});
}
next();
})
.error(function(err) {
next(err);
});
},
/**
* Checks the given properties before updating a new Student * Checks the given properties before updating a new Student
* @param {Object} attrs All student properties to be stored * @param {Object} attrs All student properties to be stored
* @param {Function} next Function to be executed when the check process * @param {Function} next Function to be executed when the check process
...@@ -486,8 +439,31 @@ module.exports = { ...@@ -486,8 +439,31 @@ module.exports = {
if (!populated_ws || !populated_ws.tries || populated_ws.tries.length == 0) if (!populated_ws || !populated_ws.tries || populated_ws.tries.length == 0)
return next_ws(); return next_ws();
// Recorremos tries
var l_tries = [];
async.each(populated_ws.tries,
function(t, next_t) {
Try.findOne(t.id)
.populate('actions')
.then((populated_try) => {
if (!populated_try || !populated_try.actions || populated_try.actions.length == 0)
return next_t();
l_tries.push(populated_try);
next_t();
})
.catch((err) => {throw err});
},
function(err) { // Ya tenemos todos los tries poblados con acciones
if (err) throw err;
if (l_tries.length > 0) {
populated_ws.tries = l_tries;
l_ws.push(populated_ws); l_ws.push(populated_ws);
}
return next_ws(); return next_ws();
});
}) })
.catch((err) => {throw err}); .catch((err) => {throw err});
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
"ngtoast": "~1.5.4", "ngtoast": "~1.5.4",
"angular-animate": "~1.4.1", "angular-animate": "~1.4.1",
"angular-sanitize": "~1.4.1", "angular-sanitize": "~1.4.1",
"angular-chart.js": "~0.7.2", "angular-chart.js": "latest",
"ng-lodash": "~0.3.0" "ng-lodash": "~0.3.0"
}, },
"resolutions": { "resolutions": {
......
No preview for this file type
This diff could not be displayed because it is too large.
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"alert": "Alert", "alert": "Alert",
"all": "All", "all": "All",
"animation": "Animation", "animation": "Animation",
"annual": "Annual",
"April": "April", "April": "April",
"attributes_not_updated": "Changes not saved", "attributes_not_updated": "Changes not saved",
"attributes_updated": "Changes saved", "attributes_updated": "Changes saved",
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
"child": "Child", "child": "Child",
"click": "Click", "click": "Click",
"click_login": "Click to login", "click_login": "Click to login",
"click_to_edit": "clic to edit",
"close": "Close", "close": "Close",
"close_session": "Close session", "close_session": "Close session",
"collections": "Collections", "collections": "Collections",
...@@ -101,6 +103,7 @@ ...@@ -101,6 +103,7 @@
"general_labels": "General labels", "general_labels": "General labels",
"generate": "Generate", "generate": "Generate",
"generate_serial": "Generate serial number", "generate_serial": "Generate serial number",
"global":"Global",
"hide": "Hide", "hide": "Hide",
"highlight": "highlight", "highlight": "highlight",
"highlighted": "Highlighted", "highlighted": "Highlighted",
...@@ -141,6 +144,7 @@ ...@@ -141,6 +144,7 @@
"methods": "Methods", "methods": "Methods",
"minutes": "minutes", "minutes": "minutes",
"month_totals": "Month totals", "month_totals": "Month totals",
"monthly":"Monthly",
"name": "Name", "name": "Name",
"new_instruction": "New instruction", "new_instruction": "New instruction",
"new_method": "New method", "new_method": "New method",
...@@ -268,10 +272,12 @@ ...@@ -268,10 +272,12 @@
"tag_deleted": "Tag deleted", "tag_deleted": "Tag deleted",
"tape_background": "Tape background", "tape_background": "Tape background",
"template_deleted": "Template deleted", "template_deleted": "Template deleted",
"time_instruction_method": "Time instructions of method",
"time_hours": "Time: {{hours}} hours", "time_hours": "Time: {{hours}} hours",
"time_instruction_method": "Time instructions of method",
"time_sessions_total": "Total sessions time",
"time_sessions_per_days": "Time of sessions per days in", "time_sessions_per_days": "Time of sessions per days in",
"time_sessions_per_month": "Time of sessions per months in", "time_sessions_per_month": "Time of sessions per months in",
"time_tries_total": "Total tries time",
"time_tries_per_days": "Time of tries per days in", "time_tries_per_days": "Time of tries per days in",
"time_tries_per_month": "Time of tries per months in", "time_tries_per_month": "Time of tries per months in",
"title": "Title", "title": "Title",
...@@ -280,6 +286,7 @@ ...@@ -280,6 +286,7 @@
"tpl_day": "{{ day | date:'yyyy-MM-dd' }}", "tpl_day": "{{ day | date:'yyyy-MM-dd' }}",
"tpl_hours_frame": "from {{ begin | date:'HH:mm:ss' }} to {{ end | date:'HH:mm:ss' }}", "tpl_hours_frame": "from {{ begin | date:'HH:mm:ss' }} to {{ end | date:'HH:mm:ss' }}",
"tries": "Tries", "tries": "Tries",
"tries_done": "Tries done",
"tries_length": "Tries length", "tries_length": "Tries length",
"tries_mean_length": "Tries mean length", "tries_mean_length": "Tries mean length",
"tries_per_days": "Tries per days in", "tries_per_days": "Tries per days in",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"alert": "Alerta", "alert": "Alerta",
"all": "Todos", "all": "Todos",
"animation": "Animación", "animation": "Animación",
"annual": "Anual",
"April": "Abril", "April": "Abril",
"attributes_not_updated": "Cambios no guardados", "attributes_not_updated": "Cambios no guardados",
"attributes_updated": "Cambios guardados", "attributes_updated": "Cambios guardados",
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
"child": "Niño", "child": "Niño",
"click": "Clic", "click": "Clic",
"click_login": "Clic para iniciar sesión", "click_login": "Clic para iniciar sesión",
"click_to_edit": "clic para editar",
"close": "Cerrar", "close": "Cerrar",
"close_session": "Cerrar sesion", "close_session": "Cerrar sesion",
"collections": "Colecciones", "collections": "Colecciones",
...@@ -101,6 +103,7 @@ ...@@ -101,6 +103,7 @@
"general_labels": "Generales", "general_labels": "Generales",
"generate": "Generar", "generate": "Generar",
"generate_serial": "Generar número de serie", "generate_serial": "Generar número de serie",
"global":"Global",
"hide": "Ocultar", "hide": "Ocultar",
"highlight": "Resaltar", "highlight": "Resaltar",
"highlighted": "Resaltado", "highlighted": "Resaltado",
...@@ -141,6 +144,7 @@ ...@@ -141,6 +144,7 @@
"methods": "Métodos", "methods": "Métodos",
"minutes": "minutos", "minutes": "minutos",
"month_totals": "Totales mes", "month_totals": "Totales mes",
"monthly":"Mensual",
"name": "Nombre", "name": "Nombre",
"new_instruction": "Nueva instrucción", "new_instruction": "Nueva instrucción",
"new_method": "Nuevo método", "new_method": "Nuevo método",
...@@ -271,8 +275,10 @@ ...@@ -271,8 +275,10 @@
"template_deleted": "Plantilla eliminada", "template_deleted": "Plantilla eliminada",
"time_hours": "Tiempo: {{hours}} horas", "time_hours": "Tiempo: {{hours}} horas",
"time_instruction_method": "Tiempo instrucciones del método", "time_instruction_method": "Tiempo instrucciones del método",
"time_sessions_total": "Tiempo total de sesiones",
"time_sessions_per_days": "Tiempo de sesiones por días en", "time_sessions_per_days": "Tiempo de sesiones por días en",
"time_sessions_per_month": "Tiempo de sesiones por meses en", "time_sessions_per_month": "Tiempo de sesiones por meses en",
"time_tries_total": "Tiempo total de ensayos",
"time_tries_per_days": "Tiempo de ensayos por días en", "time_tries_per_days": "Tiempo de ensayos por días en",
"time_tries_per_month": "Tiempo de ensayos por meses en", "time_tries_per_month": "Tiempo de ensayos por meses en",
"title": "Título", "title": "Título",
...@@ -281,6 +287,7 @@ ...@@ -281,6 +287,7 @@
"tpl_day": "{{ day | date:'dd-MM-yyyy' }}", "tpl_day": "{{ day | date:'dd-MM-yyyy' }}",
"tpl_hours_frame": "de {{ begin | date:'HH:mm:ss' }} a {{ end | date:'HH:mm:ss' }}", "tpl_hours_frame": "de {{ begin | date:'HH:mm:ss' }} a {{ end | date:'HH:mm:ss' }}",
"tries": "Ensayos", "tries": "Ensayos",
"tries_done": "Ensayos realizados",
"tries_length": "Duración ensayos", "tries_length": "Duración ensayos",
"tries_mean_length": "Duración media ensayos", "tries_mean_length": "Duración media ensayos",
"tries_per_days": "Número de ensayos por días en", "tries_per_days": "Número de ensayos por días en",
......
...@@ -56,6 +56,11 @@ dashboardApp.config(function ($stateProvider, $urlRouterProvider) { ...@@ -56,6 +56,11 @@ dashboardApp.config(function ($stateProvider, $urlRouterProvider) {
templateUrl: 'modules/login/views/login.html', templateUrl: 'modules/login/views/login.html',
controller: 'LoginCtrl' controller: 'LoginCtrl'
}) })
.state('login_office', {
url: '/login/:office',
templateUrl: 'modules/login/views/login.html',
controller: 'LoginCtrl'
})
.state('login_validate', { .state('login_validate', {
url: '/login/:code/:email', url: '/login/:code/:email',
templateUrl: 'modules/login/views/login.html', templateUrl: 'modules/login/views/login.html',
......
...@@ -16,12 +16,18 @@ function LoginCtrl( ...@@ -16,12 +16,18 @@ function LoginCtrl(
config, config,
$stateParams, $stateParams,
ngToast) { ngToast) {
$scope.credentials = { $scope.credentials = {
email: '', email: '',
password: '', password: '',
lang: 'es-es' lang: 'es-es'
}; };
$scope.office = {
logo_url : 'img/logo_pictogram.png',
name : 'Pictogram'
};
// Validation of account // Validation of account
// if the code has been sent in the url "...app/login/code/email" // if the code has been sent in the url "...app/login/code/email"
if ($stateParams.code && $stateParams.email) { if ($stateParams.code && $stateParams.email) {
...@@ -39,7 +45,17 @@ function LoginCtrl( ...@@ -39,7 +45,17 @@ function LoginCtrl(
}); });
} }
// Corporate login, office code has been passed
if ($stateParams.office) {
$http
.get(config.backend + '/office/' + $stateParams.office)
.success(function (data) {
$scope.office = data;
});
}
$scope.login = function () { $scope.login = function () {
$scope.submitted = true;
$http $http
.post(config.backend + '/sup/login', $scope.credentials) .post(config.backend + '/sup/login', $scope.credentials)
.success(function (data) { .success(function (data) {
...@@ -69,6 +85,7 @@ function LoginCtrl( ...@@ -69,6 +85,7 @@ function LoginCtrl(
$location.path('/students'); $location.path('/students');
}) })
.error(function (err) { .error(function (err) {
$scope.submitted = false;
delete $window.sessionStorage.token; delete $window.sessionStorage.token;
if (err.search("without students") > 0) { if (err.search("without students") > 0) {
$translate('no_students_for_user').then(function (translation) { $translate('no_students_for_user').then(function (translation) {
......
...@@ -5,10 +5,14 @@ ...@@ -5,10 +5,14 @@
<div class="col-md-4"> <div class="col-md-4">
<div id="login"> <div id="login">
<!-- Logo Pictogram --> <!-- Logo Pictogram
<p class="text-center"> <p>
<img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" /> <img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" />
</p> </p>
-->
<p class="text-center">
<img src="{{office.logo_url}}" alt="{{office.name}}" title="{{office.name}}">
</p>
<!-- Formulario --> <!-- Formulario -->
<!-- LoginCtrl controls here, see app.js --> <!-- LoginCtrl controls here, see app.js -->
<form name="loginForm" ng-submit="login()" novalidate> <form name="loginForm" ng-submit="login()" novalidate>
...@@ -27,7 +31,9 @@ ...@@ -27,7 +31,9 @@
<p class="text-center"> <p class="text-center">
<button type="submit" class="btn btn-primary" translate>login</button> <button type="submit" class="btn btn-primary" translate>login</button>
</p> </p>
<p class="text-center">
<i ng-class="{'fa fa-spinner fa-spin fa-2x fa-fw margin-bottom': true, 'spin_disabled': !submitted}"></i>
</p>
<p class="text-center"> <p class="text-center">
<a href="/app/#/signin" translate>create_an_account</a> <a href="/app/#/signin" translate>create_an_account</a>
</p> </p>
...@@ -36,11 +42,7 @@ ...@@ -36,11 +42,7 @@
<!-- Fin login --> <!-- Fin login -->
</div> </div>
<div class="col-md-4">&nbsp;</div> <div class="col-md-4">&nbsp;</div>
</div> </div>
<!-- Fin de row --> <!-- Fin de row -->
<footer-translate></footer-translate> <footer-translate></footer-translate>
...@@ -77,7 +77,7 @@ dashboardControllers.controller('StudentInstructionsCtrl', function StudentInstr ...@@ -77,7 +77,7 @@ dashboardControllers.controller('StudentInstructionsCtrl', function StudentInstr
$http $http
.post(config.backend+'/method/new', { .post(config.backend+'/method/new', {
'id_stu': $scope.studentData.id, 'id_stu': $scope.studentData.id,
'name': "Nuevo método (cambiar nombre)" 'name': $translate.instant("new_method") + "(" + $translate.instant("click_to_edit") + ")"
}) })
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
// Add empty array of instructions // Add empty array of instructions
...@@ -217,8 +217,13 @@ dashboardControllers.controller('StudentInstructionsCtrl', function StudentInstr ...@@ -217,8 +217,13 @@ dashboardControllers.controller('StudentInstructionsCtrl', function StudentInstr
// Add instruction // Add instruction
$scope.add_instruction = function(method){ $scope.add_instruction = function(method){
var data = {
method: method.id,
name: $translate.instant("new_instruction") + " (" + $translate.instant("click_to_edit") + ")",
objective: $translate.instant("new_objective") + " (" + $translate.instant("click_to_edit") + ")"
};
$http $http
.post(config.backend+'/instruction', { method: method.id } ) .post(config.backend+'/instruction', data )
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
console.log('Added instruction:' + JSON.stringify(data)); console.log('Added instruction:' + JSON.stringify(data));
// Add in view // Add in view
......
<div> <div>
<div class="modal-header"> <div class="modal-header">
<div class="btn-group"> <div class="btn-group">
<button class="btn btn-default" ng-model="source" uib-btn-radio="'symbolstx'" ng-click="open_category_from_bc('0')">Symbolstx</button> <button class="btn btn-default" ng-model="source" uib-btn-radio="'symbolstx'" ng-click="open_category_from_bc('0')">SymbolStix</button>
<button class="btn btn-default" ng-model="source" uib-btn-radio="'ownpictos'" ng-click="load_own_pictos()" translate>own_pictos</button> <button class="btn btn-default" ng-model="source" uib-btn-radio="'ownpictos'" ng-click="load_own_pictos()" translate>own_pictos</button>
</div> </div>
</div> </div>
......
...@@ -184,6 +184,7 @@ ...@@ -184,6 +184,7 @@
<label class="form-control" for="studentSetupUseCategories">{{ 'use_categories' | translate }}</label> <label class="form-control" for="studentSetupUseCategories">{{ 'use_categories' | translate }}</label>
</div> </div>
</fieldset> </fieldset>
<!-- DISABLED, NOT IMPLEMENTED YET
<fieldset> <fieldset>
<legend>{{ 'feedback_picto' | translate }}</legend> <legend>{{ 'feedback_picto' | translate }}</legend>
<div class="input-group"> <div class="input-group">
...@@ -389,6 +390,7 @@ ...@@ -389,6 +390,7 @@
</div> </div>
</fieldset> </fieldset>
</fieldset> </fieldset>
-->
</form> </form>
</div> </div>
</div> </div>
......
...@@ -137,6 +137,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl( ...@@ -137,6 +137,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
errorMessage = 'invalid_fields'; errorMessage = 'invalid_fields';
ngToast.danger({ content: $translate.instant(errorMessage) }); ngToast.danger({ content: $translate.instant(errorMessage) });
}); });
}; };
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
href="/app/#/students"> href="/app/#/students">
<img <img
class="topbar__logo__image" class="topbar__logo__image"
src="img/logo_pictogram.png" src="{{user.office.logo_url}}"
alt="Pictogram" alt="{{user.office.name}}"
title="Pictogram" /> title="{{user.office.name}}" />
</a> </a>
</div> </div>
<div class="topbar__supervisor nav navbar-nav navbar-right"> <div class="topbar__supervisor nav navbar-nav navbar-right">
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<div class="panel panel-default"> <div class="panel panel-default">
<!-- Default panel contents --> <!-- Default panel contents -->
<div class="panel-heading"><h3 class="panel-title" translate>students</h3> <div class="panel-heading"><h3 class="panel-title" translate>students</h3>
<span ng-if="user.isAdmin">({{user.office.currentStudents}}/{{user.office.maxStudents}} - <span translate="licenses_left" translate-values="{number: num_licenses_left}"></span>)</span> <!-- span ng-if="user.isAdmin">({{user.office.currentStudents}}/{{user.office.maxStudents}} - <span translate="licenses_left" translate-values="{number: num_licenses_left}"></span>)</span -->
</divuser.office.currentStudents}}/ivuser.office.maxStudents}} <div class="panel-body"> <div class="panel-body">
<!-- Add Student Form --> <!-- Add Student Form -->
<div ng-include="'modules/supervisor/views/students_add.html'" ng-init="hidestudentadd = true" ng-hide="hidestudentadd"></div> <div ng-include="'modules/supervisor/views/students_add.html'" ng-init="hidestudentadd = true" ng-hide="hidestudentadd"></div>
......
...@@ -4,4 +4,9 @@ ...@@ -4,4 +4,9 @@
<button type="button" class="btn btn-link">|</button> <button type="button" class="btn btn-link">|</button>
<button type="button" class="btn btn-link" ng-click="changeLanguage('en-gb')">English</button> <button type="button" class="btn btn-link" ng-click="changeLanguage('en-gb')">English</button>
</div> </div>
<div>
<p class="text-center" style="margin-top:10px">
<small>Powered by <a href="http://www.yottacode.com"><img src="img/logo_pictogram.png" width="40px" alt="Pictogram" title="Pictogram" /></a></small>
</p>
</div>
</div> </div>
...@@ -47,6 +47,12 @@ ...@@ -47,6 +47,12 @@
padding: 8px; padding: 8px;
} }
/* For hidding spinner preserving space */
.spin_disabled {
visibility: hidden;
cursor: default;
}
/* For span that are links */ /* For span that are links */
.pointer{ cursor: pointer; } .pointer{ cursor: pointer; }
...@@ -101,7 +107,7 @@ html { ...@@ -101,7 +107,7 @@ html {
/* Pie de página con idiomas: Siempre en la parte inferior de la página; */ /* Pie de página con idiomas: Siempre en la parte inferior de la página; */
div.languages { div.languages {
position: absolute; position: absolute;
bottom: -50px; /*bottom: -10px;*/
width: 100%; width: 100%;
/* Set the fixed height of the footer here */ /* Set the fixed height of the footer here */
height: 50px; height: 50px;
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
@import (less) '../app/bower_components/bootstrap/dist/css/bootstrap-theme.css'; @import (less) '../app/bower_components/bootstrap/dist/css/bootstrap-theme.css';
@import (less) '../app/bower_components/ngtoast/dist/ngToast.css'; @import (less) '../app/bower_components/ngtoast/dist/ngToast.css';
@import (less) '../app/bower_components/ngtoast/dist/ngToast-animations.css'; @import (less) '../app/bower_components/ngtoast/dist/ngToast-animations.css';
@import (less) '../app/bower_components/angular-chart.js/dist/angular-chart.css';
@import (less) 'cropper.css'; @import (less) 'cropper.css';
@import (less) 'main.css'; @import (less) 'main.css';
@import (less) 'font-awesome.min.css';
@import 'forms.less'; @import 'forms.less';
@import 'picto-grid.less'; @import 'picto-grid.less';
......
...@@ -36,12 +36,16 @@ module.exports = { ...@@ -36,12 +36,16 @@ module.exports = {
* responses over https:// and/or use websockets over the wss:// protocol * responses over https:// and/or use websockets over the wss:// protocol
* (recommended for HTTP, strongly encouraged for WebSockets) * (recommended for HTTP, strongly encouraged for WebSockets)
*/ */
ssl: { /* ssl: {
// ca: fs.readFileSync(path.join(__dirname, 'ssl', 'bundle.crt')), // ca: fs.readFileSync(path.join(__dirname, 'ssl', 'bundle.crt')),
key: fs.readFileSync(path.join(__dirname, 'ssl', 'key.key')), key: fs.readFileSync(path.join(__dirname, 'ssl', 'yottacode.com.key')),
cert: fs.readFileSync(path.join(__dirname, 'ssl', 'cert.crt')), cert: fs.readFileSync(path.join(__dirname, 'ssl', 'yottacode.com.crt')),
}, },
*/
ssl: {
key: fs.readFileSync('/etc/letsencrypt/live/dev.yottacode.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/dev.yottacode.com/cert.pem')
}
/** /**
* The `port` setting determines which TCP port your app will be * The `port` setting determines which TCP port your app will be
* deployed on. * deployed on.
...@@ -52,7 +56,7 @@ module.exports = { ...@@ -52,7 +56,7 @@ module.exports = {
* In env/production.js, you'll probably want to change this setting * In env/production.js, you'll probably want to change this setting
* to 80 (http://) or 443 (https://) if you have an SSL certificate * to 80 (http://) or 443 (https://) if you have an SSL certificate
*/ */
port: process.env.PORT || 1337, port: process.env.PORT || 443,
/* /*
* The runtime "environment" of your Sails app is either typically * The runtime "environment" of your Sails app is either typically
......
...@@ -62,6 +62,7 @@ module.exports.policies = { ...@@ -62,6 +62,7 @@ module.exports.policies = {
OfficeController: { OfficeController: {
getAll: ['tokenAuth', 'isAdmin'], getAll: ['tokenAuth', 'isAdmin'],
get: ['tokenAuth'], get: ['tokenAuth'],
getBasic: true,
supervisors: ['tokenAuth', 'isAdmin'] supervisors: ['tokenAuth', 'isAdmin']
}, },
......
...@@ -52,6 +52,7 @@ module.exports.routes = { ...@@ -52,6 +52,7 @@ module.exports.routes = {
'DELETE /method/template/:id': 'MetaMethodController.destroy', 'DELETE /method/template/:id': 'MetaMethodController.destroy',
'GET /office/get_all': 'OfficeController.getAll', 'GET /office/get_all': 'OfficeController.getAll',
'GET /office/:code': 'OfficeController.getBasic',
'GET /office/get/:id': 'OfficeController.get', 'GET /office/get/:id': 'OfficeController.get',
'GET /office/get/:id/supervisors': 'OfficeController.supervisors', 'GET /office/get/:id/supervisors': 'OfficeController.supervisors',
......
-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAPkWZj6TTJQon1rupP1SUY8dQiSv3+1xByQAGYaf
J9vZWfe6ZAy0ndFH26m0lc2S76BkQRfhWBTvWcsFhACWefSlGxpIiwxWdQOcF6cf
WyFi9VBPUXvTPyd64hCd+9+XML/0hzU4BpzJsEbPyhOv7VZA2VCZ+GAP86b/MGCS
s2QgWi7ZW0bTX0tO1WDC8JdHeaUXspwfJaqsw25SiDsNfWQmAZOa5F9I0vl4GCku
ivy16Cn/1XnpBw9M9DH18H1ENDFkOnUJYa8NU/t9lJJqNapDZ3zTLIlNd28nl3LP
HfbPGhq7qMAYmtiYt6rxHRBazL1OEFf2xb9DIVVlIKQXf/cCAwEAAaAAMA0GCSqG
SIb3DQEBCwUAA4IBAQArBhbVjPadSIWK9yGO7oca2TT+ZMp2kw4OY7+NHj+4NUFk
CKe2ZOAdvKM9wqY5P4QHux1WnqzEtga78ykaJofHeB/EFFqMkun5ETFbd/wIGKMy
WdB/vNNbsv5Hf2/ezGiw1HUsCGp2P/JTDO9+a5O3ioFhp4tvfJ7TBfdzD5eq7Xlq
DAHXPimbtnqiGGBf6efefG/Rl4cvvLyH5k/mUj00/stx3rjVayvedzOL8W4oRoxJ
SQEaqlp/MtPLXBuG0RkZsJloon+aZfcR3WE4iG2BVQe7Dqtdto+mRa9e1ba0ZUQK
Fq1iIGvsp9YIHCS3NXeJBeIllYkFK2hI7o6hALPf
-----END CERTIFICATE REQUEST-----
Para tener el servidor funcionando con certificados gratuitos de Let's encrypt los pasos son los siguientes:
```
$ cd
$ git clone https://github.com/letsencrypt/letsencrypt
$ sudo mkdir /etc/letsencrypt
$ sudo chown ubuntu:ubuntu /etc/letsencrypt
$ vim /etc/letsencrypt/cli.ini
```
Con el contenido siguiente:
```
authenticator = webroot
webroot-path = /home/ubuntu/pictogram/sails/src/assets/
server = https://acme-v01.api.letsencrypt.org/directory
renew-by-default
agree-dev-preview
agree-tos
email = info@yottacode.com
```
Para permitir a letsencrypt verificar nuestro servidor, debemos facilitar la entrada por HTTP. Para ello instalamos nginx y lo configuramos para que redirija a HTTPS:
```
$ sudo apt-get install nginx
$ sudo vim /etc/nginx/site-enabled/default
```
Con el siguiente contenido:
```
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name _;
return 301 https://$host$request_uri;
}
```
Ahora relanzamos nginx y solicitamos el certificado
```
$ sudo service nginx reload
$ /home/ubuntu/letsencrypt/letsencrypt-auto --config /etc/letsencrypt/cli.ini -d dev.yottacode.com certonly
```
Ya tenemos nuestros certificados. Finalmente configuramos Sails para que apunte a ellos:
```
$ vim /home/ubuntu/pictogram/sails/src/config/local.js
```
Con el contenido para ssl:
```
ssl: {
key: fs.readFileSync('/etc/letsencrypt/live/dev.yottacode.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/dev.yottacode.com/cert.pem')
},
```
Ya podemos relanzar sails
```
$ cd /home/ubuntu/pictograms/sails/src
$ sudo forever stopall
$ sudo forever start app.js --debug
```
Y ahora configurar cron para que el certificado se renueve solito cada mes
```
$ sudo crontab -e
```
Añadimos la línea:
```
@monthly /home/ubuntu/letsencrypt/letsencrypt-auto --config /etc/letsencrypt/cli.ini -d dev.yottacode.com certonly
```
y voila!
\ No newline at end of file
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
"dependencies": { "dependencies": {
"async": "^2.0.0-rc.4", "async": "^2.0.0-rc.4",
"bcrypt-nodejs": "0.0.3", "bcrypt-nodejs": "0.0.3",
"chart.js": "^2.3.0",
"connect-redis": "3.0.2", "connect-redis": "3.0.2",
"connect-timeout": "^1.7.0", "connect-timeout": "^1.7.0",
"ejs": "^0.8.8", "ejs": "^0.8.8",
......
...@@ -21,8 +21,8 @@ module.exports = function (grunt) { ...@@ -21,8 +21,8 @@ module.exports = function (grunt) {
'assets/app/bower_components/angular-sanitize/angular-sanitize.js', 'assets/app/bower_components/angular-sanitize/angular-sanitize.js',
'assets/app/bower_components/ngtoast/dist/ngToast.js', 'assets/app/bower_components/ngtoast/dist/ngToast.js',
'assets/app/bower_components/Chart.js/Chart.js', 'assets/app/bower_components/chart.js/dist/Chart.min.js',
'assets/app/bower_components/angular-chart.js/dist/angular-chart.js', 'assets/app/bower_components/angular-chart.js/dist/angular-chart.min.js',
'assets/app/bower_components/ng-lodash/build/ng-lodash.js', 'assets/app/bower_components/ng-lodash/build/ng-lodash.js',
'assets/app/bower_components/ng-file-upload/angular-file-upload-shim.js', 'assets/app/bower_components/ng-file-upload/angular-file-upload-shim.js',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment