Buen dia Compañeros programadores, como estan, espero que bien y desandoles los mejores exitos en sus proyectos, llevo mucho tiempo que no me aparecia por aqui un abrazo, quiero preguntarles algo y es sobre llevar un historial de los movimientos de los usuarios que operan un sistema, por ejemplo yo quiero registrar los movimientos que hacen los usuarios operadores al agregar, modificar, eliminar, etc, se me ocurre llevar estos historiales en una tabla con los ides de estos operadores, el problema es este, que yo podria registrar que un usuario hizo un cambio a tal fecha, tal hora y registro la palabra modificó, pero para saber especificamente que hizo?, quiza pueda colocar cual fue el dato que modificó pero siempre y cuando este sea una palabra cuya tabla solo guarde un dato como por ejemplo el número de teléfono o la palabra de una ciudad, pero que pasaria si fuesen mas datos, como nombre, apellido, direccion, alli es donde me pone a pensar y creo que debo hacer a cada tabla de mi sistema un historial de movimientos y que a su ves haya una final y definitiva que agarre los ides de estos historiales para luego hacer una consulta y mostrar en una tabla general que fue lo que hizo el usuario y asi saber el dato exacto que gestiono!, quiza estoy equivocado!, no se que piensen ustedes, espero que los que tengan experiencia me puedan orientar, muchas gracias.
Home » Forum » Gambas » Bases de Datos
Sobre Llevar Un Historial De Los Movimientos De Usuarios De Un Sistema
Sobre Llevar Un Historial De Los Movimientos De Usuarios De Un Sistema |
Article | |
---|---|
|
|
jousseph [ Thursday, 25 July 2019, 21:43 ] | |
Sobre Llevar Un Historial De Los Movimientos De Usuarios De Un Sistema |
Comments | |
---|---|
Bueno... lo que pides no es difícil, pero tiene implicación en muchas partes de tu sistema.
El sistema tiene dos partes: Por un lado la grabación y firmado de cada registro/consulta que se haga a la/s BBDD por otro la creación de un histórico de acciones de usuario y por último un sistema de consultas de todo eso. La primera parte más o menos es así: A.- FIRMAR TODAS LAS OPERACIONES Y MOSTRAR LA FIRMA A.1.- Añade a TODAS las tablas de tu sistema dos campos al final usr varchar(50) fmod datetime Estos campos sirven de firma para saber quién ha hecho la última modificación de cada registro. usr contendrá el "nick" de cada usuario (mejor no poner en él su código para mejorar la legibilidad). fmod contendrá la fecha y hora de la actualización. A.2.- Para hacer sencillo el "firmado de los registros", en la función que utilizes para modificar la BBDD (yo uso un módulo para altas bajas y modificaciones), añade el firmado con el nick de usuario y la fecha y hora. Algo así (extraído de cómo lo hago yo en mi módulo): ... ... rs = laConexion.edit(tabla, campoClave & "= &1", clave) rs = Control2Result(oContenedor, rs) 'esta función rellena el result a partir del form o panel que contenga los controles Try rs["usr"] = mComun.usuario.nick 'el nick del usuario. Le pongo el try por si la tabla no tuviese dicho campo Try rs["fmod"] = Now 'la fecha y la hora. El try se pone por lo mismo de arriba Try rs.Update ... ... Con esto ya tienes seguimiento de quién ha hecho la última acción sobre cada registro. A.3.- A TODOS los formularios de datos, añade un textbox llamado firma en la parte de abajo. A la hora de rellenar cada formulario con los datos existentes, añade ésto a la función que recupere los datos de la bbdd ... ... 'Este es parte del bucle con el que yo relleno los controles del form desde los campos del result (que se llaman igual que los controles). 'Tú sustituye ésto por la función que utilices para rellenar el result por eso te los pongo comentados 'For Each f In rs.Fields ' campo = f.Name 'con ésto le quitamos los alias de a., b., etc. a los campos. ' Try o = oContenedor.controls[campo] ' If Not Error And Not IsNull(o) Then ' If o Is Textedit Then ' o.richText = rs[o.name] ' Else ' Try o.Value = rs[f.Name] ' If Error Then o.Text = rs[f.Name] ' Endif ' Endif ' Next Try oContenedor.controls["firma"].text = "Modificado por " & rs!usr & " el " & Format(rs!fmod, "dd-mm-yyyy") 'aquí muestras la firma en pantalla. Le pongo el Try por si el form no contuviese el campo firma .... .... B) CREAR UN REGISTRO HISTÓRICO DE OPERACIONES SOBRE LA BBDD B.1.- Creación de la tabla del histódiro. Crea una tabla con éste diseño (Este es para mysql, puedes adaptarlo a la BBDD que uses: tipo es una cadena que identifica la operación, por ejemplo: "Actualiza Personas", "Añade Registro en Personas", "Elimina Personas", donde Personas es, claro, una tabla existente. detalle es el contenido de la operación, ahora hablamos de ello. usr y fmod ya sabemos lo que contienen B.2.- Función de actualización del histórico. En el módulo de actualización de la BBDD, añade ésta función: Public Sub hlog(tipo As String, detalle As String) detalle = Replace(detalle, "'", "\\'") 'escapamos toda comilla que pueda haber detalle = Replace(detalle, "\"", "\\\"") detalle = "insert into ad_hlog (tipo, detalle, usr,fmod) values ('" & String.Mid(tipo, 1) & "', '" & String.Mid(detalle, 1) & "', '" & String.Mid(mComun.usuario.nick, 1) & "', " & "now()" & ")" Connections[Application.name].exec(detalle) Catch 'Enviamos un email a los administradores del programa indicando el error producido mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) End Fíjate que sólo grabamos cuatro campos, el tipo, el detalle y la firma del propio histórico usr y fmod B.3.- Rellenado de la tabla del histórico: En tu función de actualización de la BBDD (la misma en la que grababas la firma en el punto A.2) añade el siguiente código antes del update: ' dim cad as string ' Try rs["usr"] = mComun.usuario.nick 'el nick del usuario. Le pongo el try por si la tabla no tuviese dicho campo ' Try rs["fmod"] = Now 'la fecha y la hora. El try se pone por lo mismo de arriba For Each f In rs.Fields Try cad &= f.name & ": " & rs[f.name] & "\n" 'try porque si el campo es mediumtext y está vacío, casca Next ' Try rs.Update Y luego llama a la función de actualización del histórico con ésta línea: mComun.hlog("Añade en " & tabla, cad) donde tabla contiene el nombre de la tabla y cad, como ves más arriba, el nombre de los campos y el contenido de cada uno que se graban en la BBDD Con ésto ya tienes todo lo que quieres saber grabado en el histórico de movimientos en la bbdd. Te adjunto aquí mismo el módulo entero de actualización de la BBDD incluyendo todo lo que arriba te pongo (casi) tal y como lo usamos en la empresa. ' gambas module file Public Function grabaRegistro(tabla As String, campoClave As String, clave As Variant, oContenedor As Object, Optional laConexion As Connection) As Boolean 'NOTE: la funcion grabaRegistro se utiliza para grabar un determinado valor de la base de datos por ejemplo a la hora de actualizar la clave de un usuario ' devuelve -1 si ha fallado la actualización y 0 si ha sido exitosa Dim rs As Result Dim lret As Integer Dim cad As String Dim f As ResultField If Not laConexion Then laConexion = Connections[Application.name] Endif If Not laConexion.Opened Then laConexion.open rs = laConexion.edit(tabla, campoClave & "= &1", clave) ' utiliza la funcion edit de gambas para grabar los datos en vez de utilizar sentencias select rs = Control2Result(oContenedor, rs) Try rs["usr"] = mComun.usuario.nick Try rs["fmod"] = Now Try rs.Update If Error Then mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) lret = -1 Else lret = 0 For Each f In rs.Fields Try cad &= f.Name & ": " & rs[f.Name] & "\n" 'try porque si el campo es mediumtext y está vacío, casca Next mComun.hlog("Modifica " & tabla, cad) End If Return lret End Public Function creaRegistro(tabla As String, oContenedor As Object, Optional conec As Connection, Optional verClave As Boolean) As Variant ' devuelve -1 si ha fallado la adición. Si verClave=true se devuelve el id del registro añadido. Si verClave=false, se devuelve 0 Dim rs, r As Result Dim lret As Integer Dim f As ResultField Dim cad, clave As String If Not conec Then conec = Connections[Application.name] If Not mComun.abreConexion(conec.name) Then Return False rs = conec.create(tabla) rs = Control2Result(oContenedor, rs) Try rs["usr"] = mComun.usuario.nick Try rs["fmod"] = Now For Each f In rs.Fields Try cad &= f.name & ": " & rs[f.name] & "\n" 'try porque si el campo es mediumtext y está vacío, casca Next Try rs.Update If Error Then mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) lret = -1 Else If verClave Then clave = conec.Tables[tabla].primaryKey[0] r = conec.Exec("select Last_Insert_id() as '" & clave & "' from `" & tabla & "`") lret = r[clave] Else lret = 0 Endif mComun.hlog("Añade en " & tabla, cad) Endif Return lret End Public Function borraRegistro(tabla As String, campoClave As String, clave As Variant, Optional hcon As Connection) As Boolean Dim r As Result Dim f As ResultField Dim cad As String If Not hcon Then hcon = Connections[Application.name] If Not mComun.abreConexion() Then Return False r = hcon.exec(Subst("SELECT * FROM " & tabla & " where `" & campoClave & "` = &1", clave)) If r.Available Then For Each f In r.Fields Try cad &= f.Name & ": " & f[f.Name] & "\n" 'try porque si el campo es mediumtext y está vacío, casca Next Endif Try hcon.delete(tabla, campoclave & "=&1", clave) If Error Then mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) Return False Else mComun.hlog("Borra de " & tabla, cad) Return True Endif End Public Sub limpiaCampos(oContenedor As Object) Dim o As Object Dim n As Integer For Each o In oContenedor.Children If o Is TabStrip Or o Is IconPanel Or o Is TabPanel Or o Is ToolPanel Then For n = 0 To o.Count - 1 o.index = n limpiaCampos(o) 'Recursividad Next o.index = 0 Endif If o Is Container Then limpiaCampos(o) 'Recursividad Endif 'Especificamos los tipos para que no limpie también los labels y demás. If o Is ValueBox Or If o Is CheckBox Or If o Is RadioButton Or If o Is Color Or If o Is Button Or If o Is DirBox Or If o Is SwitchButton Or If o Is SpinBox Then Try o.Value = 0 Else If o Is TextArea Or If o Is TextBox Or If o Is ListBox Or If o Is ComboBox Or If o Is DbListBox Or If o Is DbComboBox Or If o Is TextEditor Or If o Is TextEdit Then Try o.Text = "" Else If o Is HtEdit Then Try o.html = "" Endif Next End Public Function Control2Result(oContenedor As Object, rs As Result) As Result ' este procedimiento se utiliza desde el formulario perfil para cargar los controles o listados en tiempo de ejecucion. ', Optional campoclave As String) As Result Dim o As Object Dim f As ResultField Dim n As Integer Dim campo As String If oContenedor Is Form Then 'Esta debería ser la opción preferida, por velocidad. For Each f In rs.Fields campo = IIf(Mid(f.name, 2, 1) = ".", Mid(f.name, 3), f.Name) Try o = oContenedor.controls[campo] If Not Error And Not IsNull(o) Then If o Is Textedit Then rs[o.name] = o.richText Else Try rs[o.Name] = o.Value If Error Then rs[o.name] = o.Text Endif Endif Next Else For Each o In oContenedor.Children If o Is TabStrip Or o Is IconPanel Or o Is TabPanel Or o Is ToolPanel Then For n = 0 To o.Count - 1 o.index = n Control2Result(o, rs) 'Recursividad Next o.index = 0 Endif If o Is Container Then Control2Result(o, rs) 'Recursividad Endif For n = 0 To rs.Fields.count - 1 campo = IIf(Mid(rs.Fields[n].name, 2, 1) = ".", Mid(rs.Fields[n].name, 3), rs.Fields[n].Name) If o.name = campo Then If o Is Textedit Then rs[o.name] = o.richText Else Try rs[o.Name] = o.Value If Error Then rs[o.name] = o.Text Break Endif Endif Next Next Endif Finally Return rs Catch mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) End Public Sub Result2Control(rs As Result, oContenedor As Object) Dim o As Object Dim f As ResultField Dim campo As String Dim n As Integer If oContenedor Is Form Then 'Esta debería ser la opción preferida por velocidad For Each f In rs.Fields campo = IIf(Mid(f.name, 2, 1) = ".", Mid(f.name, 3), f.Name) 'con ésto le quitamos los alias de a., b., etc. a los campos. Try o = oContenedor.controls[campo] If Not Error And Not IsNull(o) Then If o Is Textedit Then o.richText = rs[o.name] Else Try o.Value = rs[f.Name] If Error Then o.Text = rs[f.Name] Endif Endif Next Try oContenedor.controls["firma"].text = "Modificado por " & rs!usr & " el " & Format(rs!fmod, "dd-mm-yyyy") Else For Each o In oContenedor.Children If Left(o.name, 5) = "firma" Then o.text = "Modificado por " & rs!usr & " el " & Format(rs!fmod, "dd-mm-yyyy") If o Is TabStrip Or o Is IconPanel Or o Is TabPanel Or o Is ToolPanel Then For n = 0 To o.Count - 1 o.index = n Result2Control(rs, o) 'Recursividad Next o.index = 0 Endif If o Is Container Then Result2Control(rs, o) 'Recursividad Endif For Each f In rs.Fields campo = IIf(Mid(f.name, 2, 1) = ".", Mid(f.name, 3), f.Name) For n = 0 To oContenedor.children.count - 1 If oContenedor.children[n].name = campo Then o = oContenedor.children[n] If o Is TextEdit Then o.richtext = rs[f.name] Else Try o.Value = rs[f.Name] If Error Then o.Text = rs[f.Name] Break Endif Endif Next Next Next Endif Catch mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) End Public Sub hlog(tipo As String, detalle As String) detalle = Replace(detalle, "'", "\\'") detalle = Replace(detalle, "\"", "\\\"") detalle = "insert into ad_hlog (tipo, detalle, usr,fmod) values ('" & String.Mid(tipo, 1) & "', '" & String.Mid(detalle, 1) & "', '" & String.Mid(mComun.usuario.nick, 1) & "', " & "now()" & ")" Connections[Application.name].exec(detalle) Catch mEMail.sendmail(mComun.entorno["mailprograma"], [mComun.entorno["mailerrores"]], "Error en " & Application.Name & ", "Usuario: " & mComun.usuario.nick & "\nFecha: " & Format(Now(), "dd-mm-yyyy hh:mm:ss") & "\n" & Error.Text & " - " & Error.where, mComun.servidores["mailserver"]) End Sólo te falta la manera de consultar y manejar toda esa información... pero ahora que veo todo lo que te he puesto, me parece todo un poco confuso. Dame un poco de tiempo y te hago un ejemplo funcional en Sqlite. Saludos. |
|
shordi [ Friday, 26 July 2019, 10:15 ] | |
Muchas gracias señor shordi, se ve lo profesional que es, un abrazo, saludos.
|
|
jousseph [ Friday, 26 July 2019, 17:52 ] | |
|
|
shordi [ Friday, 26 July 2019, 20:19 ] | |
shordi que pasote!!! |
|
gambafeliz [ Friday, 26 July 2019, 20:41 ] | |
Page 1 of 1 |
Home » Forum » Gambas » Bases de Datos
Users browsing this topic: 0 Registered, 0 Hidden and 1 Guest Registered Users: None |
This is a "Lo-Fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by Icy Phoenix based on phpBB
Design by DiDiDaDo
Generation Time: 0.6579s (PHP: 65% SQL: 35%)
SQL queries: 23 - Debug Off - GZIP Enabled