Commit a9388700 by Sebastián Collado Montañez

Merge branch 'develop' of http://gitlab.ujaen.es/yotta/pictogram into develop

parents b4dc86eb e197815f
Showing with 395 additions and 123 deletions
...@@ -15,6 +15,8 @@ sails/arasaac* ...@@ -15,6 +15,8 @@ sails/arasaac*
sails/arasaac sails/arasaac
sails/src/assets/symbolstx* sails/src/assets/symbolstx*
sails/src/assets/upload sails/src/assets/upload
sails/src/assets/arasaac*
sails/src/assets/arasaac
sails/upload.tgz sails/upload.tgz
# Webapp # # Webapp #
...@@ -24,7 +26,6 @@ sails/src/assets/app/bower_components ...@@ -24,7 +26,6 @@ sails/src/assets/app/bower_components
sails/src/assets/app/modules sails/src/assets/app/modules
sails/src/assets/app/css sails/src/assets/app/css
sails/src/assets/app/js sails/src/assets/app/js
sails/src/assets/scripts/config.js
sails/src/config/ssl/**/*.key sails/src/config/ssl/**/*.key
sails/src/config/ssl/**/*.crt sails/src/config/ssl/**/*.crt
sails/src/config/ssl/**/*.csr sails/src/config/ssl/**/*.csr
......
...@@ -178,6 +178,19 @@ public class Device extends SQLiteOpenHelper { ...@@ -178,6 +178,19 @@ public class Device extends SQLiteOpenHelper {
return user; return user;
} }
public Vector<User> recoverSupervisors(Integer id_stu) throws JSONException{
SQLiteDatabase db = this.getReadableDatabase();
Vector<User> users = new Vector<>();
Cursor cursor = db.query("users_detail", null, null, null, null, null, null, null);
while (cursor.moveToNext())
if (cursor.getInt(0) == id_stu)
users.add(new User(cursor.getInt(0), cursor.getString(1), cursor.getString(2), cursor.getString(3), cursor.getString(4), cursor.getString(5), cursor.getString(6), cursor.getString(7), cursor.getString(8),
cursor.getInt(9), cursor.getString(10), cursor.getString(11), cursor.getString(12), cursor.getString(13), cursor.getString(14), cursor.getString(15), cursor.getString(16), cursor.getString(17), cursor.getString(18)));
cursor.close();
//db.close(); <--no es necesario cerrar la bbdd https://groups.google.com/forum/#!msg/android-developers/NwDRpHUXt0U/jIam4Q8-cqQJ
return users;
}
public Vector<User> recoverStudents(Integer id_sup) throws JSONException{ public Vector<User> recoverStudents(Integer id_sup) throws JSONException{
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
Vector<User> users = new Vector<>(); Vector<User> users = new Vector<>();
......
...@@ -52,7 +52,6 @@ public class Picto extends Img { ...@@ -52,7 +52,6 @@ public class Picto extends Img {
public static String LEGEND = "legend"; public static String LEGEND = "legend";
public static String URI_SOUND = "uri_sound"; public static String URI_SOUND = "uri_sound";
public static String USER_AVATAR = "user_avatar"; public static String USER_AVATAR = "user_avatar";
public static String ASSOCIATED_PERSON = "associated_person";
} }
...@@ -91,7 +90,7 @@ public class Picto extends Img { ...@@ -91,7 +90,7 @@ public class Picto extends Img {
Log.e(LOG_TAG,e.getMessage()); Log.e(LOG_TAG,e.getMessage());
} }
} }
public Picto(int id, String url, String translation, int cat, int row, int column, int freeRow, int freeColumn, int stupicto_id, String uri_sound, String user_avatar, String associated_person) throws JSONException { public Picto(int id, String url, String translation, int cat, int row, int column, int freeRow, int freeColumn, int stupicto_id, String uri_sound, String user_avatar) throws JSONException {
this(id, url, new JSONObject() this(id, url, new JSONObject()
.put(JSON_ATTTRS.CATEGORY, cat) .put(JSON_ATTTRS.CATEGORY, cat)
.put(JSON_ATTTRS.COLUMN, column) .put(JSON_ATTTRS.COLUMN, column)
...@@ -104,7 +103,6 @@ public class Picto extends Img { ...@@ -104,7 +103,6 @@ public class Picto extends Img {
.put(JSON_ATTTRS.EXPRESSION,translation) .put(JSON_ATTTRS.EXPRESSION,translation)
.put(JSON_ATTTRS.URI_SOUND,uri_sound) .put(JSON_ATTTRS.URI_SOUND,uri_sound)
.put(JSON_ATTTRS.USER_AVATAR,user_avatar) .put(JSON_ATTTRS.USER_AVATAR,user_avatar)
.put(JSON_ATTTRS.ASSOCIATED_PERSON,associated_person)
); );
} }
public Picto(int id, String url,String translation, String attributes) throws JSONException { public Picto(int id, String url,String translation, String attributes) throws JSONException {
...@@ -305,14 +303,14 @@ public class Picto extends Img { ...@@ -305,14 +303,14 @@ public class Picto extends Img {
* *
* @return the associated person of a picto * @return the associated person of a picto
*/ */
public String get_associated_person() { public String get_user_avatar() {
String ass_person = null; String associated_user = null;
try { try {
ass_person = this.attributes.getString(JSON_ATTTRS.ASSOCIATED_PERSON); associated_user = this.attributes.getString(JSON_ATTTRS.USER_AVATAR);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
return ass_person; return associated_user;
} }
/** /**
...@@ -377,6 +375,18 @@ public class Picto extends Img { ...@@ -377,6 +375,18 @@ public class Picto extends Img {
/** /**
* *
* @return the uri of associated sound of the picto
*/
public void setUriSound(String path){
try {
this.attributes.put(JSON_ATTTRS.URI_SOUND, path);
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
*
* @return the associated user avatar of the picto * @return the associated user avatar of the picto
*/ */
public String getUserAvatar(){ public String getUserAvatar(){
......
...@@ -427,7 +427,7 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -427,7 +427,7 @@ public class Vocabulary implements Iterable<Picto> {
/* /*
* It saves locally a new picto obtained from the PCB * It saves locally a new picto obtained from the PCB
*/ */
public void saveLocalPicto(String url, String exp, int cat, int coord_x, int coord_y, int free_category_coord_x, int free_category_coord_y,String uri_sound,String user_avatar,String associated_person, final iLocalPicto listener) { public void saveLocalPicto(String url, String exp, int cat, int coord_x, int coord_y, int free_category_coord_x, int free_category_coord_y,String uri_sound,String user_avatar, final iLocalPicto listener) {
Picto prev_picto=PCBcontext.getPcbdb().getCurrentUser().has_categories() ? find_picto(cat, coord_x,coord_y) : find_picto(coord_x,coord_y); //¿estamos reemplazanddo un picto que ya existe? Picto prev_picto=PCBcontext.getPcbdb().getCurrentUser().has_categories() ? find_picto(cat, coord_x,coord_y) : find_picto(coord_x,coord_y); //¿estamos reemplazanddo un picto que ya existe?
...@@ -439,7 +439,7 @@ public class Vocabulary implements Iterable<Picto> { ...@@ -439,7 +439,7 @@ public class Vocabulary implements Iterable<Picto> {
int id=PCBcontext.getDevice().getNextLocalPictoID(); int id=PCBcontext.getDevice().getNextLocalPictoID();
try { try {
final Picto picto = new Picto(id, url, exp, cat, coord_x, coord_y, free_category_coord_x, free_category_coord_y,prev_picto!=null ? prev_picto.get_stupicto_id() : Picto.STUPICTO_NULL,uri_sound,user_avatar,associated_person); final Picto picto = new Picto(id, url, exp, cat, coord_x, coord_y, free_category_coord_x, free_category_coord_y,prev_picto!=null ? prev_picto.get_stupicto_id() : Picto.STUPICTO_NULL,uri_sound,user_avatar);
addPicto(picto, ImgDownloader.tsource.local, new ImgDownloader.iImgDownloaderListener() { addPicto(picto, ImgDownloader.tsource.local, new ImgDownloader.iImgDownloaderListener() {
@Override @Override
public void loadComplete() { public void loadComplete() {
......
...@@ -9,6 +9,7 @@ import com.koushikdutta.ion.Response; ...@@ -9,6 +9,7 @@ import com.koushikdutta.ion.Response;
import com.yottacode.net.RestapiWrapper; import com.yottacode.net.RestapiWrapper;
import com.yottacode.pictogram.R; import com.yottacode.pictogram.R;
import com.yottacode.pictogram.action.VocabularyAction; import com.yottacode.pictogram.action.VocabularyAction;
import com.yottacode.pictogram.dao.Device;
import com.yottacode.pictogram.dao.Picto; import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.tools.Img; import com.yottacode.pictogram.tools.Img;
import com.yottacode.pictogram.tools.PCBcontext; import com.yottacode.pictogram.tools.PCBcontext;
...@@ -23,7 +24,7 @@ import java.io.IOException; ...@@ -23,7 +24,7 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
/** /**
...@@ -98,7 +99,66 @@ public class PictoUploader { ...@@ -98,7 +99,66 @@ public class PictoUploader {
return success; return success;
} }
//TODO: Refinar el metodo
private boolean uploadSound(File audioFile) throws UnsupportedEncodingException {
boolean success;
Response<JsonObject> response=null;
String [] path = audioFile.getPath().split("\\.");
String extension = path[1];
if (extension != "mp3")
throw new UnsupportedEncodingException("Extension "+extension+" is not supported. Only mp3 files");
Ion ion = Ion.getDefault(PCBcontext.getContext());
try {
response=ion.with(PCBcontext.getContext())
.load("POST", PCBcontext.getContext().getResources().getString(R.string.server) + "/picto/upload_sound/"+picto.get_stupicto_id())
.setMultipartParameter("filename", "id_del _sonido")
.setMultipartParameter("extension", "mp3")
.setMultipartParameter("owner", Integer.toString(PCBcontext.getPcbdb().getCurrentUser().get_id_sup()))
.setMultipartParameter("folder", "pictoSound")
.setMultipartParameter("token", PCBcontext.getRestapiWrapper().getToken())
.setMultipartFile("file", "audio/mp3", audioFile)
.asJsonObject()
.withResponse().get();
if (response != null && response.getHeaders().code() == 200) {
Log.i(LOG_TAG, "Uploaded image result: " + response.getHeaders() + ":" + response.getResult());
//int img_id=response.getResult().get("id").getAsInt();
//String img_uri=response.getResult().get("uri").getAsString();
//img.set_url(img_uri);
//img.update_id(img_id);
success=true;
} else {
success=false;
Log.i(LOG_TAG, "Uploaded Sound failed ");
if (response != null)
Log.i(LOG_TAG, "Uploaded Sound failed, headers: " + response.getHeaders());
}
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Sound upload error: " + e.getMessage()+ "Code: "+
(response == null ? -1 : response.getHeaders().code()));
success=false;
} catch (ExecutionException e) {
Log.e(LOG_TAG, "Sound upload error: " + e.getMessage()+
(response == null ? -1 : response.getHeaders().code()));
success=false;
} /*catch (IOException e) {
Log.e(Img.class.getCanonicalName(), "Error when decoding "+audioFile.getName());
GUITools.show_alert(PCBcontext.getContext(), R.string.imguserLoadingErrMsg);
success=false;
}*/
// ion.dump();
return success;
}
/** /**
* if a picto was included from the PCB, the translation is uploaded to the server * if a picto was included from the PCB, the translation is uploaded to the server
...@@ -121,6 +181,7 @@ public class PictoUploader { ...@@ -121,6 +181,7 @@ public class PictoUploader {
e.printStackTrace(); e.printStackTrace();
Log.e(LOG_TAG, " Error: " + e.getLocalizedMessage()); Log.e(LOG_TAG, " Error: " + e.getLocalizedMessage());
} }
PCBcontext.getRestapiWrapper().ask(PCBcontext.getPcbdb().getCurrentUser().get_restapi_operation_stu() + "/picto/"+id_picto, params, "post", true, new RestapiWrapper.iRestapiListener() { PCBcontext.getRestapiWrapper().ask(PCBcontext.getPcbdb().getCurrentUser().get_restapi_operation_stu() + "/picto/"+id_picto, params, "post", true, new RestapiWrapper.iRestapiListener() {
@Override @Override
public void preExecute() { public void preExecute() {
...@@ -238,15 +299,26 @@ public class PictoUploader { ...@@ -238,15 +299,26 @@ public class PictoUploader {
(stupicto_id!=Picto.STUPICTO_NULL ? ", stupicto to be deleted:"+stupicto_id+")" : " .New picto")); (stupicto_id!=Picto.STUPICTO_NULL ? ", stupicto to be deleted:"+stupicto_id+")" : " .New picto"));
iPictoUploaderListener listener = new PictoUploaderListener(local_id,elements_to_be_uploaded); iPictoUploaderListener listener = new PictoUploaderListener(local_id,elements_to_be_uploaded);
if (imgUpload_success) { if (imgUpload_success){
if(this.picto.getUriSound() != "" && this.picto.getUriSound() != null ){ //Si el picto tiene audio en local
Log.i("TAG_PRUEBAS","Hay uri: "+this.picto.getUriSound()+" -Procede a subir archivo");
File file = new File(picto.getUriSound()); //Obtengo el fichero de audio local
boolean soundUpload_success = uploadSound(file); //Llamo a la subida
if(soundUpload_success) {
Log.i("TAG_PRUEBAS","Se sube sonido hay EXITO");
}else {
GUITools.show_alert(PCBcontext.getActivityContext(),Integer.parseInt(R.string.upload_error+"Audio"), PictoUploader.this.picto.get_translation());
}
}
if (stupicto_id!=Picto.STUPICTO_NULL) { if (stupicto_id!=Picto.STUPICTO_NULL) {
Log.i(LOG_TAG, "Remote Picto to be deleted:"+this.picto.get_translation()+"("+stupicto_id+")"); Log.i(LOG_TAG, "Remote Picto to be deleted:"+this.picto.get_translation()+"("+stupicto_id+")");
deletePicto(stupicto_id,listener); deletePicto(stupicto_id,listener);
} else } else {
uploadTranslation(picto.get_id(), listener); uploadTranslation(picto.get_id(), listener);
} }
else { }else{
GUITools.show_alert(PCBcontext.getActivityContext(), R.string.upload_error, PictoUploader.this.picto.get_translation()); GUITools.show_alert(PCBcontext.getActivityContext(), Integer.parseInt(R.string.upload_error+"Imagen"), PictoUploader.this.picto.get_translation());
} }
} }
......
...@@ -1155,18 +1155,18 @@ protected void showOnlyTape(boolean onlyTape) { ...@@ -1155,18 +1155,18 @@ protected void showOnlyTape(boolean onlyTape) {
int freeRow = edit ? data.getExtras().getInt(Picto.JSON_ATTTRS.FREE_ROW) : getIntent().getIntExtra(Picto.JSON_ATTTRS.FREE_ROW, -1); int freeRow = edit ? data.getExtras().getInt(Picto.JSON_ATTTRS.FREE_ROW) : getIntent().getIntExtra(Picto.JSON_ATTTRS.FREE_ROW, -1);
int freeColumn = edit ? data.getExtras().getInt(Picto.JSON_ATTTRS.FREE_COLUMN) : getIntent().getIntExtra(Picto.JSON_ATTTRS.FREE_COLUMN, -1); int freeColumn = edit ? data.getExtras().getInt(Picto.JSON_ATTTRS.FREE_COLUMN) : getIntent().getIntExtra(Picto.JSON_ATTTRS.FREE_COLUMN, -1);
String uri_sound = edit ? data.getExtras().getString(Picto.JSON_ATTTRS.URI_SOUND) : getIntent().getStringExtra(Picto.JSON_ATTTRS.URI_SOUND); String uri_sound = data.getExtras().getString(Picto.JSON_ATTTRS.URI_SOUND);
String associated_person = edit ? data.getExtras().getString(Picto.JSON_ATTTRS.ASSOCIATED_PERSON) : getIntent().getStringExtra(Picto.JSON_ATTTRS.ASSOCIATED_PERSON); String user_avatar = data.getExtras().getString(Picto.JSON_ATTTRS.USER_AVATAR);
int cat = edit ? data.getIntExtra(Picto.JSON_ATTTRS.CATEGORY, -1) : getIntent().getIntExtra(Picto.JSON_ATTTRS.CATEGORY, -1); int cat = edit ? data.getIntExtra(Picto.JSON_ATTTRS.CATEGORY, -1) : getIntent().getIntExtra(Picto.JSON_ATTTRS.CATEGORY, -1);
String path = data.getExtras().getString(PictoMenu.PATH); String path = data.getExtras().getString(PictoMenu.PATH);
String legend = data.getExtras().getString(Picto.JSON_ATTTRS.EXPRESSION); String legend = data.getExtras().getString(Picto.JSON_ATTTRS.EXPRESSION);
Log.i(EditPictoActivity.DEBUG_MESSAGE,"Antes de chooseText...DATOS--> ASS_PERSON: "+associated_person+"..URI_SOUND: "+uri_sound+"..PATH_IMAGE: "+path+"..EXPRESION: "+legend); Log.i(EditPictoActivity.DEBUG_MESSAGE,"Antes de chooseText...DATOS--> ASS_PERSON: "+user_avatar+"..URI_SOUND: "+uri_sound+"..PATH_IMAGE: "+path+"..EXPRESION: "+legend);
//TODO: COGER URI DEL SONIDO,EL USER AVATAR Y LA PERSONA ASOCIADA AL PICTO //TODO: COGER URI DEL SONIDO,EL USER AVATAR Y LA PERSONA ASOCIADA AL PICTO
chooseTextAndSavePicto(path, row, col, freeRow, freeColumn, cat, legend, uri_sound, null, associated_person); chooseTextAndSavePicto(path, row, col, freeRow, freeColumn, cat, legend, uri_sound,user_avatar);
refresh(); refresh();
} }
break; break;
...@@ -1178,7 +1178,7 @@ protected void showOnlyTape(boolean onlyTape) { ...@@ -1178,7 +1178,7 @@ protected void showOnlyTape(boolean onlyTape) {
* función para la edición de un texto asociado a una nueva imagen y guardar el nuevo picto * función para la edición de un texto asociado a una nueva imagen y guardar el nuevo picto
*/ */
public void chooseTextAndSavePicto(final String selectedImagePath, final int row, final int col, final int freeRow, final int freeColumn, public void chooseTextAndSavePicto(final String selectedImagePath, final int row, final int col, final int freeRow, final int freeColumn,
final int category, final String legend,final String uri_sound,final String user_avatar, String associated_person) { final int category, final String legend,final String uri_sound,final String user_avatar) {
// Set up the buttons // Set up the buttons
int cat = category != -1 ? category : Picto.NO_CATEGORY; int cat = category != -1 ? category : Picto.NO_CATEGORY;
...@@ -1194,7 +1194,6 @@ protected void showOnlyTape(boolean onlyTape) { ...@@ -1194,7 +1194,6 @@ protected void showOnlyTape(boolean onlyTape) {
freeColumn, freeColumn,
uri_sound, uri_sound,
user_avatar, user_avatar,
associated_person,
new iLocalPicto() { new iLocalPicto() {
@Override @Override
public void saved(Picto localPicto) { public void saved(Picto localPicto) {
......
...@@ -57,7 +57,9 @@ import java.io.FileOutputStream; ...@@ -57,7 +57,9 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.Vector;
import pl.droidsonroids.gif.GifTextView; import pl.droidsonroids.gif.GifTextView;
import static java.lang.Thread.sleep; import static java.lang.Thread.sleep;
...@@ -233,27 +235,39 @@ public class EditPictoActivity extends Activity { ...@@ -233,27 +235,39 @@ public class EditPictoActivity extends Activity {
ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION); ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION);
//Editar la lista desplegable de supervisores asociados //Editar la lista desplegable de supervisores asociados
mDrawerList = (ListView)findViewById(R.id.navList); mDrawerList = (ListView)findViewById(R.id.navList);
/**Obtener la lista de supervisores y aplicarle formato*/ /**Obtener la lista de supervisores y aplicarle formato*/
Log.i(DEBUG_MESSAGE,"Usuario: "+ PCBcontext.getPcbdb().getCurrentUser().get_name_stu()); Log.i(DEBUG_MESSAGE,"Usuario: "+ PCBcontext.getPcbdb().getCurrentUser().get_name_stu());
String supervisors = PCBcontext.getPcbdb().getCurrentUser().get_Supervisors(); ArrayList<String> supervisoresAdapter = new ArrayList<>();
Log.i(DEBUG_MESSAGE,"Supervisores: "+ supervisors); Vector<User> supervisores = null;
ArrayList<String> supervisores = new ArrayList<>(); try {
supervisores = PCBcontext.getDevice().recoverSupervisors(PCBcontext.getPcbdb().getCurrentUser().get_id_stu());
} catch (JSONException e) {
e.printStackTrace();
}
if (supervisores != null){
for(User supervisor: supervisores){
supervisoresAdapter.add(supervisor.get_name_sup()+", "+supervisor.get_surname_sup()+ "\n" +supervisor.get_email_sup() );
}
}
//String supervisors = PCBcontext.getPcbdb().getCurrentUser().get_Supervisors();
//Log.i(DEBUG_MESSAGE,"Supervisores: "+ supervisors);
//ArrayList<String> supervisores = new ArrayList<>();
if(supervisors != null) { /*if(supervisors != null) {
String[] separated = supervisors.split(";"); String[] separated = supervisors.split(";");
for (String supervisor : separated) { for (String supervisor : separated) {
String[] detalles = supervisor.split(","); String[] detalles = supervisor.split(",");
supervisores.add(detalles[0] + "\n" + detalles[1]); supervisores.add(detalles[0] + "\n" + detalles[1]);
} }
}else }else
Log.i(DEBUG_MESSAGE,"No tiene supervisores..."); Log.i(DEBUG_MESSAGE,"No tiene supervisores...");*/
mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, supervisores); mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, supervisoresAdapter);
mDrawerList.setAdapter(mAdapter); mDrawerList.setAdapter(mAdapter);
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout); mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
...@@ -304,7 +318,7 @@ public class EditPictoActivity extends Activity { ...@@ -304,7 +318,7 @@ public class EditPictoActivity extends Activity {
if(!fileAudio.exists()){ if(!fileAudio.exists()){
fileAudio.mkdirs(); fileAudio.mkdirs();
} }
previewAudioPath = dirAudioPath+File.separator+"test.3gp"; previewAudioPath = dirAudioPath+File.separator+"test.mp3";
// Initialize Views. // Initialize Views.
...@@ -352,7 +366,7 @@ public class EditPictoActivity extends Activity { ...@@ -352,7 +366,7 @@ public class EditPictoActivity extends Activity {
if(editar){ if(editar){
p = PCBcontext.getVocabulary().get_picto(getIntent().getExtras().getInt(Picto.JSON_ATTTRS.CATEGORY),getIntent().getExtras().getInt(PictoMenu.ID_PICTO_IMAGE)); p = PCBcontext.getVocabulary().get_picto(getIntent().getExtras().getInt(Picto.JSON_ATTTRS.CATEGORY),getIntent().getExtras().getInt(PictoMenu.ID_PICTO_IMAGE));
legend.setText(p.get_translation()); legend.setText(p.get_translation());
supAsociado.setText(p.get_associated_person()); supAsociado.setText(p.get_user_avatar());
} }
legend.setHorizontallyScrolling(false); legend.setHorizontallyScrolling(false);
legend.setMaxLines(1); legend.setMaxLines(1);
...@@ -360,7 +374,7 @@ public class EditPictoActivity extends Activity { ...@@ -360,7 +374,7 @@ public class EditPictoActivity extends Activity {
//Obtener imagen del intent //Obtener imagen del intent
byte[] byteArray = getIntent().getByteArrayExtra(PictoMenu.IMAGE_PICTO); byte[] byteArray = getIntent().getByteArrayExtra(PictoMenu.IMAGE_PICTO);
Bitmap imagePicto = scale_image(BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length)); final Bitmap imagePicto = scale_image(BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length));
cropImageView.setAspectRatio(editar ? imagePicto.getWidth() : 4,editar ? imagePicto.getHeight() : 3); //Si es editar un picto la ventana de recorte mantiene el tamaño de la imagen, sino 4:3 cropImageView.setAspectRatio(editar ? imagePicto.getWidth() : 4,editar ? imagePicto.getHeight() : 3); //Si es editar un picto la ventana de recorte mantiene el tamaño de la imagen, sino 4:3
cropImageView.setImageBitmap(imagePicto); cropImageView.setImageBitmap(imagePicto);
...@@ -447,8 +461,8 @@ public class EditPictoActivity extends Activity { ...@@ -447,8 +461,8 @@ public class EditPictoActivity extends Activity {
if (file.exists()) { if (file.exists()) {
File from = new File(previewAudioPath); File from = new File(previewAudioPath);
File to = new File(editar ? dirAudioPath + File.separator + legend.getText().toString() + "_" + id_pic + "_audio.3gp" : File to = new File(editar ? dirAudioPath + File.separator + legend.getText().toString() + "_" + id_pic + "_audio.mp3" :
dirAudioPath + File.separator + legend.getText().toString() + "_new_" + pathNumber + "_audio.3gp"); dirAudioPath + File.separator + legend.getText().toString() + "_new_" + pathNumber + "_audio.mp3");
if (from.exists()){ if (from.exists()){
from.renameTo(to); from.renameTo(to);
Log.i(DEBUG_MESSAGE,to.getPath().toString()); Log.i(DEBUG_MESSAGE,to.getPath().toString());
...@@ -457,13 +471,16 @@ public class EditPictoActivity extends Activity { ...@@ -457,13 +471,16 @@ public class EditPictoActivity extends Activity {
} }
} }
Intent intent = getIntent(); //Mandar a pictogram activity el path y el texto de la imagen Intent intent = getIntent(); //Mandar a pictogram activity el path y el texto de la imagen
intent.putExtra(PictoMenu.IS_EDIT, editar); //Para saber despues si estas editando o añadiendo nuevo y coger los datos de intent o de data en OnActivityResult intent.putExtra(PictoMenu.IS_EDIT, editar); //Para saber despues si estas editando o añadiendo nuevo y coger los datos de intent o de data en OnActivityResult
intent.putExtra(PictoMenu.PATH, filepath); //Mandar Path imagen intent.putExtra(PictoMenu.PATH, filepath); //Mandar Path imagen
intent.putExtra(Picto.JSON_ATTTRS.URI_SOUND,audioPath); //Mandar el path del audio intent.putExtra(Picto.JSON_ATTTRS.URI_SOUND,audioPath); //Mandar el path del audio
intent.putExtra(Picto.JSON_ATTTRS.EXPRESSION, legend.getText().toString()); //Mandar expresion nueva intent.putExtra(Picto.JSON_ATTTRS.EXPRESSION, legend.getText().toString()); //Mandar expresion nueva
intent.putExtra(Picto.JSON_ATTTRS.CATEGORY, getIntent().getIntExtra(Picto.JSON_ATTTRS.CATEGORY, -1)); intent.putExtra(Picto.JSON_ATTTRS.CATEGORY, getIntent().getIntExtra(Picto.JSON_ATTTRS.CATEGORY, -1));
intent.putExtra(Picto.JSON_ATTTRS.ASSOCIATED_PERSON, supAsociado.getText()); intent.putExtra(Picto.JSON_ATTTRS.USER_AVATAR, supAsociado.getText());
//p.setUriSound(audioPath);
setResult(RESULT_OK, intent); setResult(RESULT_OK, intent);
...@@ -613,7 +630,7 @@ public class EditPictoActivity extends Activity { ...@@ -613,7 +630,7 @@ public class EditPictoActivity extends Activity {
private void startRecording() { private void startRecording() {
mRecorder = new MediaRecorder(); mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile(previewAudioPath); mRecorder.setOutputFile(previewAudioPath);
......
...@@ -203,7 +203,7 @@ public class StudentFragmentGrid extends Fragment{ ...@@ -203,7 +203,7 @@ public class StudentFragmentGrid extends Fragment{
downloader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imgs); downloader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, imgs);
} }
private void download_supervisors(int stu_id) { private void download_supervisors(final int stu_id) {
String token = getActivity().getIntent().getExtras().getString("token"); String token = getActivity().getIntent().getExtras().getString("token");
RestapiWrapper wrapper = PCBcontext.getRestapiWrapper(); RestapiWrapper wrapper = PCBcontext.getRestapiWrapper();
...@@ -225,17 +225,20 @@ public class StudentFragmentGrid extends Fragment{ ...@@ -225,17 +225,20 @@ public class StudentFragmentGrid extends Fragment{
} }
@Override @Override
public void result(JSONArray supervisors) { public void result(JSONArray supervisors) {
String supervisorsFormat = "";
//String supervisorsFormat = "";
for (int i=0;i<supervisors.length();i++) { for (int i=0;i<supervisors.length();i++) {
JSONObject supervisor; JSONObject supervisor;
try { try {
supervisor = supervisors.getJSONObject(i); supervisor = supervisors.getJSONObject(i);
supervisorsFormat += supervisor.get("name") +" " + supervisor.get("surname") + "," + supervisor.get("email") + ";"; //PCBcontext.getDevice().insertUser(new User(stu_id,null,null,null,null,null,null,null,null,(int) supervisor.get("id"),supervisor.get("email").toString(),null,supervisor.get("name").toString(),
// supervisor.get("surname").toString(), supervisor.get("pic").toString(),supervisor.get("gender").toString(),supervisor.get("lang").toString(),supervisor.get("ttsEngine").toString(),supervisor.get("office").toString()));
//supervisorsFormat += supervisor.get("name") +" " + supervisor.get("surname") + "," + supervisor.get("email") + ";";
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
PCBcontext.getPcbdb().getCurrentUser().set_Supervisors(supervisorsFormat); //PCBcontext.getPcbdb().getCurrentUser().set_Supervisors(supervisorsFormat);
} }
@Override @Override
......
...@@ -62,13 +62,6 @@ ...@@ -62,13 +62,6 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
...@@ -76,6 +69,13 @@ ...@@ -76,6 +69,13 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
...@@ -121,17 +121,5 @@ ...@@ -121,17 +121,5 @@
<orderEntry type="library" exported="" name="ion-2.1.9" level="project" /> <orderEntry type="library" exported="" name="ion-2.1.9" level="project" />
<orderEntry type="library" exported="" name="play-services-ads-lite-9.2.1" level="project" /> <orderEntry type="library" exported="" name="play-services-ads-lite-9.2.1" level="project" />
<orderEntry type="module" module-name="commonlibrary" exported="" /> <orderEntry type="module" module-name="commonlibrary" exported="" />
<orderEntry type="library" exported="" name="android-android-24" level="project" />
<orderEntry type="library" exported="" name="okhttp-ws-2.3.0" level="project" />
<orderEntry type="library" exported="" name="socket.io-client-0.5.0" level="project" />
<orderEntry type="library" exported="" name="okhttp-2.3.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.0" level="project" />
<orderEntry type="library" exported="" name="okio-1.3.0" level="project" />
<orderEntry type="library" exported="" name="gson-2.3" level="project" />
<orderEntry type="library" exported="" name="engine.io-client-0.5.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-21.0.3" level="project" />
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
<orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
<orderEntry type="library" exported="" scope="TEST" name="json-20090211" level="project" />
</component> </component>
</module> </module>
\ No newline at end of file
Estos son scripts de automatización para las siguientes tareas en el servidor:
- Renovación de certificados
- Backup automático
## Renovación de certificados
Ver [letsencrypt.md](http://gitlab.ujaen.es/yotta/pictogram/blob/master/sails/src/config/ssl/letsencrypt.md)
## Backup automático
### Dependencias:
- Se está usando el script [ec2-automate-backup](https://github.com/colinbjohnson/aws-missing-tools/tree/master/ec2-automate-backup).
- Es necesario, para su uso, instalar [AWS-CLI](http://docs.aws.amazon.com/cli/latest/userguide/installing.html)
### Configuración:
Desde AWS IAM, debemos crear un usuario dentro de un grupo. Los permisos son los siguientes:
```
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1489386668000",
"Effect": "Allow",
"Action": [
"ec2:CreateSnapshot",
"ec2:CreateTags",
"ec2:DeleteSnapshot",
"ec2:DeleteTags",
"ec2:DescribeSnapshotAttribute",
"ec2:DescribeSnapshots",
"ec2:DescribeVolumes",
"ec2:ModifySnapshotAttribute"
],
"Resource": "*"
}
]
}
```
El comando cron que hay de muestra en `crontab` se encargará de hacer una copia cada día, para los últimos 30 días.
\ No newline at end of file
#!/bin/bash
# This script is to be run in a remote machine with access to pre
DUMPFILE=/home/ubuntu/backup/`date +%d`-mysqldump.sql.gz
ssh pre "nice mysqldump -u root -p'r00...Tt' pictodb | gzip > $DUMPFILE"
scp pre:$DUMPFILE /home/amontejo/backup
#!/bin/bash -
# export PATH=/bin is required for cut, date, grep
# export PATH=/usr/bin is required for AWS Command Line Interface tools
export PATH=/bin:/usr/bin:/home/ubuntu/.local/bin
# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY needed for AWS CLI tools
export AWS_ACCESS_KEY_ID=AKIAJJZNE3V5QMKSMU6A
export AWS_SECRET_ACCESS_KEY=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
# AWS_CONFIG_FILE required for AWS Command Line Interface tools (f.e. ".aws")
export AWS_CONFIG_FILE=/root/.aws/config
@reboot /home/ubuntu/pictogram/sails/bootstrap.sh
# Let's encrypt certs autorenew
@monthly /home/ubuntu/cron/renewcerts.sh
# AWS Volume backups
@daily /home/ubuntu/cron/aws-missing-tools/ec2-automate-backup/ec2-automate-backup.sh -c /home/ubuntu/cron/cron-primer.sh -v vol-0cd5c496 -k 30 -p -u -r "eu-central-1"
#!/bin/bash
# Renew certs
/home/ubuntu/letsencrypt/letsencrypt-auto --config /etc/letsencrypt/cli.ini -d login.pictogramweb.com -d api.pictogramweb.com -d app.pictogramweb.com -d pre.yottacode.com -d pictogram.yottacode.com -d apk.pictogramweb.com certonly
# Reload Sails
(cd /home/ubuntu/pictogram/sails/src; /usr/bin/forever stopall; /usr/bin/forever start app.js)
...@@ -309,6 +309,7 @@ CREATE TABLE IF NOT EXISTS `license` ( ...@@ -309,6 +309,7 @@ CREATE TABLE IF NOT EXISTS `license` (
`activation_ts` datetime NULL, `activation_ts` datetime NULL,
`expiration_ts` datetime NULL, `expiration_ts` datetime NULL,
`duration` int(11) DEFAULT 0, `duration` int(11) DEFAULT 0,
`creator` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `number` (`number`), UNIQUE KEY `number` (`number`),
KEY `id_stu` (`id_stu`) KEY `id_stu` (`id_stu`)
......
...@@ -43,6 +43,9 @@ Changes to be performed manually in servers to upgrade ...@@ -43,6 +43,9 @@ Changes to be performed manually in servers to upgrade
(already done in dev & pre) (already done in dev & pre)
- add new column to license:
`alter table license add column creator varchar(40) DEFAULT NULL;`
- add arasaac to source table - add arasaac to source table
`INSERT INTO `source` (`id`, `name`, `description`) VALUES (3, 'Arasaac', 'Arasaac pictograms collection');` `INSERT INTO `source` (`id`, `name`, `description`) VALUES (3, 'Arasaac', 'Arasaac pictograms collection');`
- alter table supervisor add arasaac license: - alter table supervisor add arasaac license:
......
...@@ -2,39 +2,44 @@ ...@@ -2,39 +2,44 @@
* AdminController which manages the administration login and login * AdminController which manages the administration login and login
* @type {Object} * @type {Object}
*/ */
const bcrypt = require('bcrypt-nodejs');
module.exports = { module.exports = {
// @TODO ¿?¿?
login: function (req, res) { login: function (req, res) {
var bcrypt = require('bcrypt-nodejs');
var email = req.body.email; var email = req.body.email;
var password = req.body.password; var password = req.body.password;
// no credentials // no credentials
if (!email || !password) if (!email || !password)
return res.json(401, {error: 'No credentials sent'}); return res.badRequest('No credentials sent');
// Check email // Check email
if (email != sails.config.pictogram.admin.email) var admin = sails.config.pictogram.admins.find((a) => a.email == email);
return res.json(401, {error: 'User not found'}); if (typeof admin == 'undefined')
return res.badRequest('User not found');
// if found, check password in encrypted form
bcrypt.compare(password, sails.config.pictogram.admin.password, function (err, match) { // if found, check password in encrypted form
if (err) bcrypt.compare(password, admin.password, function (err, match) {
return res.json(500, { error: 'Server error' }); if (err)
if (!match) // password do not match return res.serverError('Server error' + err);
return res.json(401, { error: 'Invalid password' }); if (!match) // password do not match
return res.unauthorized('Invalid password');
// credentials are valid, return token with max life span
return res.json(200, { // credentials are valid, return token with max life span
token: sailsTokenAuth.issueToken({'isAdmin': true}, sails.config.jwt.expiresInMinutes)}); var returned_admin = (JSON.parse(JSON.stringify(admin)));
delete returned_admin.password;
return res.ok({
token: sailsTokenAuth.issueToken({'isAdmin': true, 'email': email}, sails.config.jwt.expiresInMinutes),
user: returned_admin
}); });
});
}, },
// @TODO 357
logout: function (req, res) { logout: function (req, res) {
delete req.token; delete req.token;
res.json(200, {notice: 'Session closed'}); res.ok('Session closed');
} }
}; };
...@@ -8,6 +8,24 @@ ...@@ -8,6 +8,24 @@
module.exports = { module.exports = {
/** /**
* Get all the licenses for the given creator
* @param {request} req
* {
* email (creator email)
* }
* @param {response} res
* [list of licenses]
*/
getByEmail: function (req, res) {
if (!req.params.email)
return res.badRequest("No email provided");
License.find({creator: req.params.email})
.then((l) => res.ok(l))
.catch((e) => res.serverError(e));
},
/**
* Create a new Instruction, which is associated to the given method * Create a new Instruction, which is associated to the given method
* @param {request} req * @param {request} req
* { * {
...@@ -67,7 +85,8 @@ module.exports = { ...@@ -67,7 +85,8 @@ module.exports = {
get_new_random_license(function (license) { get_new_random_license(function (license) {
License.create({ License.create({
number: license, number: license,
duration: params.duration duration: params.duration,
creator: req.token.email
}) })
.then((l) => { .then((l) => {
if (l) { if (l) {
......
...@@ -58,7 +58,7 @@ module.exports = { ...@@ -58,7 +58,7 @@ module.exports = {
Office.findOne({ id: id }).populate('admin').then(function (office) { Office.findOne({ id: id }).populate('admin').then(function (office) {
if (office) { if (office) {
res.ok({logo_url: office.logo_url, name: office.name}); res.ok({logo_url: office.logo_url || '/app/img/logo_pictogram.png', name: office.name});
} else { } else {
res.notFound(); res.notFound();
} }
......
...@@ -442,7 +442,7 @@ module.exports = { ...@@ -442,7 +442,7 @@ module.exports = {
// update supervisor office if it is linked as therapist // update supervisor office if it is linked as therapist
Supervisor.findOne({id: req.param('id_sup')}) Supervisor.findOne({id: req.param('id_sup')})
.then((sup) => { .then((sup) => {
if (sup) { if (sup && !sup.office) {
Student.findOne({id: req.param('id_stu')}) Student.findOne({id: req.param('id_stu')})
.then((stu) => { .then((stu) => {
if (stu) { if (stu) {
...@@ -1168,7 +1168,8 @@ module.exports = { ...@@ -1168,7 +1168,8 @@ module.exports = {
fs.unlinkSync(path.join(newAvatarDirectory, student.pic)); fs.unlinkSync(path.join(newAvatarDirectory, student.pic));
} }
student.pic = newAvatarFileName; student.pic = newAvatarFileName;
delete student.password;
student.save(function (updateStudentError) { student.save(function (updateStudentError) {
if (updateStudentError) { if (updateStudentError) {
throw updateStudentError; throw updateStudentError;
......
...@@ -48,6 +48,10 @@ module.exports = { ...@@ -48,6 +48,10 @@ module.exports = {
size: 16, size: 16,
unique: true unique: true
}, },
creator: {
columnName: "creator",
type: "string",
},
toJSON: function () { toJSON: function () {
var l = this.toObject(); var l = this.toObject();
delete l.id; delete l.id;
......
...@@ -87,7 +87,11 @@ module.exports = { ...@@ -87,7 +87,11 @@ module.exports = {
students: { students: {
collection: "Student", collection: "Student",
via: 'office' via: 'office'
} },
toJSON: function() {
if (!attrs.logoUrl)
attrs.logoUrl = '/app/img/logo_pictogram.png';
}
}, },
beforeCreate: function (attrs, next) { beforeCreate: function (attrs, next) {
......
...@@ -2,7 +2,7 @@ var mailerService = require('sails-service-mailer'); ...@@ -2,7 +2,7 @@ var mailerService = require('sails-service-mailer');
module.exports.mailer = function() { module.exports.mailer = function() {
return mailerService('sendmail', { return mailerService('sendmail', {
from: 'no-reply@yottacode.com', from: 'no-reply@pictogramweb.com',
subject: sails.__('notification_from_pictogram'), subject: sails.__('notification_from_pictogram'),
provider: { provider: {
path: '/usr/sbin/sendmail' path: '/usr/sbin/sendmail'
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"action-tryend": "Try end", "action-tryend": "Try end",
"action-tryinit": "Try begin", "action-tryinit": "Try begin",
"action-unshow": "Writing mode", "action-unshow": "Writing mode",
"activation": "Activation",
"add": "Add", "add": "Add",
"add_expression": "Add expression", "add_expression": "Add expression",
"add_instruction": "Add instruction", "add_instruction": "Add instruction",
...@@ -77,6 +78,7 @@ ...@@ -77,6 +78,7 @@
"country_office_requested": "Country for office/center is mandatory", "country_office_requested": "Country for office/center is mandatory",
"create_account": "Create account", "create_account": "Create account",
"create_an_account": "Create an account", "create_an_account": "Create an account",
"creation": "Creation",
"credentials": "Credentials", "credentials": "Credentials",
"crop_image": "Crop image", "crop_image": "Crop image",
"data_no_saved": "Data can't be saved", "data_no_saved": "Data can't be saved",
...@@ -178,6 +180,7 @@ ...@@ -178,6 +180,7 @@
"legend_normal":"Normal legend", "legend_normal":"Normal legend",
"legend_full":"Only legend", "legend_full":"Only legend",
"legend_size": "Legend size", "legend_size": "Legend size",
"license": "License",
"licenses": "Licenses", "licenses": "Licenses",
"license_already_activated": "License already activated", "license_already_activated": "License already activated",
"license_created": "License created", "license_created": "License created",
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"action-tryend": "Fin de ensayo", "action-tryend": "Fin de ensayo",
"action-tryinit": "Inicio de ensayo", "action-tryinit": "Inicio de ensayo",
"action-unshow": "Modo escritura", "action-unshow": "Modo escritura",
"activation": "Activación",
"add": "Añadir", "add": "Añadir",
"add_expression": "Añadir expresión", "add_expression": "Añadir expresión",
"add_instruction": "Añadir instrucción", "add_instruction": "Añadir instrucción",
...@@ -77,6 +78,7 @@ ...@@ -77,6 +78,7 @@
"country_office_requested": "Debe especificar el país del gabinete/centro", "country_office_requested": "Debe especificar el país del gabinete/centro",
"create_account": "Crear cuenta", "create_account": "Crear cuenta",
"create_an_account": "Crear una cuenta", "create_an_account": "Crear una cuenta",
"creation": "Creación",
"credentials": "Credenciales", "credentials": "Credenciales",
"crop_image": "Recortar imagen", "crop_image": "Recortar imagen",
"data_no_saved": "Los datos no se han podido guardar", "data_no_saved": "Los datos no se han podido guardar",
...@@ -178,6 +180,7 @@ ...@@ -178,6 +180,7 @@
"legend_full":"Sólo leyenda", "legend_full":"Sólo leyenda",
"legend_apply_all":"Aplicar a todos los pictogramas", "legend_apply_all":"Aplicar a todos los pictogramas",
"legend_size": "Tamaño de la leyenda", "legend_size": "Tamaño de la leyenda",
"license": "Licencia",
"licenses": "Licencias", "licenses": "Licencias",
"licenses_left": "{{number}} licencias disponibles", "licenses_left": "{{number}} licencias disponibles",
"license_already_activated": "Licencia ya activada previamente", "license_already_activated": "Licencia ya activada previamente",
......
/vagrant/arasaac
\ No newline at end of file
/* global angular */
angular.module('dashboardConfig', []).constant('config', {
backend: 'https://' + window.location.host,
});
...@@ -3,11 +3,10 @@ ...@@ -3,11 +3,10 @@
//------------------- //-------------------
// Admin Controller // Admin Controller
//------------------- //-------------------
dashboardControllers.controller('AdminCtrl', function AdminCtrl($scope) { dashboardControllers.controller('AdminCtrl', function AdminCtrl($scope, $window) {
// The last parameter, config, is injected from config.js (defined in dashboardConfig module) // The last parameter, config, is injected from config.js (defined in dashboardConfig module)
// Assign values this way (like an object) to ensure it's the parent scope $scope.user.name ='Super'; // Assign values this way (like an object) to ensure it's the parent scope $scope.user.name ='Super';
$scope.user.surname = 'Admin'; $scope.user = JSON.parse($window.sessionStorage.user);
$scope.user.pic ='img/arturo.jpg';
}); });
\ No newline at end of file
...@@ -10,9 +10,20 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl( ...@@ -10,9 +10,20 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl(
$scope.showmessagesupervisor = false; $scope.showmessagesupervisor = false;
$scope.new_numbers = []; $scope.new_numbers = [];
$scope.formdatalicense = { $scope.formdatalicense = {
duration: 1, duration: 3,
repeat: 1 repeat: 1
}; };
$scope.licenses = [];
// Get all licenses for the user
$http
.get(config.backend + '/license/' + $scope.user.email)
.success(function(data, status, headers, config) {
$scope.licenses = data;
})
.error(function(data, status, headers, config) {
ngToast.danger({content: $translate.instant('error_general')});
});
// This generates a new license and registers it in the database // This generates a new license and registers it in the database
$scope.create_licenses = function(supervisor) { $scope.create_licenses = function(supervisor) {
...@@ -21,14 +32,15 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl( ...@@ -21,14 +32,15 @@ dashboardControllers.controller('AdminLicensesCtrl', function AdminLicensesCtrl(
$http $http
.post(config.backend+'/license', $scope.formdatalicense) .post(config.backend+'/license', $scope.formdatalicense)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
$scope.new_numbers.push(data.number.substr(0,4) + /*$scope.new_numbers.push(data.number.substr(0,4) +
"-" + data.number.substr(4,4) + "-" + data.number.substr(4,4) +
"-" + data.number.substr(8,4) + "-" + data.number.substr(8,4) +
"-" + data.number.substr(12,4)); "-" + data.number.substr(12,4));
*/
$scope.new_numbers.push(data.number);
}) })
.error(function(data, status, headers, config) { .error(function(data, status, headers, config) {
ngToast.danger({content: $translate.instant('error_general')}); ngToast.danger({content: $translate.instant('error_general')});
console.log("Error from API: " + data.error);
}); });
} }
$scope.duration_registered = $scope.formdatalicense.duration; $scope.duration_registered = $scope.formdatalicense.duration;
......
...@@ -15,8 +15,9 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope ...@@ -15,8 +15,9 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope
$http $http
.post(config.backend+'/admin/login', $scope.credentials) .post(config.backend+'/admin/login', $scope.credentials)
.success(function(data, status, headers, config) { .success(function(data, status, headers, config) {
// Save token and user data y sessionStorage // Save token, user data in sessionStorage
$window.sessionStorage.token = data.token; $window.sessionStorage.token = data.token;
$window.sessionStorage.user = JSON.stringify(data.user);
// Redirect to admin panel // Redirect to admin panel
$location.path('/admin/licenses'); $location.path('/admin/licenses');
...@@ -28,6 +29,10 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope ...@@ -28,6 +29,10 @@ dashboardControllers.controller('LoginAdminCtrl', function LoginAdminCtrl($scope
.error(function(data, status, headers, config) { .error(function(data, status, headers, config) {
// Delete token if user fails to login // Delete token if user fails to login
delete $window.sessionStorage.token; delete $window.sessionStorage.token;
delete $window.sessionStorage.user;
// Redirect to admin panel
$location.path('/admin/login');
$translate('login_fail').then(function(translation) { $translate('login_fail').then(function(translation) {
ngToast.danger({ content: translation }); ngToast.danger({ content: translation });
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<a class="navbar-brand" href="/app/#/admin"><img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" style="height: 70px;" /></a> <a class="navbar-brand" href="/app/#/admin"><img src="img/logo_pictogram.png" alt="Pictogram" title="Pictogram" style="height: 70px;" /></a>
</div> </div>
<!-- Agrupar los enlaces de navegación, los formularios y cualquier otro elemento que se pueda ocultar al minimizar la barra --> <!-- Agrupar los enlaces de navegación, los formularios y cualquier otro elemento que se pueda ocultar al minimizar la barra -->
<div class="collapse navbar-collapse navbar-ex6-collapse"> <div class="collapse navbar-collapse navbar-ex6-collapse">
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
</div> </div>
<div class="nav navbar-nav navbar-right navbar-text"> <div class="nav navbar-nav navbar-right navbar-text">
<h4 class="text-right">{{user.getFullName()}}</h4> <h4 class="text-right">{{ user.email }}</h4>
<p class="text-right"> <p class="text-right">
<!-- Botón salir --> <!-- Botón salir -->
<a ng-click="logout()" class="btn btn-default btn-sm" role="button"> <a ng-click="logout()" class="btn btn-default btn-sm" role="button">
<span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> {{ 'logout' | translate }} <span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> {{ 'logout' | translate }}
...@@ -33,4 +33,4 @@ ...@@ -33,4 +33,4 @@
</div> </div>
</div> </div>
</nav> </nav>
\ No newline at end of file
...@@ -2,13 +2,10 @@ ...@@ -2,13 +2,10 @@
<div class="row"> <div class="row">
<div class="col-md-2">
</div>
<div class="col-md-4">
<h3 translate>licenses</h3> <h3 translate>licenses</h3>
<div class="col-md-5">
<form role="form" ng-submit="create_licenses()"> <form role="form" ng-submit="create_licenses()">
<div class="form-group"> <div class="form-group">
...@@ -27,18 +24,40 @@ ...@@ -27,18 +24,40 @@
</form> </form>
<div ng-show="new_numbers.length > 0" class="alert alert-info">
<p>{{ 'licenses_created' | translate }}:</p><p>&nbsp;</p>
<div ng-repeat="number in new_numbers track by $index">
<p> <strong>{{ number }}</strong></p>
</div>
<p>{{ 'duration_in_months' | translate }}: {{ duration_registered }}</p>
</div> </div>
<div class="col-md-4">
<div ng-show="new_numbers.length > 0" class="alert alert-info">
<p>{{ 'licenses_created' | translate }}:</p><p>&nbsp;</p>
<div ng-repeat="number in new_numbers track by $index">
<p> <strong>{{ number }}</strong></p>
</div>
<p>{{ 'duration_in_months' | translate }}: {{ duration_registered }}</p>
</div>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
</div> </div>
<div class="col-md-5">
<p> {{ 'licenses_created' | translate }}: {{ licenses.length }}</p>
<div class="pre-scrollable">
<table class="table table-striped">
<thead>
<tr>
<th>{{ 'license' | translate }}</th>
<th>{{ 'creation' | translate }}</th>
<th>{{ 'activation' | translate }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="l in licenses | orderBy : 'creation_ts' : true" ng-class-odd="'striped'">
<td><tt>{{ l.number }}</tt></a></td>
<td>{{ l.creation_ts | date : "dd/MM/y" }}</td>
<td>{{ l.activation_ts | date : "dd/MM/y" }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div> </div>
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label translate>license_number</label> <label translate>license_number</label>
<input type="text" id="setup_license" class="form-control" mask="9999-9999-9999-9999" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formUser.license_number" required> <input type="text" id="setup_license" class="form-control" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formUser.license_number" required>
<div ng-show="studentData.license && !studentData.license_expired" class="alert alert-info" role="alert"> <div ng-show="studentData.license && !studentData.license_expired" class="alert alert-info" role="alert">
<i class="fa fa-info-circle" aria-hidden="true"></i> {{ 'license_expires' | translate }} {{ studentData.expiration_date }} <i class="fa fa-info-circle" aria-hidden="true"></i> {{ 'license_expires' | translate }} {{ studentData.expiration_date }}
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<input class="form-control" type="text" id="student_license" mask="9999-9999-9999-9999" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formdatastudent.license_number" required> <input class="form-control" type="text" id="student_license" mask="wwww-wwww-wwww-wwww" clean="true" placeholder="{{ 'license_number' | translate }}" ng-model="formdatastudent.license_number" required>
</div> </div>
......
...@@ -11,12 +11,12 @@ ...@@ -11,12 +11,12 @@
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
<div class="languages-margin text-center text-muted"> <div class="languages-margin text-center text-muted">
Powered by &nbsp; <a href="http://www.yottacode.com"><img src="img/logo_pictogram.png" width="40px" alt="Pictogram" title="Pictogram" /></a> Powered by &nbsp; <a href="http://www.pictogramweb.com"><img src="img/logo_pictogram.png" width="40px" alt="Pictogram" title="Pictogram" /></a>
</div> </div>
</div> </div>
<div class="col-xs-4"> <div class="col-xs-4">
<div class="languages-margin text-right text-muted"> <div class="languages-margin text-right text-muted">
<a href="mailto:soporte@yottacode.com" translate>support</a> | <a href="mailto:soporte@pictogramweb.com" translate>support</a> |
<a href='/app/#/disclaimer' target='_blank' translate>disclaimer</a> <a href='/app/#/disclaimer' target='_blank' translate>disclaimer</a>
</div> </div>
</div> </div>
......
...@@ -59,6 +59,10 @@ ...@@ -59,6 +59,10 @@
margin-top: 7px; margin-top: 7px;
} }
.table .table-striped .striped {
background-color: lightgray !important;
}
/* Evitar scrolling horizontal */ /* Evitar scrolling horizontal */
body{ body{
......
...@@ -6,10 +6,18 @@ var UPLOAD_PATH = path.join(__dirname, '..', '..', 'upload'); ...@@ -6,10 +6,18 @@ var UPLOAD_PATH = path.join(__dirname, '..', '..', 'upload');
module.exports.pictogram = { module.exports.pictogram = {
version: "1.1", // actual version of the server, to be checked by the client version: "1.1", // actual version of the server, to be checked by the client
admin: { admins: [
email: 'amontejo@ujaen.es', {
password: '$2a$06$flEEOc15SerMeYWARrN9w.KSpJuM.jDsaTgrtD0ESzbxKHPl0f/zq' //y00ttaa!! email: 'amontejo@ujaen.es',
}, password: '$2a$06$flEEOc15SerMeYWARrN9w.KSpJuM.jDsaTgrtD0ESzbxKHPl0f/zq', //y00ttaa!!
lang: "es-es"
},
{
email: 'luisballesteros@editorialcepe.es',
password: '$2a$10$Re9LxejAm6GjYLvw7LCbQeLiNn4HDGxjQMbZxg0paP3SGIJI6Rn52', //ba!!3sTe;0s
lang: "es-es"
}
],
serialSize: 10, // number of characters in generated serial numbers serialSize: 10, // number of characters in generated serial numbers
pageLimit: 10, // number of elements per "page" pageLimit: 10, // number of elements per "page"
......
...@@ -121,8 +121,9 @@ module.exports.policies = { ...@@ -121,8 +121,9 @@ module.exports.policies = {
LicenseController: { LicenseController: {
// create: ['tokenAuth', 'isAdmin'], // create: ['tokenAuth', 'isAdmin'],
// activate: ['tokenAuth'] // activate: ['tokenAuth']
create: true, create: ['tokenAuth'],
activate: true activate: ['tokenAuth'],
getByEmail: ['tokenAuth']
}, },
SupervisorController: { SupervisorController: {
......
...@@ -39,6 +39,7 @@ module.exports.routes = { ...@@ -39,6 +39,7 @@ module.exports.routes = {
'POST /instruction/template': 'MetaInstructionController.create', 'POST /instruction/template': 'MetaInstructionController.create',
'DELETE /instruction/template/:id': 'MetaInstructionController.destroy', 'DELETE /instruction/template/:id': 'MetaInstructionController.destroy',
'GET /license/:email': 'LicenseController.getByEmail',
'POST /license': 'LicenseController.create', 'POST /license': 'LicenseController.create',
'PUT /license/:number': 'LicenseController.activate', 'PUT /license/:number': 'LicenseController.activate',
......
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