Bloquear pantalla si otro usuario está activo con JavaScript y PHP

Bloquear pantalla si otro usuario está activo con JavaScript y PHP

Muchas veces en un sistema web nos encontramos con la situación de que necesitamos bloquear pantalla si otro usuario está activo en esa misma, esto como una solución para la concurrencia de usuarios y posibles modificaciones no deseadas en base de datos, hoy implementaremos esta funcionalidad con JavaScript y PHP.

Actualmente existen varias formas de tratar la concurrencia de usuarios.

Hoy vamos a hablar e implementar posiblemente la solución más sencilla pero eficaz.

En un proyecto que estoy desarrollando me tope con esta problemática que me ocasionaba actualizaciones en base de datos no deseadas.


¿Sabías que?

¿Necesitas aprender algo nuevo ? Ve a Udemy, busca el tema del que quieres aprender, selecciona el curso para ti y continua con tu aprendizaje.

Udemy

Trabajo en un sistema donde un usuario ingresa a una pantalla y se encuentra con cientos de datos que se actualizan en base de datos automáticamente al cambiar sus valores.

Esto hace que el sistema sea más fácil de trabajar pues no existe un botón de guardar, pero también causa algunos problemas de compatibilidad al estar dos usuarios sobre la misma pantalla de proyecto.

Por esta razón implementamos una solución de concurrencia de usuarios bastante simple, bloquear pantalla si otro usuario está activo, veamos que hicimos.

Estructura de base de datos

Cabe mencionar que en nuestra base de datos tenemos una tabla de proyectos que es sobre lo que va la pantalla que queremos bloquear el acceso a solo un usuario.

En esta tabla de proyectos agregamos dos columnas o campos más: ultimaactualizacion y idusuarioactivo.

El primer campo es un datetime donde almacenaremos una fecha que cada usuario dentro de la pantalla de proyecto estará reportando cada cierto tiempo.

El segundo campo es el id del usuario que está reportando para conocer a detalle quien está trabajando en la pantalla de proyecto.

Revisar concurrencia al ingresar a pantalla

A continuación veamos lo que se hace al ingresar a la pantalla de proyecto, nuestra pantalla en la que queremos implementar esta funcionalidad.

function revisarConcurrencia(){

            jQuery.post("database/revisarUltimaActualizacion.php",{

                idproyecto : <?php echo $IDPROYECTO; ?>,
                idusuario : <?php echo $_SESSION['IDINDEX']; ?>

            }).done(function(data){

                data = JSON.parse(data);

                if( data['status'] == "ERR" ){

                    jQuery("#usuarioactivo").html(data["usuario"]);

                    jQuery("#popup-proyecto-en-uso").modal({
                        backdrop: 'static',
                        keyboard: false
                    });

                }else{

                    // Iniciamos worker concurrencia
                    iniciarWorker();

                }

            });

        }

