Commit 2e789223 by Arturo Montejo Ráez

fixed merge conflicts

parents 03bef2e9 cb78814c
Showing with 263 additions and 181 deletions
......@@ -10,7 +10,7 @@ android {
versionCode 1
versionName "1.3"
resValue "string", "db_name", "PCB.db"
resValue "integer", "db_version", "8"
resValue "integer", "db_version", "10"
//resValue "string", "app_version", "1.1"
resValue "string", "core_vocabulary", "core_vocabulary"
resValue "string", "apk", "to_be_set_in_subproject"
......
......@@ -5,7 +5,6 @@ import android.util.Log;
import com.yottacode.net.RestapiWrapper;
import com.yottacode.pictogram.R;
import com.yottacode.pictogram.action.PictoAction;
import com.yottacode.pictogram.action.VocabularyAction;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.net.ImgDownloader;
......@@ -69,6 +68,7 @@ public class Vocabulary implements Iterable<Picto> {
VocabularyTalk.iVocabularyListener vocabulary_listeners[] = {new VocabularyTalk.iVocabularyListener() {
@Override
public void change(action action, int picto_cat, int picto_id, JSONObject args) {
switch (action) {
case delete: {
removePicto(picto_cat, picto_id);
......@@ -189,7 +189,7 @@ public class Vocabulary implements Iterable<Picto> {
@Override
public void result(JSONObject result) {
if (result != null) {
if (result != null && PCBcontext.is_user_logged()) {
JSONObject picto, attributes;
JSONObject stupicto = null;
try {
......@@ -207,12 +207,11 @@ public class Vocabulary implements Iterable<Picto> {
stupicto.getInt("id"),
attributes);
}
synchronizeImgs(pictos);
if (PCBcontext.is_user_logged()) {
PCBcontext.getPcbdb().setStudentVocabulary(Vocabulary.this);
PCBcontext.getPcbdb().setActiveSceneForStudent(result); //Aqui inserto en scene los datos que llegan de la activa
}else
Log.i(this.getClass().getName(), "Downloaded images ended when the user comes to logout");
PCBcontext.getPcbdb().setStudentVocabulary(Vocabulary.this);
PCBcontext.getPcbdb().setActiveSceneForStudent(result); //Aqui inserto en scene los datos que llegan de la activa
Log.i(this.getClass().getName(), " Pictos downloaded: " + result.getJSONArray("pictos").length());
} catch (JSONException e) {
StackTraceElement traces[] = e.getStackTrace();
......@@ -222,6 +221,7 @@ public class Vocabulary implements Iterable<Picto> {
this.error(new RestapiWrapper.HTTPException("JSON Error:" + e.getMessage(), -1));
}
}
else Log.e(this.getClass().getName(), "Downloaded images ended when the user comes to logout");
}
@Override
......@@ -368,7 +368,10 @@ public class Vocabulary implements Iterable<Picto> {
int index=find_picto_index(pic_cat, pic_id);
if (index>=0) { //puede ocurrir que se intente modificar un pictograma que fue borrado
Picto picto = this.pictos.get(pic_cat).get(index);
String old_legend=picto.get_legend();
picto.set_json_attr(attrs);
if (!old_legend.equals(picto.get_legend())) //puede ocurrir que se cambie la leyenda de TODOS los pictos
this.synchronize();
PCBcontext.getPcbdb().modifyPicto(pic_id, attrs.toString());
}
else
......
package com.yottacode.pictogram.net;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.yottacode.net.RestapiWrapper;
......@@ -76,12 +75,12 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
}
@Override
public void result(JSONObject result) {
public void result(JSONObject result) { PCBcontext.getPcbdb().user_online(true);
}
@Override
public void error(RestapiWrapper.HTTPException e) {
Log.e(this.getClass().getSimpleName(), "Error un when server login:" + e.getMessage()+"( error "+e.getCode()+")");
Log.e(this.getClass().getSimpleName(), "Error when server login:" + e.getMessage()+"( error "+e.getCode()+")");
if (e instanceof LoginException)
for (iNetServiceStatus listener: listeners)
if (listener instanceof iNetServiceDevice) ((iNetServiceDevice)listener).restart_app(false);
......@@ -100,7 +99,7 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
@Override
public void result(JSONObject result) {
PCBcontext.getPcbdb().user_online(true);
}
@Override
......@@ -217,7 +216,7 @@ public class NetService implements Runnable, RestapiWrapper.iSilentLogin {
return restfullSynchroTimming;
}
private void synchronizeStudentAttributes() {
public void synchronizeStudentAttributes() {
int id=PCBcontext.getPcbdb().getCurrentUser().get_id_stu();
PCBcontext.getRestapiWrapper().ask("stu/" + id, new RestapiWrapper.iRestapiListener() {
@Override
......
......@@ -41,7 +41,9 @@ public class StudentTalk implements Emitter.Listener {
String pic=msg.getString("pic");
String lang=msg.getString("lang");
String attributes=msg.getString("attributes");
JSONObject license=msg.getJSONObject("license");
//JSONObject license= msg.getJSONObject("license");
Log.e("STUDENT","change...remove license in hard when lincense is not null");
JSONObject license=new JSONObject().put("isValid",true);
User user=PCBcontext.getPcbdb().getCurrentUser();
User updatedUser=new User(id, username, user.get_pwd_stu(), name, surname, id_active_scene, pic, gender, lang, attributes,
user.get_id_sup(), user.get_email_sup(), user.get_pwd_sup(), user.get_name_sup(), user.get_surname_sup(), user.get_url_img_sup(), user.get_gender_sup(),
......
......@@ -23,6 +23,7 @@ import org.json.JSONException;
import org.json.JSONObject;
public final class PCBcontext {
private static final String LOG_TAG =PCBcontext.class.getName();
private static Context context;
private static PCBDBHelper pcbdb;
private static Device device=null;
......@@ -107,8 +108,10 @@ public final class PCBcontext {
PCBcontext.getDevice().insertUser(updatedStudent);
if (updatedStudent.is_picto_size_big()!=getPcbdb().getCurrentUser().is_picto_size_big() || PCBcontext.getVocabulary().has_categories() != vocabulary.has_categories()
|| updatedStudent.get_active_scene() != PCBcontext.getPcbdb().getCurrentUser().get_active_scene())
PCBcontext.getNetService().restart_app(false);
|| updatedStudent.get_active_scene() != PCBcontext.getPcbdb().getCurrentUser().get_active_scene()) {
Log.e(LOG_TAG, "Major config modification. Restarting is mandatory");
PCBcontext.getNetService().restart_app(false);
}
else {
PCBcontext.getPcbdb().setCurrentUser(updatedStudent);
PCBcontext.getNetService().getNetServiceDevice().updateUserConfig(updatedStudent, valid_license);
......
......@@ -49,7 +49,7 @@ pwd TEXT(40) NOT NULL,
name TEXT(40) NOT NULL,
surname TEXT(60) NOT NULL,
url_img VARCHAR(250) NOT NULL,
gender TEXT(1) NOT NULL CHECK (gender IN ('M','F')),
gender TEXT(1) NULL CHECK (gender IN (NULL, 'M','F')),
lang TEXT(5) NOT NULL CHECK (lang in ('en-gb','en-us','es-es')),
tts_engine TEXT(100) NULL,
office TEXT(140) NULL
......
......@@ -20,7 +20,7 @@
<string name="loginErrorTxt">Login</string>
<string name="loginErrorMsg">Invalid user or password. Please, try it again.</string>
<string name="loginNoLicenseMsg">Not valid user license. Please, contact with Yotta.</string>
<string name="loginExpiredLicenseMsg">User license was expired on</string>
<string name="loginExpiredLicenseMsg">User license was expired. Please contact with Yotta.</string>
<string name="userInetErrorMsg">Unknown new user name because Internet conection is not available</string>
<string name="userLoadingTxt">Loading</string>
<string name="userLoadingMsg">Loading students. Please wait.</string>
......@@ -84,6 +84,7 @@
<string name="fa_flask">&#xf0c3;</string>
<string name="fa_exclamation_triangle">&#xf071;</string>
<string name="fa_user_plus">&#xf234;</string>
<string name="fa_question_circle">&#xf059;</string>
<string name="google_play_student_apk">https://play.google.com/store/apps/details?id=com.yottacode.yotta_tablet</string>
<string name="google_play_supervisor_apk">https://play.google.com/store/apps/details?id=com.yottacode.supervisor_tablet</string>
......
......@@ -24,7 +24,7 @@
<string name="loginErrorTxt">Login</string>
<string name="loginErrorMsg">El usuario no existe o la contraseña indicada no es correcta. Inténtelo de nuevo.</string>
<string name="loginNoLicenseMsg">Licencia incorrecta o caducada. Contacte con Yotta para adquirir una.</string>
<string name="loginExpiredLicenseMsg">La licencia del usuario expiró con fecha</string>
<string name="loginExpiredLicenseMsg">La licencia del usuario expiró. Contacte con Yotta para ampliar la licencia actual</string>
<string name="imguserLoadingMsg">Cargando imágenes de los alumnos. Por favor espere.</string>
<string name="imguserLoadingErrMsg">Imagen con formato no válido.</string>
......@@ -78,6 +78,7 @@
<string name="fa_certificate">&#xf0a3;</string>
<string name="fa_flask">&#xf0c3;</string>
<string name="fa_exclamation_triangle">&#xf071;</string>
<string name="fa_question_circle">&#xf059;</string>
<string name="fa_user_plus">&#xf234;</string>
<string name="google_play_student_apk">https://play.google.com/store/apps/details?id=com.yottacode.yotta_tablet</string>
<string name="google_play_supervisor_apk">https://play.google.com/store/apps/details?id=com.yottacode.supervisor_tablet</string>
......
......@@ -21,7 +21,7 @@
<string name="loginErrorTxt">Login</string>
<string name="loginErrorMsg">El usuario no existe o la contraseña indicada no es correcta. Inténtelo de nuevo.</string>
<string name="loginNoLicenseMsg">El usuario no tiene una licencia válida. Contacte con Yotta para adquirir una.</string>
<string name="loginExpiredLicenseMsg">La licencia del usuario expiró con fecha</string>
<string name="loginExpiredLicenseMsg">La licencia del usuario expiró. Contacte con Yotta para ampliar la licencia actual</string>
<string name="userInetErrorMsg">Este usuario requiere conexión a internet para ser validado</string>
<string name="userLoadingTxt">Cargando</string>
<string name="userLoadingMsg">Cargando alumnos. Por favor espere.</string>
......@@ -84,6 +84,7 @@
<string name="fa_flask">&#xf0c3;</string>
<string name="fa_exclamation_triangle">&#xf071;</string>
<string name="fa_user_plus">&#xf234;</string>
<string name="fa_question_circle">&#xf059;</string>
<string name="google_play_student_apk">https://play.google.com/store/apps/details?id=com.yottacode.yotta_tablet</string>
<string name="google_play_supervisor_apk">https://play.google.com/store/apps/details?id=com.yottacode.supervisor_tablet</string>
</resources>
......@@ -5,10 +5,8 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
......@@ -18,14 +16,12 @@ import android.speech.tts.UtteranceProgressListener;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
......@@ -51,7 +47,6 @@ import com.yottacode.pictogram.tabletlibrary.net.NetServiceTablet;
import com.yottacode.pictogram.tools.Img;
import com.yottacode.pictogram.tools.PCBcontext;
import com.yottacode.pictogram.tts.TTSHelper;
import com.yottacode.tools.GUITools;
import org.json.JSONArray;
import org.json.JSONException;
......
......@@ -2,12 +2,8 @@ package com.yottacode.pictogram.tabletlibrary.gui.login;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.provider.ContactsContract;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
......@@ -22,9 +18,8 @@ import java.util.Vector;
import static com.yottacode.pictogram.R.string.fa_certificate;
import static com.yottacode.pictogram.R.string.fa_flask;
import static com.yottacode.pictogram.R.string.fa_exclamation_triangle;
import static com.yottacode.pictogram.R.string.fa_user_plus;
import static com.yottacode.pictogram.R.string.fa_question_circle;
/**
* Creates a View for each student on the list with a photo and his/her name.
* It uses list_single.xml for the layout creation.
......@@ -73,8 +68,10 @@ public class CustomList extends ArrayAdapter<String>{
// License, except add student view
TextView licenseView = (TextView) rowView.findViewById(R.id.loginStudentLicense);
licenseView.setTypeface(fontAwesome);
if(licenses[position].equals("pro")) {
if (!PCBcontext.getNetService().online()) {
licenseView.setText(fa_question_circle);
licenseView.setTextColor(getContext().getResources().getColor(R.color.text_danger));
}else if(licenses[position].equals("pro")) {
licenseView.setText(fa_certificate);
licenseView.setTextColor(getContext().getResources().getColor(R.color.text_primary));
}else if (licenses[position].equals("trial")) {
......
......@@ -8,7 +8,6 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
......@@ -116,7 +115,8 @@ public class StudentFragmentGrid extends Fragment {
return;
}
new_user(i);
new_user(i, licenseStudents[i].equals("pro") || licenseStudents[i].equals("trial") );
download_supervisors(PCBcontext.getPcbdb().getCurrentUser().get_id_stu());
}
}
......@@ -179,8 +179,9 @@ public class StudentFragmentGrid extends Fragment {
/**
* Change user data, load vocabulary and goes to VOCA Activity
* @param i Position on students downloaded collection
* @param license_valid
*/
private void new_user(int i) {
private void new_user(int i, final boolean license_valid) {
JSONObject st = this.downloaded_students.get(i);
Intent intent = getActivity().getIntent();
......@@ -220,6 +221,7 @@ public class StudentFragmentGrid extends Fragment {
public void loadComplete() {
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
PCBcontext.getPcbdb().user_valid(license_valid);
Intent pictogramActivity = new Intent(getActivity(), VOCA.class);
startActivity(pictogramActivity);
}
......
......@@ -59,7 +59,13 @@ public class ListInstructionsFragment extends Fragment{
@Override
public void onStart() {
super.onStart();
super.onStart();
checkStudent();
initMethods(getView());
initInstructions(getView());
setMethods();
methodPosition=-1;
instructionPosition=-1;
}
public void initAdapters() {
......@@ -104,16 +110,12 @@ public class ListInstructionsFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_instructions_session, container, false);
progressDialog = ProgressDialog.show(getActivity(), getString(R.string.session_instruction), getString(R.string.session_loading));
checkStudent();
initMethods(view);
initInstructions(view);
setMethods();
methodPosition=-1;
instructionPosition=-1;
return view;
View view = inflater.inflate(R.layout.fragment_instructions_session, container, false);
progressDialog = ProgressDialog.show(getActivity(), getString(R.string.session_instruction), getString(R.string.session_loading));
return view;
}
void close() {
ListInstructionsFragment.this.getActivity().finish();
startActivity(new Intent(getActivity(), VOCA.class));
......
......@@ -87,7 +87,7 @@ public class NetServiceTablet implements NetService.iNetServiceDevice {
public void restart_app(boolean resetPrevUser) {
Log.e(LOG_TAG,"App restarting, reset last login:"+resetPrevUser);
Log.i(LOG_TAG,"App restarting, reset last login:"+resetPrevUser);
Context context=PCBcontext.getActivityContext();
......
......@@ -177,7 +177,7 @@ public class SessionWrapper {
public static void getMethods(final iMethodWrapper listener) {
int id=PCBcontext.getPcbdb().getCurrentUser().get_id_stu();
Log.i(LOG_TAG,"License valid:"+ PCBcontext.getPcbdb().isUser_valid()+" User:"+id+","+PCBcontext.getPcbdb().getCurrentUser().get_name_stu());
PCBcontext.getRestapiWrapper().ask("stu/" + id+"/methods",null,"get",true, new RestapiWrapper.iRestapiListener() {
@Override
public void preExecute() {
......@@ -194,6 +194,7 @@ public class SessionWrapper {
try {
listener.methods(new JSONArray(1).put(result));
} catch (JSONException e) {
listener.methods(new JSONArray());
listener.error(e.getMessage());
}
}
......
......@@ -6,6 +6,11 @@
state: present
when: ansible_distribution == 'CentOS' or ansible_distribution == 'Amazon'
- name: Install Postfix (for sending emails)
package:
name: postfix
state: present
- name: Install NPM dependencies
npm:
path: "{{ server_path }}/{{ server_relative_path }}"
......
/* global Student, PictoCore, VStuLastInstruction, StuPicto, StuSup, sailsTokenAuth, sails,
Picto */
const generatePassword = require('password-generator');
/**
/* StudentController
*
......@@ -182,7 +184,6 @@ module.exports = {
resolve(params.license_number);
else {
License.newTrial(params.id_sup, function(err, license) {
console.log(license.number);
if (err)
reject(err);
else
......@@ -193,45 +194,88 @@ module.exports = {
.then((license_number) => {
// Check license
License.isActivable(license_number, function(err) {
if (err) {
return res.badRequest(err.message);
}
return new Promise(function(resolve, reject) {
License.isActivable(license_number, function(err) {
if (err)
reject(err)
else
resolve(license_number);
});
});
// Create student
Student.create(params)
.then(function(created) {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
})
.then((license_number) => {
return new Promise(function(resolve, reject) {
Student.genUsername(params.name, params.surname, function(username) {
resolve({username: username, license_number: license_number});
});
});
})
.then((info) => {
// Create student
var stuData = {
name: params.name,
surname: params.surname,
password: generatePassword(),
username: info.username,
lang: params.lang
};
Student.create(stuData)
.then(function(created) {
sails.log.debug('Student ' + created.id + ' created: ' + JSON.stringify(created));
// Activate license
License.activate(info.license_number, created.id, function(err, license) {
if (err) {
Student.destroy({id: created.id});
return res.badRequest(err);
}
// Activate license
License.activate(license_number, created.id, function(err, license) {
if (err) {
created = created.toJSON();
created.license = license.toObject();
// Link to supervisor
StuSup.create({student: created.id, supervisor: params.id_sup})
.then((stu_sup) => {
if (!stu_sup) {
Student.destroy({id: created.id});
return res.badRequest(err);
return res.serverError("Unable to link to supervisor");
}
created = created.toJSON();
created.license = license.toObject();
// Link to supervisor
StuSup.create({student: created.id, supervisor: params.id_sup})
.then((stu_sup) => {
if (!stu_sup) {
Student.destroy({id: created.id});
return res.serverError("Unable to link to supervisor");
}
return res.ok(created);
})
.catch((err) => {
Student.destroy({id: created.id});
throw err
});
//
// Send sockets messages
//
const socketToOmit = (req.isSocket) ? req.socket : undefined;
const linkSupervisorToStudentEvent = sails.hooks.events.linkSupervisorToStudent(
stu_sup.supervisor,
stu_sup.student
);
sails.hooks.events.broadcastEvent(
sails.hooks.rooms.supervisor(stu_sup.supervisor),
linkSupervisorToStudentEvent,
socketToOmit
);
sails.hooks.events.broadcastEvent(
sails.hooks.rooms.student(stu_sup.student),
linkSupervisorToStudentEvent,
socketToOmit
);
// return OK
return res.ok(created);
})
.catch((err) => {
Student.destroy({id: created.id});
throw err
});
})
.catch(function(err) {
sails.log.debug(err.message);
return res.serverError(err.message);
});
})
.catch(function(err) {
sails.log.debug(err.message);
return res.serverError(err.message);
});
})
.catch((err) => {res.serverError(err)});
......@@ -874,9 +918,11 @@ module.exports = {
.then(function(scene){
if(!scene)
throw new Error("Scene not found");
console.log("scene ID: " + scene.id)
Scene.pictos(scene.id, function(err, pictos){
if (err)
return res.serverError("Error obtaining pictos: "+ err);
scene = scene.toObject();
scene.active = true;
scene.pictos=pictos;
return res.ok(scene);
......@@ -894,6 +940,7 @@ module.exports = {
updateActiveScene: function(req,res){
var params = req.allParams();
Student.findOne({id:params.id_stu})
.populate('license')
.then(student => {
student.id_active_scene=params.id_scene;
delete student.password;
......
......@@ -4,6 +4,7 @@ const fs = require('fs');
const path = require('path');
const lodash = require('lodash');
const bcrypt = require('bcrypt-nodejs');
const generatePassword = require('password-generator');
/**
* SupervisorController
......@@ -272,7 +273,7 @@ module.exports = {
var params = req.params.all();
// Send email confirmation --------------------------------
function sendConfirmationMail(supervisor, cb) {
function sendConfirmationMail(supervisor, password, cb) {
var token = sailsTokenAuth.issueToken({
id_sup: supervisor.id,
......@@ -282,7 +283,11 @@ module.exports = {
var message = sails.__({
phrase: 'signin_mail',
locale: params.lang || 'es-es'
}) + 'https://' + req.headers.host + '/sup/activate/' + token; // expires in 1 week
},
{
url: 'https://' + req.headers.host + '/sup/activate/' + token,
password: password
});
var subject = sails.__({
phrase: 'notification_from_pictogram',
......@@ -303,13 +308,17 @@ module.exports = {
sails.log.debug("Creating supervisor with params " + JSON.stringify(params));
if (!params.password || !params.email )
if (!params.name || !params.email || params.role != 'office' && !params.surname)
return res.badRequest("Invalid params");
// randomly generated memorable password
var password = generatePassword();
var supData = {
role: params.role,
name: typeof params.name == 'undefined' ? '' : params.name,
password: params.password,
name: params.name,
surname: params.surname,
password: password,
email: params.email,
pic: sails.config.pictogram.paths.defaultAvatarFileName,
lang: params.lang || 'es-es',
......@@ -321,7 +330,7 @@ module.exports = {
if (!sup)
return res.serverError("Supervisor created but returned null");
sendConfirmationMail(sup, (err) => {
sendConfirmationMail(sup, password, (err) => {
if (err) throw err;
return res.ok();
});
......
/* global Student, StuSup, sails */
const bcrypt = require('bcrypt-nodejs');
var _ = require('lodash');
/**
* @class Student
......@@ -60,7 +61,7 @@ module.exports = {
lang: {
columnName: 'lang',
type: 'string',
size: 2
size: 5
},
id_active_scene: {
columnName: 'id_active_scene',
......@@ -630,6 +631,36 @@ module.exports = {
.catch(err => {throw err});
})
.catch(err => {cb(err, null)});
},
/**
* Generates a new username using name and surname
*/
genUsername: function(name, surname, callback) {
var prefix = (name + ' ' + surname).split(/\s+/).map(x => {return x.toLowerCase()[0]}).join('');
var counter = 0;
var found = true;
async.doWhilst(
function (cb) {
counter = counter + 1;
Student.findOne({username: prefix + counter})
.then((l) => {
if (!l)
found = false;
cb();
})
.catch((err) => {
found = false;
cb();
});
},
function () {
return found;
},
function () {
callback(prefix + counter);
}
);
}
};
......@@ -249,6 +249,7 @@
"msg_change_password": "Please enter a new password for your account:",
"msg_request_change_password": "Enter your email to request for a password change. An e-mail will be sent to access password change form.",
"name": "Name",
"name_invalid": "Invalid name",
"new_img": "New image",
"new_instruction": "New instruction",
"new_method": "New method",
......@@ -409,7 +410,8 @@
"state_spontaneous": "Spontaneous",
"state_supervised": "Supervised",
"stop": "Stop",
"student_account_confirm": "The new account is now available from the students list.",
"student_existing_confirm": "The student's account is now available from the students list below.",
"student_new_confirm": "The new account for <b>{{ name }} {{ surname }}</b>, with serial number <tt>{{ serial }}</tt> and credential username <tt>{{ username }}</tt>, is now available from the students list. <br> Please, set password for this new account in its <a href=\"/app/#/student/{{ id_stu }}/setup\">configuration section</a>.",
"student_added": "Student added",
"student_already_exists": "A student with that username already exists, please try with another one",
"student_already_linked": "The student is already linked to your account",
......@@ -438,6 +440,7 @@
"supervisors": "Supervisors",
"support": "User support",
"surname": "Surname",
"surname_invalid": "Invalid surname",
"tag_deleted": "Tag deleted",
"tape_background": "Tape background",
"template_deleted": "Template deleted",
......
......@@ -248,6 +248,7 @@
"msg_change_password": "Por favor, introduzca la nueva clave para su cuenta:",
"msg_request_change_password": "Introduzca su correo electrónico para solicitar el cambio de clave. Recibirá un correo con la dirección de acceso al formulario de cambio de clave.",
"name": "Nombre",
"name_invalid": "Nombre inválido",
"new_img": "Nueva imagen",
"new_instruction": "Nueva instrucción",
"new_method": "Nuevo método",
......@@ -407,7 +408,8 @@
"state_spontaneous": "Espontáneo",
"state_supervised": "Guiado",
"stop": "Parar",
"student_account_confirm": "La nueva cuenta ahora está disponible en su lista de alumnos.",
"student_existing_confirm": "La nueva cuenta de estudiante ahora está disponible en su lista de alumnos, abajo.",
"student_new_confirm": "La cuenta para <b>{{ name }} {{ surname }}</b>, con número de serie <tt>{{ serial }}</tt> y credencial de usuario <tt>{{ username }}</tt>, está ya disponible en su lista de estudiantes. <br>Por favor, establezca la contraseña para la nueva cuenta en la <a href=\"/app/#/student/{{ id_stu }}/setup\">sección de configuración</a> de la misma.",
"student_added": "Estudiante añadido",
"student_already_exists": "Ya existe un estudiante con ese nombre de usuario. Por favor, inténtelo de nuevo con algo diferente.",
"student_already_linked": "El estudiante ya está vinculado a su cuenta",
......@@ -436,6 +438,7 @@
"support": "Atención al cliente",
"supervisors": "Supervisores",
"surname": "Apellidos",
"surname_invalid": "Apellidos inválidos",
"tag_deleted": "Etiqueta borrada",
"tape_background": "Fondo de la cinta",
"template_deleted": "Plantilla eliminada",
......
......@@ -100,15 +100,12 @@ function LoginCtrl(
var formdata_empty = {
name: '',
surname: '',
email: '',
password: '',
password_confirm: '',
lang: '',
role: '',
};
$scope.minlength = CONSTANTS.password_minlength;
/* Forms objects */
$scope.forms = {};
......@@ -142,13 +139,13 @@ $scope.signup = function (formName) {
return;
}
if ($scope.formdata.password.length < CONSTANTS.password_minlength) {
ngToast.danger($translate.instant('password_short', {minlength: CONSTANTS.password_minlength}));
if (typeof $scope.formdata.name == 'undefined' || form.name.$invalid) {
ngToast.danger($translate.instant('name_invalid'));
return;
}
if ($scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger($translate.instant('password_match'));
if ($scope.formdata.role != "office" && (typeof $scope.formdata.surname == 'undefined' || form.surname.$invalid )) {
ngToast.danger($translate.instant('surname_invalid'));
return;
}
......
......@@ -152,25 +152,21 @@
<img src="img/parents.png" alt="{{'parents_tutor' | translate}}" title="{{'parents_tutor' | translate}}" />
</div>
<div class="form-group col-md-4">
<input type="hidden" ng-model="formdata.role" value="tutor"></input>
<label translate>name</label>
<div class="form-group">
<label translate>email</label>
<div class="form-group">
<input type="email" class="form-control" name="email" placeholder="{{ 'email' | translate }}" ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.tutorForm.email.$dirty && forms.tutorForm.email.$invalid" translate>email_invalid</span>
</div>
<input type="text" class="form-control" name="name" placeholder="{{ 'name' | translate }}" ng-model="formdata.name" required/>
</div>
<label translate>surname</label>
<div class="form-group">
<input type="text" class="form-control" name="surname" placeholder="{{ 'surname' | translate }}" ng-model="formdata.surname" required/>
</div>
<label translate>email</label>
<div class="form-group">
<input type="email" class="form-control" name="email" placeholder="{{ 'email' | translate }}" ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.tutorForm.email.$dirty && forms.tutorForm.email.$invalid" translate>email_invalid</span>
</div>
<fieldset>
<label translate>password</label>
<div class="form-group">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" name="password" required ng-model="formdata.password"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.tutorForm.password.$dirty && forms.tutorForm.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" required ng-model="formdata.password_confirm"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.tutorForm.password.$dirty && forms.tutorForm.password_confirm.$dirty" translate>password_match</span>
</div>
</fieldset>
<div class="form-group">
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
......@@ -208,26 +204,26 @@
<img src="img/therapist.png" alt="{{'therapist' | translate}}" title="{{'therapist' | translate}}" />
</div>
<div class="form-group col-md-4" id="tutor_form">
<input type="hidden" ng-model="formdata.role" value="therapist"></input>
<label translate>name</label>
<div class="form-group">
<input type="text" class="form-control" name="name" placeholder="{{ 'name' | translate }}" ng-model="formdata.name" required/>
</div>
<label translate>surname</label>
<div class="form-group">
<input type="text" class="form-control" name="surname" placeholder="{{ 'surname' | translate }}" ng-model="formdata.surname" required/>
</div>
<label translate>email</label>
<div class="form-group">
<label translate>email</label>
<input type="email" class="form-control" name="email" placeholder="{{ 'email' | translate }}" ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.therapistForm.email.$dirty && forms.therapistForm.email.$invalid" translate>email_invalid</span>
<span class="color_red text_sm pull-right" ng-show="forms.theraphistForm.email.$dirty && forms.theraphistForm.email.$invalid" translate>email_invalid</span>
</div>
<fieldset>
<label translate>password</label>
<div class="form-group">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" name="password" required ng-model="formdata.password"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.therapistForm.password.$dirty && forms.therapistForm.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" required ng-model="formdata.password_confirm"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.therapistForm.password.$dirty && forms.therapistForm.password_confirm.$dirty" translate>password_match</span>
</div>
</fieldset>
<div class="form-group">
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
</div>
<div class="form-group">
<label>Captcha</label>
<div vc-recaptcha></div>
......@@ -259,26 +255,16 @@
<img src="img/office.jpg" alt="{{'office_center' | translate}}" title="{{'office_center' | translate}}" />
</div>
<div class="form-group col-md-4" id="office_form">
<input type="hidden" ng-model="formdata.role" value="office"></input>
<label translate>name</label>
<div class="form-group">
<label translate>name</label>
<input type="text" class="form-control" placeholder="{{ 'name' | translate }}" name="name" required ng-model="formdata.name"/>
<input type="text" class="form-control" name="name" placeholder="{{ 'name' | translate }}" ng-model="formdata.name" required/>
</div>
<div class="form-group">
<label translate>email</label>
<input type="email" class="form-control" placeholder="{{ 'email' | translate }}" name="email" required ng-model="formdata.email"/>
<span class="color_red text_sm pull-right" ng-show="forms.officeForm.email.$dirty && forms.officeForm.email.$invalid" translate>email_invalid</span>
</div>
<fieldset>
<label translate>password</label>
<div class="form-group">
<input type="password" class="form-control" id="signin_password1" placeholder="{{ 'password_type' | translate }}" name="password" required ng-model="formdata.password"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.officeForm.password.$dirty && forms.officeForm.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="signin_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" required ng-model="formdata.password_confirm"/>
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.officeForm.password.$dirty && forms.officeForm.password_confirm.$dirty" translate>password_match</span>
</div>
</fieldset>
<div class="form-group">
<input type="checkbox" ng-model="formdata.disclaimer_accepted">
<span translate>disclaimer_accept</span>
......
......@@ -57,11 +57,11 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$scope.showForm = function () {
// Reset the form
$scope.formdata = {
username: '',
name: '',
password: '',
password_confirm: '',
name: $translate.instant('name'),
surname: $translate.instant('surname'),
name: '',
surname: '',
birthdate: Date(),
country: 'ES',
gender: 'M',
......@@ -94,6 +94,7 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$http.post(config.backend + '/stu/license/sup/' + $rootScope.user.id, {license: $scope.formdata.license_number})
.success(function (data) {
loadStudents();
$scope.confirmation_msg = $translate.instant('student_existing_confirm');
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
......@@ -118,18 +119,20 @@ dashboardControllers.controller('StudentsCtrl', function StudentsCtrl(
$scope.addNew = function (type) {
// set language according to interface settings
$scope.formdata.lang = $translate.use();
// Validate password match
if ($scope.formdata.password_confirm.length && $scope.formdata.password !== $scope.formdata.password_confirm) {
ngToast.danger($translate.instant('password_match'));
return;
}
$scope.formdata.lang = $rootScope.user.lang;
// Send creating call to server
$http.post(config.backend + '/stu', $scope.formdata)
.success(function (data) {
loadStudents();
$scope.confirmation_msg = $translate.instant('student_new_confirm',
{
name: data.name,
surname: data.surname,
username: data.username,
serial: data.license.number,
id_stu: data.id,
});
$scope.slide.rightTo('confirmation');
})
.error(function (err) {
......
......@@ -96,17 +96,12 @@
</div>
<div class="form-group col-md-4">
<div class="form-group">
<label translate>username</label>
<input type="username" class="form-control" id="setup_username" placeholder="{{ 'username_default' | translate }}" required ng-model="formdata.username" />
<label translate>name</label>
<input type="text" class="form-control" id="setup_name" placeholder="{{ 'name' | translate }}" required ng-model="formdata.name" />
</div>
<div class="form-group">
<label translate>password</label>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" name="password" ng-model="formdata.password" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.new.password.$dirty && forms.new.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" ng-model="formdata.password_confirm" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.new.password.$dirty && forms.new.password_confirm.$dirty" translate>password_match</span>
<label translate>surname</label>
<input type="text" class="form-control" id="setup_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdata.surname" />
</div>
<div class="form-group">
<label translate>license_number</label>
......@@ -140,17 +135,12 @@
</div>
<div class="form-group col-md-4" id="office_form">
<div class="form-group">
<label translate>username</label>
<input type="username" class="form-control" id="setup_username" placeholder="{{ 'username_default' | translate }}" required ng-model="formdata.username" />
</div>
<div class="form-group">
<label translate>password</label>
<input type="password" class="form-control" id="setup_password1" placeholder="{{ 'password_new_type' | translate }}" name="password" ng-model="formdata.password" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password.length < minlength && forms.test.password.$dirty && forms.test.password_confirm.$dirty"> {{ 'password_short' | translate:'{ minlength: minlength }' }}</span>
<label translate>name</label>
<input type="text" class="form-control" id="setup_name" placeholder="{{ 'name' | translate }}" required ng-model="formdata.name" />
</div>
<div class="form-group">
<input type="password" class="form-control" id="setup_password2" placeholder="{{ 'password_confirm' | translate }}" name="password_confirm" ng-model="formdata.password_confirm" required />
<span class="color_red text_sm pull-right" ng-show="formdata.password != formdata.password_confirm && forms.test.password.$dirty && forms.test.password_confirm.$dirty" translate>password_match</span>
<label translate>surname</label>
<input type="text" class="form-control" id="setup_surname" placeholder="{{ 'surname' | translate }}" required ng-model="formdata.surname" />
</div>
</div>
</div>
......@@ -173,7 +163,7 @@
<div ng-class="slide.back ? 'switch-animation-back' : 'switch-animation'" ng-switch-when="confirmation">
<h2>{{ 'account_available' | translate }} </h2>
<p translate>student_account_confirm</p>
<p ng-bind-html="confirmation_msg"></p>
<br>
<img src="img/child.png"/>
......
......@@ -5,12 +5,12 @@
"notification_from_pictogram": "Notification from Pictogram",
"no_name": "No name",
"no_surname": "No surname",
"office_link": "The office/center \"{{ name }}\" with email \"{{ email }}\" has added you as part of its team in Pictogram.",
"signin_mail": "To activate your Pictogram account, click on this link:\n",
"student_unlinked": "You have lost the link to the student \"{{ name }} {{ surname }}\", with license number \"{{ license }}\".",
"therapist_office_request": "{{ name }}, with email {{ email }}, is requesting to be linked as therapist to any of your students.",
"tutor_office_request": "{{ name }}, with email {{ email }}, is requesting to be linked as tutor/father/mother to any of your students.",
"office_link": "The office/center \"{{{ name }}}\" with email \"{{{ email }}}\" has added you as part of its team in Pictogram.",
"signin_mail": "To activate your Pictogram account, first click on this link:\n {{{ url }}} \nAccess with your email and the following password:\n {{{ password }}}\nWe recommend to change your password as soon as possible.",
"student_unlinked": "You have lost the link to the student \"{{{ name }}} {{{ surname }}}\", with license number \"{{{ license }}}\".",
"therapist_office_request": "{{{ name }}, with email {{{ email }}} is requesting to be linked as therapist to any of your students.",
"tutor_office_request": "{{{ name }}}, with email {{{ email }}}, is requesting to be linked as tutor/father/mother to any of your students.",
"Welcome": "Welcome",
"welcome_msg1": "Welcome to Pictogram, {{ name }}!",
"welcome_msg1": "Welcome to Pictogram, {{{ name }}}!",
"welcome_msg2": "Your account is now active. You can proceed to"
}
......@@ -5,12 +5,12 @@
"notification_from_pictogram": "Notificación desde Pictogram",
"no_name": "Sin nombre",
"no_surname": "Sin apellidos",
"office_link": "El centro/gabinete \"{{ name }}\", con correo electrónico \"{{ email }}\" le ha añadido como parte de su equipo.",
"signin_mail": "Para activar su cuenta en Pictogram, haga click en el siguiente enlace:\n",
"student_unlinked": "Se ha desvinculado de la cuenta de estudiante \"{{ name }} {{ surname }}\", con número de licencia \"{{ license }}\".",
"therapist_office_request": "El/la terapeuta {{ name }}, con correo electrónico {{ email }}, pide ser asociado a algún estudiante.",
"tutor_office_request": "El/la tutor/a/padre/madre {{ name }}, con correo electrónico {{ email }}, pide ser asociado a algún estudiante.",
"office_link": "El centro/gabinete \"{{{ name }}}\", con correo electrónico \"{{{ email }}}\" le ha añadido como parte de su equipo.",
"signin_mail": "Para activar su cuenta en Pictogram, primero haga click en el siguiente enlace:\n {{{ url }}} \nAcceda con su correo y la contraseña siguiente:\n {{{ password }}}\nLe recomendamos modificar la contraseña tan pronto acceda al sistema.",
"student_unlinked": "Se ha desvinculado de la cuenta de estudiante \"{{{ name }}} {{{ surname }}}\", con número de licencia \"{{{ license }}}\".",
"therapist_office_request": "El/la terapeuta {{{ name }}}, con correo electrónico {{{ email }}}, pide ser asociado a algún estudiante.",
"tutor_office_request": "El/la tutor/a/padre/madre {{{ name }}}, con correo electrónico {{{ email }}}, pide ser asociado a algún estudiante.",
"Welcome": "Bienvenido",
"welcome_msg1": "¡Bienvenido a Pictogram, {{ name }}!",
"welcome_msg1": "¡Bienvenido a Pictogram, {{{ name }}}!",
"welcome_msg2": "Su cuenta está ahora activa, por lo que puede"
}
......@@ -24,6 +24,7 @@
"jsonwebtoken": "~0.4.0",
"lodash": "^3.10.1",
"moment": "^2.18.1",
"password-generator": "^2.1.0",
"rc": "~0.5.0",
"sails": "^0.12.3",
"sails-disk": "~0.10.0",
......
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