Blog

Desarrollo sobre Topoos II

Para los que queráis echar un vistazo al código os dejamos aquí el repositorio de Github de la prueba de tecnología. Acordaos de registraros en Topoos y leer el README del repositorio.

Si queréis podéis ir directamente a las conclusiones.

Registro de la aplicación en Topoos

El primer paso a dar será registrar la aplicación de Parkplan en Topoos. Al registrar la aplicación debemos proporcionar una redirect_uri y una push_uri. La redirect_uri será utilizada por Topoos para realizar un callback a nuestro servidor después de realizar una autenticación de usuario a través de Topoos. Y la push_uri será utilizada por Topoos a mode de web hook para recibir alertas. En nuestro caso, recibiremos alertas cuando definamos una zona de control y alguno de nuestros controlados se salga fuera de esta zona.

Una vez registrada la aplicacion obtenemos un CLIENT_ID que identifica a la aplicación de Parkplan en Topoos.

Login/registro del usuario en una aplicación sobre Topoos

Todos los usuarios de Parkplan deberán estar autenticados en Topoos. Por ello cuando acceden al sistema para autenticarse:

GET http://parkplan.byteflair.cloudbees.net/api/v1/login

El sistema les redirige a la siguiente URL:

https://login.topoos.com/oauth/authtoken?
client_id=CLIENT_ID&redirect_uri={redirect_uri}&response_type=code&scope={scope}

En esa dirección se les solicitará el nombre de usuario y la contraseña (para hacer login). También se les da la opción de registrarse en caso de no disponer de una cuenta en Topoos.

La primera vez que se autentiquen en Topoos se les presentará una pantalla donde se les pregunta si consienten que la aplicación Parkplan acceda a sus datos de Topoos. Una vez autenticados en Topoos y habiendo aceptado que Parkplan acceda a sus datos, serán redirigidos de nuevo a Parkplan. La URL a la que se les redirige es la que se configuró cuando se registró la aplicación Parkplan en el sistema de Topoos: redirect_uri.

Si el usuario no acepta compartir los datos con Parkplan o no es autenticado con éxito, Topoos realizará la siguiente llamada.

GET <redirect_uri>?error=access_denied (cuando el usuario no da acceso a la aplicación)

En cambio, si todo transcurre correctamente, Topoos incorá la siguiente URL:

GET &lt;redirect_uri&gt;?code={authorization_code}

El siguiente paso es realizar otra petición a Topoos, esta vez para obtener un access token que permitirá a Parkplan actuar en nombre del usuario en el sistema Topoos:

POST https://login.topoos.com/oauth/accesstoken

En la petición se envían como parámetros: grant_type, cliend_id, client_secret, code (conseguido en el paso anterior) y la redirect_uri que deberá ser la misma que la especificada en la configuración de la aplicación.

El sistema responde con un acces_token y un refresh_token. Habrá que guardar ambos.

El último paso será el de recuperar información del usuario, siempre y cuando se trate de un nuevo usuario. Los detalles del usuario se obtienen mediante la siguiente petición:

GET https://api.topoos.com/1/users/me/show.json?oauth_token={access_token}

El sistema nos responde con la información personal del usuario: email, nombre de usuario. Se guarda esta información junto con la recuperada en el paso anterior (access_token, refresh_token).

Solicitar el control de un usuario

Para que un usuario (controlador) pueda solicitar el control de otro (controlado), ambos tendrán que estar registrados en el sistema y el usuario que actúe de controlador deberá conocer el nombre de usuario del controlado.

La petición que hay que realizar es la siguiente:

POST http://parkplan.byteflair.cloudbees.net/api/v1/users/{controllerId}/controllees
{
 “username”: “<controlled_username>”
}

Como respuesta se obtiene el detalle del usuario controlado

{
 “id”: <controlled_id>,
 “username”: “<controlled_username>”
}

La solicitud quedará en estado PENDING a la espera de que el usuario controlado responda aceptando o rechazando la solicitud.

Sólo se puede tener en curso (en estado PENDING o ACCEPTED) una única solicitud de control sobre un mismo usuario. Si se intenta solicitar el control de un usuario que ya está siendo controlado o que todavía no ha respondido a otra solicitud anterior el sistema responderá con un error como el siguiente:

{
 "reason":"Pairing (controller: <controllerId>, controlled: <controlledId>) is [PENDING|ACCEPTED]."
}

A continuación se puede ver un diagrama con los estados por los que puede pasar las solicitudes de control.

topoos-fence_status

 

Consultar las solicitudes de control pendientes

Para que un usuario pueda aceptar o rechazar una solicitud de control antes tendrá que ser capaz de consultar las solicitudes de control que tiene pendiente de una respuesta.