Esta función debe de llamarse al inicio del proyecto, recomendable en el metodo jQuery(document).ready(function(){).

Lo que hacemos aquí es revisar si existe un usuario activo mediante un archivo llamado revisarUltimaActualizacion.php.

Si el estatus es ERR entonces sabemos que existe otro usuario en este proyecto entonces hacemos cualquier cosa que querramos nosotros lanzamos un modal con información del usuario activo gracias al idusuarioactivo.

Si no existe usuario activo únicamente iniciamos la función iniciarWorker() que se encarga de reportar que estamos trabajando en esta pantalla cada cierto tiempo.

Revisar ultima actualización

<?php

include "db.php";

if( isset($_POST['idproyecto']) && isset($_POST['idusuario']) ){

	$idproyecto = $_POST['idproyecto'];

	$idusuario = $_POST['idusuario'];

	$fecha = date("Y-m-d H:i:s");

	$fechaUltima = "";

	$idusuarioactivo = 0;

	$usuario = "";

	$data = array();

	$data["status"] = "";

	$data["ultimaactualizacion"] = "";

	$data["idusuarioactivo"] = 0;

	$data["usuario"] = "";

	// Revisar si han pasado más de 10 min sin actividad en ese proyecto

	$sql = " SELECT ultimaactualizacion, idusuarioactivo, usuarios.correo as usuario FROM proyectos INNER JOIN usuarios ON proyectos.idusuarioactivo = usuarios.idusuario WHERE idproyecto = $idproyecto";

	$sql .= " AND idusuarioactivo != $idusuario; "; 

	$result = mysqli_query($conn, $sql);

	if($result->num_rows>0){

		while($fila=$result->fetch_assoc()){

		    $fechaUltima = $fila["ultimaactualizacion"];

		    $idusuarioactivo = $fila["idusuarioactivo"];

		    $usuario = $fila["usuario"];

		}

		// Comparamos

		$fechaPrimera = new DateTime($fecha);
		$fechaUltima = new DateTime($fechaUltima);
		$diferencia = $fechaUltima->diff( $fechaPrimera )->i;

		if( $diferencia > 5 ){ // Si han pasado mas de 10 minutos

			$sql_u = "UPDATE proyectos SET ultimaactualizacion = '$fecha', idusuarioactivo = $idusuario WHERE idproyecto = $idproyecto; ";

			if ($conn->query($sql_u) === TRUE) {

				$data["status"] = "OK";
				$data["ultimaactualizacion"] = $fecha;
				$data["idusuarioactivo"] = $idusuario;
				$data["usuario"] = $usuario;

			} else {

				echo "ERR";
				
			}

		}else{ // Existe un usuario activo

			$data["status"] = "ERR";
			$data["ultimaactualizacion"] = $fechaUltima;
			$data["idusuarioactivo"] = $idusuarioactivo;
			$data["usuario"] = $usuario;

		}

	}

	echo json_encode($data);

	$conn->close();

}

?>

He tratado de comentar el código anterior para que sea más fácil de comprender.

Lo que hace es prácticamente revisar la última fecha de actualización y el id usuario activo mediante un idproyecto.

Si no hay actividad hace más de 10 minutos se registra la fecha actual y el id usuario que entro a revisar, ahora el tiene el control de la pantalla o proyecto.

Regresamos el arreglo mediante JSON, en este arreglo pasamos estatus, ultimaactualizacion, idusuarioactivo y usuario.

Worker en JavaScript

En nuestra pantalla de proyecto también implementamos la función iniciarWorker() que se encarga de reportar cada 3 minutos a base de datos.

function iniciarWorker() {

            if(typeof(Worker) !== "undefined") {

                if(typeof(worker) == "undefined") {

                    worker = new Worker("assets/js/worker.js");

                }

                // Enviamos idproyecto e idusuario
                worker.postMessage("<?php echo $IDPROYECTO;?>-<?php echo $_SESSION['SIJSAUSERIDINDEX']; ?>");
                
                // Recibimos confirmacion
                worker.onmessage = function(event) {

                    console.log(event.data);

                };

            } else {

                console.log("Tu navegador no soporta Workers.");

            }

        }

        function detenerWorker() { 

          worker.terminate();

          worker = undefined;

        }

Esto lo hacemos mediante un archivo JavaScript llamado worker.js que veremos a continuación.

function ultimaActualizacion(idproyecto, idusuario) {

    const Http = new XMLHttpRequest();

	const url = '../../database/registrarUltimaActualizacion.php?idproyecto='+idproyecto+"&idusuario="+idusuario;

	Http.open("POST", url);

	Http.send();

	Http.onreadystatechange = (e) => {

	  	if( Http.responseText == "OK" ){

	  		postMessage("Ultima actualizacion registrada.");

	  	}

	}

    setTimeout("ultimaActualizacion("+idproyecto+","+idusuario+")", (60000)*3 );

}

onmessage = function(e) {

    var tmp = e.data.split("-");

    if( tmp.length == 2){

    	ultimaActualizacion(tmp[0], tmp[1]);

    }
};



En la función onmessage recibimos el idproyecto y el idusuario que enviamos en  nuestra pantalla de proyecto y los enviamos a la función ultimaActualización.

En esta función lo único que hacemos es registrar nuestra actividad en base de datos mediante el archivo registrarUltimaActualizacion.php

Ejemplo de la funcionalidad Picture in Picture en JavaScript.

Registrar ultima actualización

En este archivo recibimos idproyecto e idusuario que usaremos para registrar en la base de datos que seguimos trabajando en ese proyecto.

<?php

include "db.php";

if( isset($_GET['idproyecto']) && isset($_GET['idusuario']) ){

	$idproyecto = $_GET['idproyecto'];

	$idusuario = $_GET['idusuario'];

	$fecha = date("Y-m-d H:i:s");

	$sql = "UPDATE proyectos SET ultimaactualizacion = '$fecha', idusuarioactivo = $idusuario WHERE idproyecto = $idproyecto; ";

	if ($conn->query($sql) === TRUE) {

		echo "OK";

	} else {

		echo "ERR";
		
	}

	$conn->close();

}

?>

Ahora cuando un usuario este activo en un proyecto y quiera ingresar otro usuario al mismo proyecto verá este mensaje, tu puedes realizar cualquier otra acción.

Bloquear pantalla si otro usuario está activo con JavaScript y PHP

Ceder el control rápidamente

Aunque esta funcionalidad funciona perfectamente existe el inconveniente de tener que esperar algunos minutos para que otro usuario tome el control de un proyecto.

A pesar de que una persona solicitará a la otra que le deje ingresar a un proyecto aún asi tiene que esperar menos de 10 minutos a que deje de reportar una vez abandono la pantalla de proyecto.

Para solucionar este problema se implementó un botón en la pantalla de proyectos que permite ceder el control, es decir, eliminar los campos ultimaactualización e idusuarioactivo.

En nuestra pantalla de proyecto:

jQuery("#btn_cederControl").on("click",function(){

                jQuery.post( "database/eliminarUltimaActualizacion.php", {

                    idproyecto : <?php echo $IDPROYECTO; ?>,
                    idusuario : <?php echo $_SESSION['SIJSAUSERIDINDEX']; ?>

                }).done(function( data ) {

                    if( data == "OK" ){

                        location.href = "tablero-de-proyectos";

                    }

                });

            });

En nuestro archivo eliminarUltimaActualizacion.php:

<?php

include "db.php";

if( isset($_POST['idproyecto']) && isset($_POST['idusuario']) ){

	$idproyecto = $_POST['idproyecto'];

	$idusuario = $_POST['idusuario'];

	$sql = "UPDATE proyectos SET ultimaactualizacion = '', idusuarioactivo = 0 WHERE idproyecto = $idproyecto AND idusuarioactivo = $idusuario; ";

	if ($conn->query($sql) === TRUE) {

		echo "OK";

	} else {

		echo "ERR";
		
	}

	$conn->close();

}

?>

Como dijimos anteriormente, limpiamos los campos de ultimaactualizacion e idusuarioactivo, de esta forma cualquier usuario podrá ingresar rápidamente sin tener que esperar.

Si esta información sobre cómo bloquear pantalla si otro usuario está activo con JavaScript y PHP te ha sido de utilidad no olvides compartirla en tus redes sociales favoritas o dejarnos un comentario en la sección de abajo si tienes cualquier duda respecto de este tema, será un placer ayudarte.

¡Hasta luego!

Clic para valorar esta información
[Total: 3 Promedio: 5]