Macros/ScriptForge/HowToJournalizeUpdatesOfDocsExample
Appearance
< Macros | ScriptForge
TDF LibreOffice Document Liberation Project Community Blogs Weblate Nextcloud Redmine Ask LibreOffice Donate
How to journalize the updates that are logged inside a document
Authored by Jean-Pierre Ledure.
- In this example, every Save command registers, before the save itself, the time when the change took place, who did it and what has been changed.
- What has been changed is asked to the user with a simple input box. You might also imagine a more complex dialog.
- Anyway, a new record is inserted at the bottom of an internal file stored in the document. Even when mailed or shared, updates remain registered. Each record is coded as a very basic CSV file.
- In addition, the log file may be extracted from the document and loaded into a new Calc sheet.
How to run it in BASIC
- Create a new document.
- Open the Basic IDE
- Select the first available blank module
- Copy and paste the Basic code
- Save the document anywhere
- Associate the document's "Save Document" event with the LogUpdate() function
- To extract the log file, run manually the ExtractLogFile() Sub
How to run it in Python
Create a new document.
- Run APSO
- Create a new module, call it 'Module1'
- Copy and paste the Python code below
- Verify line 17
- Save and run the Main() method
Code
REM SCRIPTFORGE WIKI EXAMPLE
REM How to log the updates of a document ?
REM Minimal required version: LibreOffice 24.2
REM Used services
REM Document, FileSystem, Platform
Option Explicit
Const logfile = "log/updates-logfile.txt"
'*******************************************************************
'* Associate next Sub with the "Save document" event of the document
'*******************************************************************
Function LogUpdate(Optional event As Object) As Boolean
' Implements a simple logging of a document's updates:
' At each Save, an input box is displayed to get a comment
' related to the last changes.
' A logging record is created only if the comment is not null.
' The logging is stored in the document itself. This allows
' to register updates even when the document is mailed or shared.
Dim doc As Object ' The actual document as a Document class instance
Dim pf As Object ' The Platform service
Dim username As String ' The actual logged user
Dim userdata As Object ' A Dictionary class instance
Dim logmessage As String ' A log message given by the user
Dim logrecord As String ' The record to insert at the bottom of the log file
Dim fs As Object ' The FileSystem service
Dim filename As String ' The name of the internal log file
Dim foldername As String ' The name of the internal log folder
Dim file As Object ' A TextStream class instance
GlobalScope.BasicLibraries.loadLibrary("ScriptForge")
' Next If makes the script easier to test directly from the Basic IDE
If IsMissing(event) Then
Set doc = CreateScriptService("Document", ThisComponent)
Else
Set doc = CreateScriptService("DocumentEvent", event)
End If
If IsNull(doc) Then Exit Function
' Get data to log
Set pf = CreateScriptService("Platform")
username = pf.CurrentUser
userdata = pf.UserData
logmessage = InputBox("Summarize the changes done today :", "Saving ...")
' Do nothing if Cancel was clicked.
If Len(logmessage) = 0 Then Exit Function
logrecord = Now() & "," & username & "," _
& userdata.Item("firstname") & " " & userdata.Item("lastname") & "," _
& logmessage
' Store the record at the bottom of the log file
Set fs = CreateScriptService("FileSystem")
filename = fs.BuildPath(doc.filesystem, logfile)
foldername = fs.GetParentFolderName(filename)
' Either make a new file or append to the existing one
If fs.FileExists(filename) Then
file = fs.OpenTextFile(filename, iomode := fs.ForAppending)
Else
fs.CreateFolder(foldername)
file = fs.CreateTextFile(filename)
End If
file.WriteLine(logrecord)
file.CloseFile()
' Housekeeping
userdata.Dispose()
doc.Dispose()
' Go ahead with Save
LogUpdate = False
End Function
'*******************************************************************
'* Execute next Sub to extract the logged records
'*******************************************************************
Sub ExtractLogFile(Optional event As Object)
' The log file is loaded in an empty Calc sheet
' The Sub is presumed located in a document's macro library
Dim doc As Object ' The actual document as a Document class instance
Dim ui As Object ' The UI service
Dim fs As Object ' The FileSystem service
Dim filename As String ' The name of the internal log file
Dim calc As Object ' A new Calc document as a Calc class instance
GlobalScope.BasicLibraries.loadLibrary("ScriptForge")
Set doc = CreateScriptService("Document", ThisComponent)
Set ui = CreateScriptService("UI")
' Is there a log file ?
Set fs = CreateScriptService("FileSystem")
filename = fs.BuildPath(doc.filesystem, logfile)
If Not fs.FileExists(filename) Then
MsgBox "No log file could be found in your document."
Exit Sub
End If
' Extract and load the file
Set calc = ui.CreateDocument("Calc") ' Create a new Calc document
calc.ImportFromCSVFile(filename, "A1")
' Housekeeping
doc.Dispose()
calc.Dispose()
End Sub
# coding: utf-8
from __future__ import unicode_literals
from scriptforge import CreateScriptService
### SCRIPTFORGE WIKI EXAMPLE
### How to log the updates of a document ?
### Minimal required version: LibreOffice 24.2
### Used services
### Document, FileSystem, Platform
logfile = 'log/updates-logfile.txt'
basic = CreateScriptService('Basic')
pf = CreateScriptService('Platform')
fs = CreateScriptService('FileSystem')
ui = CreateScriptService('UI')
# *******************************************************************
# * Associate next def with the 'Save document' event of the document
# *******************************************************************
def logupdate(event = None):
# Implements a simple logging of a document's updates:
# At each Save, an input box is displayed to get a comment
# related to the last changes.
# A logging record is created only if the comment is not null.
# The logging is stored in the document itself. This allows
# to register updates even when the document is mailed or shared.
# doc The actual document as a Document class instance
# username The actual logged user
# userdata A dict(ionary)
# logmessage A log message given by the user
# logrecord The record to insert at the bottom of the log file
# filename The name of the internal log file
# foldername The name of the internal log folder
# file A TextStream class instance
# doc is derived from the input event
doc = CreateScriptService('DocumentEvent', event)
if doc is None:
return
# Get data to log
username = pf.CurrentUser
userdata = pf.UserData
logmessage = basic.InputBox('Summarize the changes done today :', 'Saving ...')
# Do nothing if Cancel was clicked.
if len(logmessage) == 0:
return False
logrecord = str(basic.Now()) + ',' + username + ',' \
+ userdata['firstname'] + ' ' + userdata['lastname'] + ',' \
+ logmessage
# Store the record at the bottom of the log file
filename = fs.BuildPath(doc.filesystem, logfile)
foldername = fs.GetParentFolderName(filename)
# Either make a new file or append to the existing one
if fs.FileExists(filename):
file = fs.OpenTextFile(filename, iomode = fs.ForAppending)
else:
fs.CreateFolder(foldername)
file = fs.CreateTextFile(filename)
file.WriteLine(logrecord)
file.CloseFile()
# Housekeeping
doc.Dispose()
# Go ahead with Save
return False
# *******************************************************************
# * Execute next Sub to extract the logged records
# *******************************************************************
def extractlogfile(event = None):
# The log file is loaded in an empty Calc sheet
# doc The actual document as a Document class instance
# filename The name of the internal log file
# calc A new Calc document as a Calc class instance
doc = CreateScriptService('Document', basic.ThisComponent)
# Is there a log file ?
filename = fs.BuildPath(doc.FileSystem, logfile)
if fs.FileExists(filename) is False:
basic.MsgBox('No log file could be found in your document.')
return
# Extract and load the file
calc = ui.CreateDocument('Calc') # Create a new Calc document
calc.ImportFromCSVFile(filename, 'A1')
# Housekeeping
doc.Dispose()
calc.Dispose()
g_exportedScripts = (logupdate, extractlogfile)
if __name__ == "__main__":
logupdate()