GET http://parkplan.byteflair.cloudbees.net/api/v1/pairings?controlled={controlledId}&status=PENDING

Como respuesta se obtendrá una lista con las solicitudes en estado PENDING en las que aparece como controlado:

[{
 "id": <pairingId>,
 "controller": <controllerId>,
 "controlled": <controlledId>,
 "status":"PENDING"
}]

Del mismo modo un usuario podrá consultar las solicitudes que ha realizado para evitar realizarlas por duplicado:

GET http://parkplan.byteflair.cloudbees.net/api/v1/pairings?controller={controllerId}&status=PENDING

Aceptar/Rechazar una solicitud de control

Para aceptar o rechazar una solicitud de control se necesita el identificador de la solicitud en cuestión. Este se puede obtener consultando las solicitudes pendientes de respuesta.

PUT http://parkplan.byteflair.cloudbees.net/api/v1/pairings/{pairingId}
{
 “status”: “[ACCEPTED|REJECTED]”
}

Una solicitud podrá ser aceptada o rechazada cuando se encuentre pendiente de respuesta (PENDING). En cualquier otro caso el sistema responderá con un error indicando que acciones se pueden realizar en el estado en el que se encuentra.

Por ejemplo, si tenemos una solicitud aceptada y la intentamos aceptar de nuevo el sistema nos responderá con el siguiente error:

{
 "reason":"ACCEPTED pairing can only be canceled."
}

Consultar controlados/controladores

Para que un usuario cree una zona de control, tendrá que seleccionar una lista de usuarios a incluir en dicha zona de control. Para seleccionar la lista de usuarios a controlar tendrá que ser capaz de consultar los usuarios que han aceptado la solicitud de control.

GET http://parkplan.byteflair.cloudbees.net/api/v1/users/{controllerId}/controllees

Como respuesta obtendrá la lista de usuarios que han aceptado la solicitud de control:

[{
 "id": <controlledId>,
 "username": "<controlledUsername>"
}]

Los usuarios también serán capaces de consultar quiénes son capaces de controlarles:

GET http://parkplan.byteflair.cloudbees.net/api/v1/users/{controlledId}/controllers

Eliminar un controlado

Un usuario controlador podrá dejar de controlar a otro usuario. Como consecuencia de esto todas las zonas de control que estuvieran en curso serán detenidas.

DELETE http://parkplan.byteflair.cloudbees.net/api/v1/users/{controllerId}/controllees/{controlledId}

 Crear una zona de control

Un usuario (controlador) podrá controlar que otros usuarios (controlados) permanezcan dentro de una determinada zona (zona de control). En caso de algún usuario controlado salga de la zona de control el controlador recibirá una notificación. La zona de control viene determinada por una superficie circular y se define mediante un punto (latitud y longitud) y una distancia en kilómetros que representa el radio desde el punto. Para crear una zona de control se realizará la siguiente petición:

POST http://parkplan.byteflair.cloudbees.net/api/v1/users/{controllerId}/fences
{
 "name":"<fenceName>",
 "controllees": [<controlledIdList>],
 "lat": <latitude>,
 "lng": <longitude>,
 "radius": <radius>
}

A partir de este momento la zona de control quedará activada (en estado CREATED) y en caso de recibir la posición de algún controlado fuera de la zona de control se le notificará al controlador de la zona de control.

Sólo podrán incluirse en la zona de control usuarios que hayan aceptado ser controlados por el controlador. En cualquier otro caso el sistema responderá con un error como el siguiente:

{
 "reason":"Pairing (controller:17, controlled:19) does not exist."
}

Cuando el sistema recibe esta petición efectúa 2 peticiones al sistema de Topoos por cada usuario controlado que se incluya en la lista. La primera de las peticiones es para dar de alta un Track en Topoos:

GET https://api.topoos.com/1/tracks/add.json?oauth_token={access_token}&name={trackName}

Como respuesta obtendremos un identificador del Track creado. La segunda petición es para crear una Rule asociada a dicho Track que contendrá la definición en sí misma de la zona de control:

GET https://api.topoos.com/1/rules/add.json?
oauth_token={access_token}&track={trackId}&type=TRACK_OUT_OF_BOUNDS&lat={lat}&lng={lng}&radius={radius}

Topoos no admite crear un Track con varios usuarios relacionados. Es esta la razón por la que las dos llamadas anteriores hay que repetirlas por cada usuario incluido en la zona de control.

Consultar zonas de control

