diff --git a/soap/swad_web_service.h b/soap/swad_web_service.h index 08fe62d10..165ede896 100644 --- a/soap/swad_web_service.h +++ b/soap/swad_web_service.h @@ -440,6 +440,36 @@ struct swad__sendMessageOutput struct swad__usersArray usersArray; }; +/* structs used in getLocations */ +struct swad__location + { + int institutionCode; + char *institutionShortName; + char *institutionFullName; + int centerCode; + char *centerShortName; + char *centerFullName; + int buildingCode; + char *buildingShortName; + char *buildingFullName; + int floor; + int roomCode; + char *roomShortName; + char *roomFullName; + }; +struct swad__locationsArray + { + struct swad__location *__ptr; // pointer to array + int __size; // number of elements pointed to + }; + +/* getLocations */ +struct swad__getLocationsOutput + { + int numLocations; + struct swad__locationsArray locationsArray; + }; + /*****************************************************************************/ /*************************** Web service functions ***************************/ /*****************************************************************************/ @@ -523,3 +553,7 @@ int swad__sendNotice (char *wsKey,int courseCode,char *body, struct swad__sendNoticeOutput *sendNoticeOut); int swad__sendMessage (char *wsKey,int messageCode,char *to,char *subject,char *body, struct swad__sendMessageOutput *sendMessageOut); + +/* Wi-Fi-based positioning system */ +int swad__getLocations (char *wsKey,char *MAC, + struct swad__getLocationsOutput *getLocationsOut); diff --git a/sql/cambios.sql b/sql/cambios.sql index 323f87544..1dc7efd7a 100644 --- a/sql/cambios.sql +++ b/sql/cambios.sql @@ -13339,6 +13339,28 @@ UPDATE usr_data SET InsCod=1130 WHERE InsCod=25037; ALTER TABLE rooms CHANGE COLUMN BldCod BldCod INT NOT NULL DEFAULT -1; - - \ No newline at end of file + +-------------------- + +INSERT INTO room_MAC (RooCod,MAC) VALUES (1,0xf07f0667d5ff); +INSERT INTO room_MAC (RooCod,MAC) VALUES (2,0x6886a731695f); +INSERT INTO room_MAC (RooCod,MAC) VALUES (108,0xccd53989961f); + +mysql> SELECT RooCod,HEX(MAC) FROM room_MAC; ++--------+--------------+ +| RooCod | HEX(MAC) | ++--------+--------------+ +| 1 | F07F0667D5FF | +| 2 | 6886A731695F | +| 108 | CCD53989961F | ++--------+--------------+ +3 rows in set (0.00 sec) + + +SELECT institutions.InsCod,institutions.ShortName,institutions.FullName,centres.CtrCod,centres.ShortName,centres.FullName,buildings.BldCod,buildings.ShortName,buildings.FullName,rooms.Floor,rooms.RooCod,rooms.ShortName,rooms.FullName FROM room_MAC,rooms,buildings,centres,institutions WHERE room_MAC.MAC=0xCCD53989961F AND room_MAC.RooCod=rooms.RooCod AND rooms.BldCod=buildings.BldCod AND buildings.CtrCod=centres.CtrCod AND centres.InsCod=institutions.InsCod ORDER BY institutions.FullName,centres.FullName,buildings.FullName,rooms.Floor,rooms.FullName; + + + + +------------------------------- \ No newline at end of file diff --git a/sql/swad.sql b/sql/swad.sql index 4f6e76bd0..49e4ce88e 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -1264,7 +1264,7 @@ CREATE TABLE IF NOT EXISTS projects ( INDEX(CrsCod,ModifTime), INDEX(CrsCod,DptCod)); -- --- Table rooms: stores the classrooms associated to each centre +-- Table rooms: stores the rooms associated to each centre -- CREATE TABLE IF NOT EXISTS rooms ( RooCod INT NOT NULL AUTO_INCREMENT, @@ -1278,6 +1278,14 @@ CREATE TABLE IF NOT EXISTS rooms ( UNIQUE INDEX(RooCod), INDEX(CtrCod,BldCod,Floor)); -- +-- Table room_MAC: stores the associations between rooms and MAC addresses +-- +CREATE TABLE IF NOT EXISTS room_MAC ( + RooCod INT NOT NULL AUTO_INCREMENT, + MAC BIGINT NOT NULL, + UNIQUE INDEX(RooCod,MAC), + UNIQUE INDEX(MAC,RooCod)); +-- -- Table sessions: stores the information of open sessions -- CREATE TABLE IF NOT EXISTS sessions ( diff --git a/swad_API.c b/swad_API.c index 1bcbfd5f0..a99289bfa 100644 --- a/swad_API.c +++ b/swad_API.c @@ -166,6 +166,7 @@ static const char *API_Functions[1 + API_NUM_FUNCTIONS] = [API_getMatches ] = "getMatches", // 29 [API_getMatchStatus ] = "getMatchStatus", // 30 [API_answerMatchQuestion ] = "answerMatchQuestion", // 31 + [API_getLocations ] = "getLocations", // 32 }; /* Web service roles (they do not match internal swad-core roles) */ @@ -5017,7 +5018,7 @@ int swad__getMatches (struct soap *soap, " (SELECT mch_groups.MchCod" " FROM mch_groups,crs_grp_usr" " WHERE crs_grp_usr.UsrCod=%ld" - " AND mch_groups.GrpCod=crs_grp_usr.GrpCod))", + " AND mch_groups.GrpCod=crs_grp_usr.GrpCod))" " ORDER BY MchCod", Game.GamCod, Gbl.Usrs.Me.UsrDat.UsrCod); @@ -5887,3 +5888,168 @@ int swad__getMarks (struct soap *soap, return SOAP_OK; } + +/*****************************************************************************/ +/**************** Get locations associated to a MAC address ******************/ +/*****************************************************************************/ + +int swad__getLocations (struct soap *soap, + char *wsKey,char *MAC, // input + struct swad__getLocationsOutput *getLocationsOut) // output + { + int ReturnCode; + unsigned long MACnum; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumLocs; + unsigned NumLoc; + size_t Length; + + /***** Initializations *****/ + API_Set_gSOAP_RuntimeEnv (soap); + Gbl.WebService.Function = API_getLocations; + + /***** Check web service key *****/ + if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK) + return ReturnCode; + if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database + return soap_receiver_fault (soap, + "Bad web service key", + "Web service key does not exist in database"); + + /***** Get some of my data *****/ + if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod)) + return soap_receiver_fault (soap, + "Can not get user's data from database", + "User does not exist in database"); + Gbl.Usrs.Me.Logged = true; + Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs.Role; + + /***** Convert MAC string to number *****/ + if (sscanf (MAC,"%lx",&MACnum) != 1) + return soap_receiver_fault (soap, + "Bad MAC", + "MAC address format should be 12 hexadecimal digits"); + + /***** Get list of locations *****/ + NumLocs = (unsigned) + DB_QuerySELECT (&mysql_res,"can not get matches", + "SELECT institutions.InsCod," // row[ 0] + "institutions.ShortName," // row[ 1] + "institutions.FullName," // row[ 2] + "centres.CtrCod," // row[ 3] + "centres.ShortName," // row[ 4] + "centres.FullName," // row[ 5] + "buildings.BldCod," // row[ 6] + "buildings.ShortName," // row[ 7] + "buildings.FullName," // row[ 8] + "rooms.Floor," // row[ 9] + "rooms.RooCod," // row[10] + "rooms.ShortName," // row[11] + "rooms.FullName" // row[12] + " FROM room_MAC,rooms,buildings,centres,institutions" + " WHERE room_MAC.MAC=%lu" + " AND room_MAC.RooCod=rooms.RooCod" + " AND rooms.BldCod=buildings.BldCod" + " AND buildings.CtrCod=centres.CtrCod" + " AND centres.InsCod=institutions.InsCod" + " ORDER BY institutions.FullName," + "centres.FullName," + "buildings.FullName," + "rooms.Floor," + "rooms.FullName", + MACnum); + getLocationsOut->locationsArray.__size = + getLocationsOut->numLocations = (int) NumLocs; + + if (getLocationsOut->numLocations == 0) + getLocationsOut->locationsArray.__ptr = NULL; + else // Matches found + { + getLocationsOut->locationsArray.__ptr = soap_malloc (soap, + (getLocationsOut->locationsArray.__size) * + sizeof (*(getLocationsOut->locationsArray.__ptr))); + for (NumLoc = 0; + NumLoc < NumLocs; + NumLoc++) + { + /* Get next location */ + row = mysql_fetch_row (mysql_res); + /* + institutions.InsCod // row[ 0] + institutions.ShortName // row[ 1] + institutions.FullName // row[ 2] + centres.CtrCod // row[ 3] + centres.ShortName // row[ 4] + centres.FullName // row[ 5] + buildings.BldCod // row[ 6] + buildings.ShortName // row[ 7] + buildings.FullName // row[ 8] + rooms.Floor // row[ 9] + rooms.RooCod // row[10] + rooms.ShortName // row[11] + rooms.FullName // row[12] + */ + + /* Get institution code (row[0]) */ + getLocationsOut->locationsArray.__ptr[NumLoc].institutionCode = (int) Str_ConvertStrCodToLongCod (row[0]); + + /* Get institution short name (row[1]) */ + Length = strlen (row[1]); + getLocationsOut->locationsArray.__ptr[NumLoc].institutionShortName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].institutionShortName,row[1],Length); + + /* Get institution full name (row[2]) */ + Length = strlen (row[2]); + getLocationsOut->locationsArray.__ptr[NumLoc].institutionFullName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].institutionFullName,row[2],Length); + + /* Get center code (row[3]) */ + getLocationsOut->locationsArray.__ptr[NumLoc].centerCode = (int) Str_ConvertStrCodToLongCod (row[3]); + + /* Get center short name (row[4]) */ + Length = strlen (row[4]); + getLocationsOut->locationsArray.__ptr[NumLoc].centerShortName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].centerShortName,row[4],Length); + + /* Get center full name (row[5]) */ + Length = strlen (row[5]); + getLocationsOut->locationsArray.__ptr[NumLoc].centerFullName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].centerFullName,row[5],Length); + + /* Get building code (row[6]) */ + getLocationsOut->locationsArray.__ptr[NumLoc].buildingCode = (int) Str_ConvertStrCodToLongCod (row[6]); + + /* Get building short name (row[7]) */ + Length = strlen (row[7]); + getLocationsOut->locationsArray.__ptr[NumLoc].buildingShortName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].buildingShortName,row[7],Length); + + /* Get building full name (row[8]) */ + Length = strlen (row[8]); + getLocationsOut->locationsArray.__ptr[NumLoc].buildingFullName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].buildingFullName,row[8],Length); + + /* Get floor (row[9]) */ + getLocationsOut->locationsArray.__ptr[NumLoc].floor = (int) Str_ConvertStrCodToLongCod (row[9]); + + /* Get room code (row[10]) */ + getLocationsOut->locationsArray.__ptr[NumLoc].roomCode = (int) Str_ConvertStrCodToLongCod (row[10]); + + /* Get room short name (row[11]) */ + Length = strlen (row[11]); + getLocationsOut->locationsArray.__ptr[NumLoc].roomShortName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].roomShortName,row[11],Length); + + /* Get room full name (row[12]) */ + Length = strlen (row[12]); + getLocationsOut->locationsArray.__ptr[NumLoc].roomFullName = (char *) soap_malloc (soap,Length + 1); + Str_Copy (getLocationsOut->locationsArray.__ptr[NumLoc].roomFullName,row[12],Length); + } + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return SOAP_OK; + } diff --git a/swad_API.h b/swad_API.h index eb8e95035..5189f7841 100644 --- a/swad_API.h +++ b/swad_API.h @@ -31,7 +31,7 @@ /***************************** Public constants ******************************/ /*****************************************************************************/ -#define API_NUM_FUNCTIONS 31 +#define API_NUM_FUNCTIONS 32 /*****************************************************************************/ /******************************* Public types ********************************/ @@ -72,6 +72,7 @@ typedef enum API_getMatches = 29, API_getMatchStatus = 30, API_answerMatchQuestion = 31, + API_getLocations = 32, } API_Function_t; /*****************************************************************************/ diff --git a/swad_changelog.h b/swad_changelog.h index a258eabb5..413d14ec3 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -481,6 +481,7 @@ contiene una de las que yo imparto. As /* TODO: Geolocalización: + Función API sendCurrentLocation... Parámetros a enviar a la función: 1. Código único de ubicación (número) @@ -502,11 +503,13 @@ Funci Paramétros: MAC, string con ubicación (ej. "Aula 0.1") -Función API getLocations -1. Añadir tipo de ubicación -2. Añadir lista desplegable de MAC asociadas a una ubicación -3. API: getLocations (como parámetro se pasa la MAC) - - que devolveria las filas de la tabla de ubicaciones asociadas a esa MAC +Función de la API para ver dónde se encuentra un usuario: +getUserLocation +Un usuario sólo podrá consultar la ubicación de otro usuario +si la intersección de los centros de sus asignaturas no es vacía, +es decir, no tienen por qué compartir asignaturas, +pero sí al menos alguna asignatura de cada uno tiene que compartir el centro +(Por ej. Eva y Antonio comparten ETSIIT, pero no titulación ni asignatura) */ // TODO: Sugerencia de Jesús García Miranda. En las preguntas de tipo test de elección única (o un nuevo tipo con un nuevo nombre), @@ -525,6 +528,7 @@ Funci // TODO: Integrar pull requests con traducciones del alemán del usuario eruedin en GitHub // TODO: Cambiar icono notificaciones nuevas con "bell-on.svg" // TODO: Ahmed El Moukhtari Koubaa: Cuando le damos a la opción de mostrar solo los mensajes no leídos, se muestran estos mensajes, pero cuando los intentamos leer, es decir, hacemos clic sobre ellos se recarga toda la página por así decirlo y vuelve a dar una lista con los mensajes, pero descartando aquel que clicamos porque, entiendo yo al menos, que ya lo ha marcado como leído. +// TODO: Cambiar "centre" a "center" /*****************************************************************************/ /****************************** Public constants *****************************/ @@ -544,11 +548,18 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.213.1 (2020-05-06)" +#define Log_PLATFORM_VERSION "SWAD 19.214 (2020-05-06)" #define CSS_FILE "swad19.193.1.css" #define JS_FILE "swad19.193.1.js" /* - Version 19.213.2: May 06, 2020 Change color of dates on current exam event. (? lines) + Version 19.214.1: May 06, 2020 Change color of dates on current exam event. (? lines) + Version 19.214: May 05, 2020 New API function getLocations. (301568 lines) + 1 change necessary in database: +CREATE TABLE IF NOT EXISTS room_MAC (RooCod INT NOT NULL AUTO_INCREMENT,MAC BIGINT NOT NULL,UNIQUE INDEX(RooCod,MAC),UNIQUE INDEX(MAC,RooCod)); + If you want to use MyISAM: +ALTER TABLE room_MAC ENGINE=MyISAM; + + Version 19.213.2: May 06, 2020 Changed settings of firewall. (301361 lines) Version 19.213.1: May 06, 2020 Fixed bug in edition of set of questions. (301357 lines) Version 19.213: May 06, 2020 Edition of exam event. Code refactoring in groups. (301327 lines) diff --git a/swad_database.c b/swad_database.c index a74bdb4bc..29be70382 100644 --- a/swad_database.c +++ b/swad_database.c @@ -2691,6 +2691,23 @@ mysql> DESCRIBE rooms; "UNIQUE INDEX(RooCod)," "INDEX(CtrCod,BldCod,Floor))"); + /***** Table room_MAC *****/ +/* +mysql> DESCRIBE room_MAC; ++--------+------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++--------+------------+------+-----+---------+----------------+ +| RooCod | int(11) | NO | PRI | NULL | auto_increment | +| MAC | bigint(20) | NO | PRI | NULL | | ++--------+------------+------+-----+---------+----------------+ +2 rows in set (0.00 sec) +*/ + DB_CreateTable ("CREATE TABLE IF NOT EXISTS room_MAC (" + "RooCod INT NOT NULL AUTO_INCREMENT," + "MAC BIGINT NOT NULL," // 12 digits hexadecimal number + "UNIQUE INDEX(RooCod,MAC)," + "UNIQUE INDEX(MAC,RooCod))"); + /***** Table sessions *****/ /* mysql> DESCRIBE sessions; diff --git a/swad_exam.c b/swad_exam.c index e52f33588..6c93a4148 100644 --- a/swad_exam.c +++ b/swad_exam.c @@ -1983,14 +1983,16 @@ void Exa_ReceiveFormExam (void) ItsANewExam = (Exam.ExaCod <= 0); /***** Get all current exam data from database *****/ - // Some data are necessary to show exam and sets of questions again + // Some data, not received from form, + // are necessary to show exam and sets of questions again if (!ItsANewExam) { Exa_GetDataOfExamByCod (&Exam); Exams.ExaCod = Exam.ExaCod; } - /***** If I can edit exams ==> receive some data of exam from form *****/ + /***** If I can edit exams ==> + overwrite some exam data with the data received from form *****/ Exa_ReceiveExamFieldsFromForm (&Exam,Txt); if (Exa_CheckExamFieldsReceivedFromForm (&Exam)) { diff --git a/swad_firewall.c b/swad_firewall.c index 2bfdcb6c3..ec6fa15ea 100644 --- a/swad_firewall.c +++ b/swad_firewall.c @@ -43,8 +43,9 @@ extern struct Globals Gbl; /* The maximum number of clicks in the interval should be large enough to prevent an IP from being banned due to automatic refresh when the user is viewing the last clicks. */ -#define Fw_CHECK_INTERVAL ((time_t)(10UL)) // Check clicks in the last 10 seconds -#define Fw_MAX_CLICKS_IN_INTERVAL 100 // Maximum of 100 clicks allowed in 10 seconds +#define Fw_CHECK_INTERVAL ((time_t)(30UL)) // Check clicks in the last 30 seconds +#define Fw_MAX_CLICKS_IN_INTERVAL 150 // Maximum of 150 clicks allowed in 30 seconds + // (5 clicks/s sustained for 30 s) #define Fw_TIME_BANNED ((time_t)(60UL*60UL)) // Ban IP for 1 hour