Tanto los usuarios controladores como los que son controlados podrán consultar sus zonas de control. Los primeros para saber a quienes están controlando y en qué zonas. Y los segundos para saber por quiénes están siendo controlados y por qué zonas tienen restringidos sus movimientos. Para consultar las zonas de control habrá que hacer la siguiente petición:

GET http://parkplan.byteflair.cloudbees.net/api/v1/users/{userId}/fences?
status=[CREATED|RUNNING|STOPPING|STOPPED]

Esto nos devolverá una lista como la siguiente:

[{
 "id": <fenceId>,
 "name": “<fenceName>”,
 "created": <creationDate>,
 "controller": <controllerId>,
 "controllees": [<controlledIdList>],
 "status": "[CREATED|RUNNING|STOPPING|STOPPED]",
 "lat": <latitude>,
 "lng": <longitude>,
 "radius": <radius>
}]

El listado contendrá tanto las zonas de control controladas por el usuario como en las que le están controlando a él. Para las zonas de control en las que el usuario sea controlado, únicamente se mostrará a ese mismo usuario como controlado, no pudiendo saber a quiénes más se está controlando en esa misma zona.

Ver el detalle de una zona de control

También se podrán ver las posiciones por las que un usuario controlado se está moviendo. Esto le interesará tanto al controlador como al controlado (para respetar los límites).

GET http://parkplan.byteflair.cloudbees.net/api/v1/fences/{fenceId}

El resultado contendra la lista de posiciones agrupadas por usuario controlado, con un indicador de si la posición está fuera de los límites establecidos o no:

{
 "id": <fenceId>,
 "name": “<fenceName>”,
 "created": <creationDate>,
 "controller": <controllerId>,
 "controllees": [<controlledIdList>],
 "status": "[CREATED|RUNNING|STOPPING|STOPPED]",
 "lat": <latitude>,
 "lng": <longitude>,
 "radius": <radius>,
 "detail": {
 "positions": {
   "<controlledId>": [{
     "lat": <latitude>,
     "lng": <longitude>,
     "date": <date>,
     "violation": <out_of_bounds>
   }]
 }
}

En el caso de que el usuario que consulta el detalle sea un usuario controlado, únicamente se verá él como usuario controlado así como sus posiciones.

Si el usuario no es el controlador de la zona de control ni tampoco es ninguno de los usuarios controlados el sistema nos devolverá un error como el siguiente:

{
 "reason":"User (id:<userId>) is not controller nor controlled of fence (id:<fenceId>)."
}

En este caso para obtener la lista de las posiciones de cada usuario se invoca a un enpoint de Topoos:

GET https://api.topoos.com/1/tracks/get.json?oauth_token={access_token}&track={trackId}

El sistema delega en Topoos el guardado y obtención de las posiciones por las que se mueven los usuarios. Esto es así en este caso porque Topoos proporciona una funcionalidad que se ajusta a nuestras necesidades. Esta funcionalidad es registrar las posiciones y después obtener un listado de ellas.

En otros casos (como la creación de zonas de control), no se puede delegar totalmente en Topoos y hay que mantener una “réplica” de los datos puesto que no se ajusta totalmente a la funcionalidad deseada. En el caso de la creación de zonas de control el principal motivo para mantener una copia de los Tracks y las Reglas es que Topoos no permite asignar varios usuarios a un mismo Track.

Detener una zona de control

Un usuario controlador podrá dejar de controlar una determinada zona de control. Esto significará que dejará de recibir avisos cuando alguno de los usuarios controlados salgan fuera de la zona de control. Hay que tener en cuenta que una vez que se detiene el control de una determinada zona de control, no puede volver a reanudarse. En caso de querer reanudar el control en la misma zona habría que volver a crearla de nuevo. Esto es así porque Topoos no lo permite, y en el momento que se establece el final del control de una determinada zona es imposible reanudarlo para la misma zona sin crear otra zona de nuevo.

La petición a realizar para detener el control sobre una zona de control es:

PUT http://parkplan.byteflair.cloudbees.net/api/v1/users/{controllerId}/fences/{fenceId}
{
 "status":"STOPPING"
}

La zona de control se detendrá si el usuario es el controlador de la misma y si la zona de control no se ha detenido anteriormente. En caso contrario el sistema no responderá con el siguiente error (en el caso de que ya se encuentre detenida):

{
 "reason":"STOPPED fence can not be updated."
}

O con el siguiente error (en el caso de que el usuario no sea el controlador de la zona de control):

{
 "reason":"User (id:19) is not controller of fence (id: 1000003)."
}

Enviar una posición

Para que los usuarios controladores puedan saber dónde se encuentran los usuarios controlados y que el sistema pueda notificarles cuando se salgan de las zonas de control, los usuarios controlados tendrán que enviar al sistema periódicamente