diff --git a/cubesql-webadmin.xojo_project b/cubesql-webadmin.xojo_project index d1a141f..ae23e8c 100644 --- a/cubesql-webadmin.xojo_project +++ b/cubesql-webadmin.xojo_project @@ -20,6 +20,9 @@ Folder=containers;webapp/containers;&h000000005859EFFF;&h0000000018D38FFF;false Folder=base;webapp/containers/base;&h000000000B1567FF;&h000000005859EFFF;false WebContainer=cntStatus;webapp/containers/cntStatus.xojo_code;&h000000000A45BFFF;&h000000005859EFFF;false Folder=server;webapp/containers/server;&h0000000045A527FF;&h000000005859EFFF;false +Folder=data;webapp/containers/data;&h00000000107E37FF;&h000000005859EFFF;false +WebContainer=cntDatabases;webapp/containers/data/cntDatabases.xojo_code;&h0000000040B4DFFF;&h00000000107E37FF;false +WebContainer=cntBackups;webapp/containers/data/cntBackups.xojo_code;&h000000004237B7FF;&h00000000107E37FF;false WebContainer=cntRegistrationAction;webapp/containers/server/cntRegistrationAction.xojo_code;&h000000000788EFFF;&h0000000045A527FF;false Folder=security;webapp/containers/security;&h000000007FF17FFF;&h000000005859EFFF;false Class=cntBase;webapp/containers/base/cntBase.xojo_code;&h0000000041D557FF;&h000000000B1567FF;false @@ -33,7 +36,6 @@ BuildSteps=Build Automation;Build Automation.xojo_code;&h000000001394FFFF;&h0000 ColorAsset=colTextKey;styles/colTextKey.xojo_color;&h000000005870AFFF;&h00000000139DBFFF;false Module=modWebStyles;styles/modWebStyles.xojo_code;&h0000000002BE7FFF;&h00000000139DBFFF;false WebContainer=cntRegistration;webapp/containers/server/cntRegistration.xojo_code;&h000000002FA707FF;&h0000000045A527FF;false -WebContainer=cntDatabases;webapp/containers/server/cntDatabases.xojo_code;&h0000000040B4DFFF;&h0000000045A527FF;false WebContainer=cntConsole;webapp/containers/server/cntConsole.xojo_code;&h000000004BD2DFFF;&h0000000045A527FF;false WebContainer=cntGroups;webapp/containers/security/cntGroups.xojo_code;&h0000000034036FFF;&h000000007FF17FFF;false WebContainer=cntUsers;webapp/containers/security/cntUsers.xojo_code;&h00000000700FF7FF;&h000000007FF17FFF;false diff --git a/styles/modWebStyles.xojo_code b/styles/modWebStyles.xojo_code index a6aeeda..ed069f3 100644 --- a/styles/modWebStyles.xojo_code +++ b/styles/modWebStyles.xojo_code @@ -25,6 +25,31 @@ Protected Module modWebStyles End Sub #tag EndMethod + #tag Method, Flags = &h0 + Sub ShowWithActionWarning(Extends dialog As WebMessageDialog) + dialog.Show + + Timer.CallLater(1, AddressOf ShowWithActionWarningTimerAction, dialog) + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ShowWithActionWarningTimerAction(dialog As Variant) + If (Not (dialog IsA WebMessageDialog)) Then Return + + Var javaScript() As String + javaScript.Add("(function() {") + javaScript.Add(" let button = document.getElementById('" + WebMessageDialog(dialog).ControlID + "_action');") + javaScript.Add(" button.classList.remove('btn-primary');") + javaScript.Add(" button.classList.add('btn-warning');") + javaScript.Add("})();") + + WebMessageDialog(dialog).ExecuteJavaScript(String.FromArray(javaScript, "")) + + End Sub + #tag EndMethod + #tag Method, Flags = &h0 Function StyleListboxKeyColumn() As WebStyle Var style As New WebStyle diff --git a/webapp/Session.xojo_code b/webapp/Session.xojo_code index 0197251..8b83480 100644 --- a/webapp/Session.xojo_code +++ b/webapp/Session.xojo_code @@ -18,7 +18,7 @@ Inherits WebSession DB = loginDB Try - DB.ExecuteSQL("SET CLIENT TYPE TO 'cubeSQL Web Admin " + App.Version + "'") + DB.ExecuteSQL("SET CLIENT TYPE TO 'cubeSQL Web Admin " + App.Version.EscapeSqlQuotes + "'") Var rs As RowSet = db.SelectSQL("SHOW MY INFO") @@ -289,6 +289,14 @@ Inherits WebSession Type="Boolean" EditorType="" #tag EndViewProperty + #tag ViewProperty + Name="ClientId" + Visible=false + Group="Behavior" + InitialValue="-1" + Type="Integer" + EditorType="" + #tag EndViewProperty #tag EndViewBehavior End Class #tag EndClass diff --git a/webapp/containers/base/cntDatasourceBase.xojo_code b/webapp/containers/base/cntDatasourceBase.xojo_code index 3c7919f..6b7b64d 100644 --- a/webapp/containers/base/cntDatasourceBase.xojo_code +++ b/webapp/containers/base/cntDatasourceBase.xojo_code @@ -132,7 +132,7 @@ Implements WebDataSource If bSearchFilter And col.IsSearchable Then If rs.Column(col.DatabaseColumnName).StringValue.Contains(Me.SearchValue, ComparisonOptions.CaseInsensitive) Then - 'We want so see rows that contain the text of the SerachFilter + 'We want so see rows that contain the text of the SearchFilter bSearchFilterShowRow = True End If End If diff --git a/webapp/containers/data/cntBackups.xojo_code b/webapp/containers/data/cntBackups.xojo_code new file mode 100644 index 0000000..1633e08 --- /dev/null +++ b/webapp/containers/data/cntBackups.xojo_code @@ -0,0 +1,1480 @@ +#tag WebContainerControl +Begin cntDatasourceBase cntBackups + Compatibility = "" + ControlCount = 0 + ControlID = "" + Enabled = True + Height = 500 + Indicator = 0 + LayoutDirection = 0 + LayoutType = 0 + Left = 0 + LockBottom = False + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = True + LockVertical = False + ScrollDirection = 0 + TabIndex = 0 + Top = 0 + Visible = True + Width = 750 + _mDesignHeight = 0 + _mDesignWidth = 0 + _mPanelIndex = -1 + Begin WebListBox lstInfos + ColumnCount = 1 + ColumnWidths = "" + ControlID = "" + Enabled = True + HasHeader = True + Height = 342 + HighlightSortedColumn= True + Index = -2147483648 + Indicator = 0 + InitialValue = "" + LastAddedRowIndex= 0 + LastColumnIndex = 0 + LastRowIndex = 0 + Left = 0 + LockBottom = True + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = True + LockTop = True + LockVertical = False + NoRowsMessage = "No Backups" + ProcessingMessage= "" + RowCount = 0 + RowSelectionType= 1 + Scope = 2 + SearchCriteria = "" + SelectedRowColor= &c0d6efd + SelectedRowIndex= 0 + TabIndex = 0 + TabStop = True + Tooltip = "" + Top = 0 + Visible = True + Width = 750 + _mPanelIndex = -1 + End + Begin WebButton btnDelete + AllowAutoDisable= False + Cancel = False + Caption = "Delete" + ControlID = "" + Default = False + Enabled = False + Height = 38 + Index = -2147483648 + Indicator = 4 + Left = 630 + LockBottom = True + LockedInPosition= True + LockHorizontal = False + LockLeft = False + LockRight = True + LockTop = False + LockVertical = False + Scope = 2 + TabIndex = 5 + TabStop = True + Tooltip = "" + Top = 442 + Visible = True + Width = 100 + _mPanelIndex = -1 + End + Begin WebButton btnBackup + AllowAutoDisable= False + Cancel = False + Caption = "Backup" + ControlID = "" + Default = False + Enabled = True + Height = 38 + Index = -2147483648 + Indicator = 0 + Left = 20 + LockBottom = True + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = False + LockVertical = False + PanelIndex = "0" + Scope = 2 + TabIndex = 2 + TabStop = True + Tooltip = "" + Top = 442 + Visible = True + Width = 100 + _mPanelIndex = -1 + End + Begin WebButton btnRestore + AllowAutoDisable= False + Cancel = False + Caption = "Restore" + ControlID = "" + Default = False + Enabled = False + Height = 38 + Index = -2147483648 + Indicator = 5 + Left = 522 + LockBottom = True + LockedInPosition= True + LockHorizontal = False + LockLeft = False + LockRight = True + LockTop = False + LockVertical = False + PanelIndex = "0" + Scope = 2 + TabIndex = 4 + TabStop = True + Tooltip = "" + Top = 442 + Visible = True + Width = 100 + _mPanelIndex = -1 + End + Begin WebMessageDialog dlgDelete + ControlID = "" + Enabled = True + Explanation = "" + Index = -2147483648 + Indicator = 0 + LockBottom = False + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = True + LockVertical = False + Message = "" + Scope = 2 + Title = "" + Tooltip = "" + _mPanelIndex = -1 + End + Begin WebRectangle rctFilter + BackgroundColor = &cFFFFFF + ControlCount = 0 + ControlID = "" + Enabled = True + HasBackgroundColor= False + Height = 75 + Index = -2147483648 + Indicator = 0 + LayoutDirection = 0 + LayoutType = 0 + Left = 0 + LockBottom = True + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = True + LockTop = False + LockVertical = False + PanelIndex = "0" + Scope = 2 + TabIndex = 1 + TabStop = True + Tooltip = "" + Top = 350 + Visible = True + Width = 750 + _mDesignHeight = 0 + _mDesignWidth = 0 + _mPanelIndex = -1 + Begin WebLabel labFilter + Bold = True + ControlID = "" + Enabled = True + FontName = "" + FontSize = 0.0 + Height = 38 + Index = -2147483648 + Indicator = 0 + Italic = False + Left = 20 + LockBottom = False + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = True + LockVertical = False + Multiline = False + PanelIndex = "0" + Parent = "rctFilter" + Scope = 2 + TabIndex = 0 + TabPanelIndex = -1 + TabStop = True + Text = "Filter" + TextAlignment = 0 + TextColor = &c000000FF + Tooltip = "" + Top = 370 + Underline = False + Visible = True + Width = 60 + _mPanelIndex = -1 + End + Begin WebLabel labFilterDatabase + Bold = False + ControlID = "" + Enabled = True + FontName = "" + FontSize = 0.0 + Height = 38 + Index = -2147483648 + Indicator = 0 + Italic = False + Left = 151 + LockBottom = False + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = True + LockVertical = False + Multiline = False + PanelIndex = "0" + Parent = "rctFilter" + Scope = 2 + TabIndex = 1 + TabPanelIndex = -1 + TabStop = True + Text = "Database:" + TextAlignment = 0 + TextColor = &c000000FF + Tooltip = "" + Top = 370 + Underline = False + Visible = True + Width = 140 + _mPanelIndex = -1 + End + Begin WebPopupMenu lstFilterDatabase + ControlID = "" + Enabled = True + Height = 38 + Index = -2147483648 + Indicator = 0 + InitialValue = "" + LastAddedRowIndex= 0 + LastRowIndex = 0 + Left = 299 + LockBottom = False + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = True + LockVertical = False + PanelIndex = "0" + Parent = "rctFilter" + RowCount = 0 + Scope = 2 + SelectedRowIndex= 0 + SelectedRowText = "" + TabIndex = 2 + TabPanelIndex = -1 + TabStop = True + Tooltip = "" + Top = 370 + Visible = True + Width = 400 + _mPanelIndex = -1 + End + Begin WebProgressWheel pgrWheel + Colorize = False + ControlID = "" + Enabled = True + Height = 32 + Index = -2147483648 + Indicator = 0 + Left = 710 + LockBottom = False + LockedInPosition= True + LockHorizontal = False + LockLeft = False + LockRight = True + LockTop = True + LockVertical = False + Parent = "rctFilter" + Scope = 2 + SVGColor = &c00000000 + SVGData = "" + TabIndex = 3 + TabPanelIndex = 0 + TabStop = True + Tooltip = "" + Top = 373 + Visible = False + Width = 32 + _mPanelIndex = -1 + End + End + Begin WebThread thrBackup + DebugIdentifier = "" + Index = -2147483648 + LockedInPosition= True + Priority = 5 + Scope = 2 + StackSize = 0 + ThreadID = 0 + ThreadState = "" + End + Begin WebThread thrDelete + DebugIdentifier = "" + Index = -2147483648 + LockedInPosition= True + Priority = 5 + Scope = 2 + StackSize = 0 + ThreadID = 0 + ThreadState = "" + End + Begin WebThread thrRestore + DebugIdentifier = "" + Index = -2147483648 + LockedInPosition= True + Priority = 5 + Scope = 2 + StackSize = 0 + ThreadID = 0 + ThreadState = "" + End + Begin WebMessageDialog dlgRestore + ControlID = "" + Enabled = True + Explanation = "" + Index = -2147483648 + Indicator = 0 + LockBottom = False + LockedInPosition= True + LockHorizontal = False + LockLeft = True + LockRight = False + LockTop = True + LockVertical = False + Message = "" + PanelIndex = "0" + Scope = 2 + Title = "" + Tooltip = "" + _mPanelIndex = -1 + End + Begin WebButton btnDownload + AllowAutoDisable= False + Cancel = False + Caption = "Download" + ControlID = "" + Default = False + Enabled = False + Height = 38 + Index = -2147483648 + Indicator = 2 + Left = 414 + LockBottom = True + LockedInPosition= True + LockHorizontal = False + LockLeft = False + LockRight = True + LockTop = False + LockVertical = False + PanelIndex = "0" + Scope = 2 + TabIndex = 3 + TabStop = True + Tooltip = "" + Top = 442 + Visible = True + Width = 100 + _mPanelIndex = -1 + End + Begin WebThread thrDownload + DebugIdentifier = "" + Index = -2147483648 + LockedInPosition= True + Priority = 5 + Scope = 2 + StackSize = 0 + ThreadID = 0 + ThreadState = "" + End + Begin WebTimer timDownload + ControlID = "" + Enabled = True + Index = -2147483648 + Location = 0 + LockedInPosition= True + Period = 500 + RunMode = 0 + Scope = 2 + TabIndex = 6 + TabStop = True + _mPanelIndex = -1 + End + Begin WebTimer timThread + ControlID = "" + Enabled = True + Index = -2147483648 + Location = 0 + LockedInPosition= True + Period = 500 + RunMode = 0 + Scope = 2 + TabIndex = 6 + TabStop = True + _mPanelIndex = -1 + End +End +#tag EndWebContainerControl + +#tag WindowCode + #tag Event + Sub Opening() + Self.Load() + + Self.ShowInfos() + + ebOpened = True + + End Sub + #tag EndEvent + + + #tag Method, Flags = &h21 + Private Sub ActionBackup() + If Me.IsThreadRunning Then Return + + Var databasename As String = Me.GetSelectedDatabasename() + If (databasename = "") Then Return + + esActionDatabasename = databasename + esActionTimestamp = "" + + pgrWheel.Visible = True + + thrBackup.Start + timThread.RunMode = WebTimer.RunModes.Multiple + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ActionDelete() + If Me.IsThreadRunning Then Return + + Var databasename As String = Me.GetSelectedDatabasename() + Var timestamp As String = Me.GetSelectedTimestamp() + If (databasename = "") Or (timestamp = "") Then Return + + Var backupDate As DateTime = Me.GetDateTimeFromTimestamp(timestamp) + + dlgDelete.Title = "Delete Backup" + dlgDelete.Indicator = Indicators.Danger + dlgDelete.ActionButton.Caption = "Delete" + dlgDelete.CancelButton.Visible = True + dlgDelete.Message = "Are you sure you want to delete Backup '" + backupDate.ToString(DateTime.FormatStyles.Medium, DateTime.FormatStyles.Medium) + "' of Database " + databasename + "?" + dlgDelete.Explanation = "This action cannot be undone." + + esActionDatabasename = databasename + esActionTimestamp = timestamp + + dlgDelete.ShowWithActionDanger() + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ActionDeleteButtonPressed(obj As WebMessageDialog, button As WebMessageDialogButton) + If (button <> obj.ActionButton) Then Return + If (esActionTimestamp = "") Or (esActionDatabasename = "") Then Return + + pgrWheel.Visible = True + + thrDelete.Start + timThread.RunMode = WebTimer.RunModes.Multiple + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ActionDownload() + If Me.IsThreadRunning Then Return + + Var databasename As String = Me.GetSelectedDatabasename() + Var timestamp As String = Me.GetSelectedTimestamp() + If (databasename = "") Or (timestamp = "") Then Return + + esActionDatabasename = databasename + esActionTimestamp = timestamp + + pgrWheel.Visible = True + + timDownload.RunMode = WebTimer.RunModes.Multiple + thrDownload.Start + timThread.RunMode = WebTimer.RunModes.Multiple + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ActionDownloadStarted(file As WebFile) + If (file = Me.Download) Then + Me.Download = Nil + End If + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ActionRestore() + If Me.IsThreadRunning Then Return + + Var databasename As String = Me.GetSelectedDatabasename() + Var timestamp As String = Me.GetSelectedTimestamp() + If (databasename = "") Or (timestamp = "") Then Return + + Var backupDate As DateTime = Me.GetDateTimeFromTimestamp(timestamp) + + dlgRestore.Title = "Restore Backup" + dlgRestore.Indicator = Indicators.Danger + dlgRestore.ActionButton.Caption = "Restore" + dlgRestore.CancelButton.Visible = True + dlgRestore.Message = "Are you sure you want to restore database " + databasename+ " from Backup '" + backupDate.ToString(DateTime.FormatStyles.Medium, DateTime.FormatStyles.Medium) + "' ?" + dlgRestore.Explanation = "This action cannot be undone." + + esActionDatabasename = databasename + esActionTimestamp = timestamp + + dlgRestore.ShowWithActionWarning() + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ActionRestoreButtonPressed(obj As WebMessageDialog, button As WebMessageDialogButton) + If (button <> obj.ActionButton) Then Return + If (esActionTimestamp = "") Or (esActionDatabasename = "") Then Return + + pgrWheel.Visible = True + + thrRestore.Start + timThread.RunMode = WebTimer.RunModes.Multiple + + End Sub + #tag EndMethod + + #tag Method, Flags = &h0 + Sub Constructor() + Super.Constructor + + Me.Area = "Data" + Me.Title = "Backups" + + + Redim Me.Columns(-1) + + Var col As DatasourceColumn + + col = New DatasourceColumn() + col.Width = "50%" + col.DatabaseColumnName = "timestamp" + col.Heading = "Date" + col.FieldType = DatasourceColumn.FieldTypes.Text + col.Sortable = True + col.SortDirection = WebListBox.SortDirections.Descending + Me.Columns.Add(col) + + col = New DatasourceColumn() + col.Width = "50%" + col.DatabaseColumnName = "virtualtime" + col.Heading = "Time" + col.FieldType = DatasourceColumn.FieldTypes.Text + col.Sortable = False + col.IsVirtual = True + col.SortDirection = WebListBox.SortDirections.None + Me.Columns.Add(col) + + End Sub + #tag EndMethod + + #tag Method, Flags = &h1 + Protected Function GetColumnData(col As DatasourceColumn, row As Dictionary) As Variant + Select Case col.DatabaseColumnName + + Case "timestamp", "virtualtime" + Var sTimestamp As String = row.Lookup("timestamp", "19000101_000000").StringValue + Var timestamp As DateTime = Me.GetDateTimeFromTimestamp(sTimestamp) + + Select Case col.DatabaseColumnName + Case "timestamp" + Return timestamp.ToString(DateTime.FormatStyles.Long, DateTime.FormatStyles.None) + Case "virtualtime" + Return timestamp.ToString(DateTime.FormatStyles.None, DateTime.FormatStyles.Medium) + End Select + + + Else + Return Super.GetColumnData(col, row) + + End Select + + End Function + #tag EndMethod + + #tag Method, Flags = &h21 + Private Function GetDateTimeFromTimestamp(psTimestamp As String) As DateTime + Var iYear As Integer = psTimestamp.Middle(0, 4).ToInteger + Var iMonth As Integer = psTimestamp.Middle(4, 2).ToInteger + Var iDay As Integer = psTimestamp.Middle(6, 2).ToInteger + + Var iHour As Integer = psTimestamp.Middle(9, 2).ToInteger + Var iMinute As Integer = psTimestamp.Middle(11, 2).ToInteger + Var iSecond As Integer = psTimestamp.Middle(13, 2).ToInteger + + Var utcDateTimeValue As DateTime = New DateTime(iYear, iMonth, iDay, iHour, iMinute, iSecond, 0, New TimeZone("UTC")) + Var localDateTimeValue As New DateTime(utcDateTimeValue.SecondsFrom1970, Timezone.Current) + + Return localDateTimeValue + + End Function + #tag EndMethod + + #tag Method, Flags = &h21 + Private Function GetSelectedDatabasename() As String + If (lstFilterDatabase.SelectedRowIndex < 0) Then Return "" + Return lstFilterDatabase.RowTagAt(lstFilterDatabase.SelectedRowIndex) + + End Function + #tag EndMethod + + #tag Method, Flags = &h21 + Private Function GetSelectedTimestamp() As String + If (lstInfos.SelectedRowIndex < 0) Then Return "" + + Var selectedRowTag As Variant = lstInfos.RowTagAt(lstInfos.SelectedRowIndex) + If (selectedRowTag IsA Dictionary) Then + Return Dictionary(selectedRowTag).Lookup("timestamp", "").StringValue + End If + + Return "" + + End Function + #tag EndMethod + + #tag Method, Flags = &h21 + Private Function IsThreadRunning() As Boolean + If (thrBackup.ThreadState <> Thread.ThreadStates.NotRunning) Then Return True + If (thrDelete.ThreadState <> Thread.ThreadStates.NotRunning) Then Return True + If (thrDownload.ThreadState <> Thread.ThreadStates.NotRunning) Then Return True + If (thrRestore.ThreadState <> Thread.ThreadStates.NotRunning) Then Return True + Return False + + End Function + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub Load() + Me.LoadDatabases() + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub LoadDatabases() + lstFilterDatabase.RemoveAllRows + + Try + Var rs As RowSet = Session.DB.SelectSQL("SHOW DATABASES") + If (rs = Nil) Then Return + + If (rs.RowCount > 0) Then + rs.MoveToFirstRow + While (Not rs.AfterLastRow) + lstFilterDatabase.AddRow(rs.Column("databasename").StringValue, rs.Column("databasename").StringValue) + + rs.MoveToNextRow + Wend + End If + + rs.Close + + Catch DatabaseException + + Finally + If (lstFilterDatabase.RowCount > 0) Then lstFilterDatabase.SelectedRowIndex = 0 + + End Try + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub RefreshButtons() + Var bBackup, bDownload, bRestore, bDelete As Boolean + + Var timestamp As String = Me.GetSelectedTimestamp() + Var databasename As String = Me.GetSelectedDatabasename() + + bBackup = (databasename <> "") + + If (timestamp <> "") And (databasename <> "") Then + bDownload = True + bRestore = True + bDelete = True + End If + + If (btnBackup.Enabled <> bBackup) Then btnBackup.Enabled = bBackup + If (btnDownload.Enabled <> bDownload) Then btnDownload.Enabled = bDownload + If (btnRestore.Enabled <> bRestore) Then btnRestore.Enabled = bRestore + If (btnDelete.Enabled <> bDelete) Then btnDelete.Enabled = bDelete + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub ShowInfos() + Me.UpdateNoRowsMessage() + + Var filterDatabasename As String = Me.GetSelectedDatabasename() + + If (filterDatabasename <> "") Then + Me.LoadDatasource(Session.DB.SelectSQL("SHOW BACKUPS FOR DATABASE '" + filterDatabasename.EscapeSqlQuotes + "'")) + Else + Me.LoadDatasource(Nil) + End If + + + If (lstInfos.DataSource = Nil) Then + lstInfos.DataSource = Self + Else + lstInfos.ReloadData() + End If + + End Sub + #tag EndMethod + + #tag Method, Flags = &h21 + Private Sub UpdateNoRowsMessage() + Var sInfo As String = "No Backups" + + Var filterDatabasename As String = Me.GetSelectedDatabasename() + If (filterDatabasename <> "") Then + sInfo = sInfo + " for Database " + filterDatabasename + End If + + lstInfos.NoRowsMessage = sInfo + + End Sub + #tag EndMethod + + #tag Method, Flags = &h1 + Protected Sub WebTimer_RowDataLoaded(obj As WebTimer) + Super.WebTimer_RowDataLoaded(obj) + + If (esSelectAfterReload = "") Then + Me.RefreshButtons() + Return + End If + + Var sSelectAfterReload As String = esSelectAfterReload + esSelectAfterReload = "" + + Var bFound As Boolean = False + For i As Integer = lstInfos.LastRowIndex DownTo 0 + If (lstInfos.RowTagAt(i) IsA Dictionary) Then + Var rowTag As Dictionary = lstInfos.RowTagAt(i) + If (rowTag.Lookup("timestamp", "-").StringValue <> sSelectAfterReload) Then Continue + lstInfos.SelectedRowIndex = i + bFound = True + Exit 'Loop + End If + Next + + If (Not bFound) Then lstInfos.SelectedRowIndex = -1 + + Me.RefreshButtons() + + End Sub + #tag EndMethod + + + #tag Property, Flags = &h21 + Private Download As WebFile + #tag EndProperty + + #tag Property, Flags = &h21 + Private ebOpened As Boolean + #tag EndProperty + + #tag Property, Flags = &h21 + Private ebReloadAfterThread As Boolean + #tag EndProperty + + #tag Property, Flags = &h21 + Private esActionDatabasename As String + #tag EndProperty + + #tag Property, Flags = &h21 + Private esActionTimestamp As String + #tag EndProperty + + #tag Property, Flags = &h21 + Private esSelectAfterReload As String + #tag EndProperty + + +#tag EndWindowCode + +#tag Events lstInfos + #tag Event + Sub SelectionChanged(rows() As Integer) + #Pragma unused rows + + Self.RefreshButtons() + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events btnDelete + #tag Event + Sub Pressed() + Self.ActionDelete() + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events btnBackup + #tag Event + Sub Pressed() + Self.ActionBackup() + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events btnRestore + #tag Event + Sub Pressed() + Self.ActionRestore() + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events dlgDelete + #tag Event + Sub ButtonPressed(button As WebMessageDialogButton) + Self.ActionDeleteButtonPressed(Me, button) + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events lstFilterDatabase + #tag Event + Sub SelectionChanged(item As WebMenuItem) + #Pragma unused item + + If (Not ebOpened) Then Return + + Self.ShowInfos() + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events thrBackup + #tag Event + Sub Run() + Var Databasename As String = esActionDatabasename + + If (Databasename = "") Then + esActionTimestamp = "" + esActionDatabasename = "" + Return + End If + + Try + + Session.DB.ExecuteSQL("BACKUP NOW '" + Databasename.EscapeSqlQuotes + "'") + + Me.SleepAndYieldToNext 100 + + Me.AddUserInterfaceUpdate("Success" : True) + + esSelectAfterReload = "" + Try + Var rs As RowSet = Session.DB.SelectSQL("SHOW BACKUPS FOR DATABASE '" + esActionDatabasename.EscapeSqlQuotes + "'") + If (rs <> Nil) Then + + If (rs.RowCount > 0) Then + rs.MoveToFirstRow + esSelectAfterReload = rs.Column("timestamp").StringValue + End If + + rs.Close + End If + + Catch DatabaseException + esSelectAfterReload = "" + + End Try + + + Catch err As DatabaseException + + Me.AddUserInterfaceUpdate("Error" : "Error" + If(err.ErrorNumber > 0, " " + err.ErrorNumber.ToString, "") + ": " + err.Message) + + End Try + + esActionTimestamp = "" + esActionDatabasename = "" + ebReloadAfterThread = True + + End Sub + #tag EndEvent + #tag Event + Sub UserInterfaceUpdate(data() As Dictionary) + For Each update As Dictionary In data + + If update.HasKey("Success") Then + 'nothing to do + End If + + If update.HasKey("Error") Then + Var dialog As New WebMessageDialog + dialog.Title = "Backup Database" + dialog.Indicator = Indicators.Warning + dialog.ActionButton.Caption = "OK" + dialog.CancelButton.Visible = False + dialog.Message = "Could not backup database." + dialog.Explanation = update.Lookup("Error", "").StringValue + dialog.Show + End If + + Next + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events thrDelete + #tag Event + Sub Run() + Var sDeleteTimestamp As String = esActionTimestamp + Var sDeleteFromDatabase As String = esActionDatabasename + + If (sDeleteTimestamp = "") Or (sDeleteFromDatabase = "") Then + esActionTimestamp = "" + esActionDatabasename = "" + Return + End If + + Try + + Session.DB.ExecuteSQL("DROP BACKUP FOR DATABASE '" + sDeleteFromDatabase.EscapeSqlQuotes + "' WITH TIMESTAMP '" + sDeleteTimestamp.EscapeSqlQuotes + "'") + + Me.AddUserInterfaceUpdate("Success" : True) + + Catch err As DatabaseException + + Me.AddUserInterfaceUpdate("Error" : "Error" + If(err.ErrorNumber > 0, " " + err.ErrorNumber.ToString, "") + ": " + err.Message) + + End Try + + esActionTimestamp = "" + esActionDatabasename = "" + ebReloadAfterThread = True + + End Sub + #tag EndEvent + #tag Event + Sub UserInterfaceUpdate(data() As Dictionary) + For Each update As Dictionary In data + + If update.HasKey("Success") Then + 'nothing to do + End If + + If update.HasKey("Error") Then + Var dialog As New WebMessageDialog + dialog.Title = "Delete Backup" + dialog.Indicator = Indicators.Warning + dialog.ActionButton.Caption = "OK" + dialog.CancelButton.Visible = False + dialog.Message = "Could not delete backup." + dialog.Explanation = update.Lookup("Error", "").StringValue + dialog.Show + End If + + Next + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events thrRestore + #tag Event + Sub Run() + Var sRestoreTimestamp As String = esActionTimestamp + Var sRestoreFromDatabase As String = esActionDatabasename + + If (sRestoreTimestamp = "") Or (sRestoreFromDatabase = "") Then + esActionTimestamp = "" + esActionDatabasename = "" + Return + End If + + Try + + Session.DB.ExecuteSQL("RESTORE BACKUP FOR DATABASE '" + sRestoreFromDatabase.EscapeSqlQuotes + "' WITH TIMESTAMP '" + sRestoreTimestamp + "'") + + Me.AddUserInterfaceUpdate("Success" : True) + + Catch err As DatabaseException + + Me.AddUserInterfaceUpdate("Error" : "Error" + If(err.ErrorNumber > 0, " " + err.ErrorNumber.ToString, "") + ": " + err.Message) + + End Try + + esActionTimestamp = "" + esActionDatabasename = "" + ebReloadAfterThread = False + + End Sub + #tag EndEvent + #tag Event + Sub UserInterfaceUpdate(data() As Dictionary) + For Each update As Dictionary In data + + If update.HasKey("Success") Then + 'nothing to do + End If + + If update.HasKey("Error") Then + Var dialog As New WebMessageDialog + dialog.Title = "Restore Backup" + dialog.Indicator = Indicators.Warning + dialog.ActionButton.Caption = "OK" + dialog.CancelButton.Visible = False + dialog.Message = "Could not restore backup." + dialog.Explanation = update.Lookup("Error", "").StringValue + dialog.Show + End If + + Next + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events dlgRestore + #tag Event + Sub ButtonPressed(button As WebMessageDialogButton) + Self.ActionRestoreButtonPressed(Me, button) + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events btnDownload + #tag Event + Sub Pressed() + Self.ActionDownload() + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events thrDownload + #tag Event + Sub Run() + Self.Download = Nil + + Var sDownloadTimestamp As String = esActionTimestamp + Var sDownloadFromDatabase As String = esActionDatabasename + + If (sDownloadTimestamp = "") Or (sDownloadFromDatabase = "") Then + esActionTimestamp = "" + esActionDatabasename = "" + Return + End If + + Var iDbTimeout As Integer = Session.DB.Timeout + Var bSuccess As Boolean = False + Var prepareDownload As WebFile + + Try + Session.DB.Timeout = 600 'a long Timeout for Download + Session.DB.ExecuteSQL("DOWNLOAD BACKUP DATABASE '" + sDownloadFromDatabase.EscapeSqlQuotes + "' WITH TIMESTAMP '" + sDownloadTimestamp.EscapeSqlQuotes + "'") + + Var data As New MemoryBlock(1) 'we don't know the size - let the MemoryBlock increase as needed + Dim bs As New BinaryStream(data) + ' call ReceiveChunk in a loop until all chunks have been received + While True + ' read the next chunk from the server + Dim chunk As String = Session.DB.ReceiveChunk + + ' there was an error receving a chunk, report the error and bail + If Session.DB.Error Then + Var errorMessage As String = Session.DB.ErrMsg + If (errorMessage = "") Then errorMessage = "Unknown Error while downloading..." + Raise New DatabaseException(errorMessage, Session.DB.ErrCode) + End If + + ' see if we have reached the end of the chunks and exit the loop if we have + If Session.DB.EndChunk Or (chunk.Bytes = 0) Then + bSuccess = True + bs.Close + Exit 'Loop + End If + + ' write the chunk out to the stream and loop again + bs.Write chunk + + Me.YieldToNext + Wend + + If (Not bSuccess) Then + Raise New DatabaseException("Unknown Error while downloading...", -1) + End If + + prepareDownload = New WebFile + prepareDownload.MimeType = "application/octet-stream" + prepareDownload.ForceDownload = True + prepareDownload.FileName = sDownloadFromDatabase + "_" + sDownloadTimestamp + prepareDownload.Data = data + AddHandler prepareDownload.Downloaded, WeakAddressOf Self.ActionDownloadStarted + + Catch err As DatabaseException + + Me.AddUserInterfaceUpdate("Error" : "Error" + If(err.ErrorNumber > 0, " " + err.ErrorNumber.ToString, "") + ": " + err.Message) + + Finally + Session.DB.Timeout = iDbTimeout + + End Try + + esActionTimestamp = "" + esActionDatabasename = "" + ebReloadAfterThread = False + + If (prepareDownload <> Nil) Then + Self.Download = prepareDownload + End If + + + End Sub + #tag EndEvent + #tag Event + Sub UserInterfaceUpdate(data() As Dictionary) + For Each update As Dictionary In data + + If update.HasKey("Success") Then + 'nothing to do + End If + + If update.HasKey("Error") Then + Var dialog As New WebMessageDialog + dialog.Title = "Download Backup" + dialog.Indicator = Indicators.Warning + dialog.ActionButton.Caption = "OK" + dialog.CancelButton.Visible = False + dialog.Message = "Could not download backup." + dialog.Explanation = update.Lookup("Error", "").StringValue + dialog.Show + End If + + Next + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events timDownload + #tag Event + Sub Run() + If (Self.Download = Nil) Then Return + + Me.RunMode = WebTimer.RunModes.Off + + Session.GoToURL(Self.Download.URL) + + End Sub + #tag EndEvent +#tag EndEvents +#tag Events timThread + #tag Event + Sub Run() + If (Self.IsThreadRunning) Then Return + + Me.RunMode = WebTimer.RunModes.Off + + pgrWheel.Visible = False + + If ebReloadAfterThread Then + Self.ShowInfos() + End If + + + End Sub + #tag EndEvent +#tag EndEvents +#tag ViewBehavior + #tag ViewProperty + Name="Area" + Visible=false + Group="Behavior" + InitialValue="Home" + Type="String" + EditorType="MultiLineEditor" + #tag EndViewProperty + #tag ViewProperty + Name="SearchAvailable" + Visible=false + Group="Behavior" + InitialValue="False" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="_mPanelIndex" + Visible=false + Group="Behavior" + InitialValue="-1" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="ControlCount" + Visible=false + Group="Behavior" + InitialValue="" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Name" + Visible=true + Group="ID" + InitialValue="" + Type="String" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Super" + Visible=true + Group="ID" + InitialValue="" + Type="String" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Left" + Visible=true + Group="Position" + InitialValue="0" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Top" + Visible=true + Group="Position" + InitialValue="0" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="ControlID" + Visible=false + Group="Behavior" + InitialValue="" + Type="String" + EditorType="MultiLineEditor" + #tag EndViewProperty + #tag ViewProperty + Name="Enabled" + Visible=true + Group="Behavior" + InitialValue="True" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="LockBottom" + Visible=true + Group="Behavior" + InitialValue="False" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="LockHorizontal" + Visible=true + Group="Behavior" + InitialValue="False" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="LockLeft" + Visible=true + Group="Behavior" + InitialValue="True" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="LockRight" + Visible=true + Group="Behavior" + InitialValue="False" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="LockTop" + Visible=true + Group="Behavior" + InitialValue="True" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="LockVertical" + Visible=true + Group="Behavior" + InitialValue="False" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Visible" + Visible=true + Group="Behavior" + InitialValue="" + Type="Boolean" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="_mDesignHeight" + Visible=false + Group="Behavior" + InitialValue="" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="_mDesignWidth" + Visible=false + Group="Behavior" + InitialValue="" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="_mName" + Visible=false + Group="Behavior" + InitialValue="" + Type="String" + EditorType="MultiLineEditor" + #tag EndViewProperty + #tag ViewProperty + Name="ScrollDirection" + Visible=true + Group="Behavior" + InitialValue="ScrollDirections.None" + Type="WebContainer.ScrollDirections" + EditorType="Enum" + #tag EnumValues + "0 - None" + "1 - Horizontal" + "2 - Vertical" + "3 - Both" + #tag EndEnumValues + #tag EndViewProperty + #tag ViewProperty + Name="TabIndex" + Visible=true + Group="Visual Controls" + InitialValue="" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Indicator" + Visible=false + Group="Visual Controls" + InitialValue="" + Type="WebUIControl.Indicators" + EditorType="Enum" + #tag EnumValues + "0 - Default" + "1 - Primary" + "2 - Secondary" + "3 - Success" + "4 - Danger" + "5 - Warning" + "6 - Info" + "7 - Light" + "8 - Dark" + "9 - Link" + #tag EndEnumValues + #tag EndViewProperty + #tag ViewProperty + Name="LayoutType" + Visible=true + Group="View" + InitialValue="LayoutTypes.Fixed" + Type="LayoutTypes" + EditorType="Enum" + #tag EnumValues + "0 - Fixed" + "1 - Flex" + #tag EndEnumValues + #tag EndViewProperty + #tag ViewProperty + Name="LayoutDirection" + Visible=true + Group="View" + InitialValue="LayoutDirections.LeftToRight" + Type="LayoutDirections" + EditorType="Enum" + #tag EnumValues + "0 - LeftToRight" + "1 - RightToLeft" + "2 - TopToBottom" + "3 - BottomToTop" + #tag EndEnumValues + #tag EndViewProperty + #tag ViewProperty + Name="Title" + Visible=false + Group="Behavior" + InitialValue="" + Type="String" + EditorType="MultiLineEditor" + #tag EndViewProperty + #tag ViewProperty + Name="Width" + Visible=false + Group="" + InitialValue="250" + Type="Integer" + EditorType="" + #tag EndViewProperty + #tag ViewProperty + Name="Height" + Visible=false + Group="" + InitialValue="250" + Type="Integer" + EditorType="" + #tag EndViewProperty +#tag EndViewBehavior diff --git a/webapp/containers/server/cntDatabases.xojo_code b/webapp/containers/data/cntDatabases.xojo_code similarity index 98% rename from webapp/containers/server/cntDatabases.xojo_code rename to webapp/containers/data/cntDatabases.xojo_code index 4701f4f..cc630e0 100644 --- a/webapp/containers/server/cntDatabases.xojo_code +++ b/webapp/containers/data/cntDatabases.xojo_code @@ -247,8 +247,8 @@ End Try - Var sqlCreateDb As String = "CREATE DATABASE " + "'" + Name + "'" - If (Key <> "") Then sqlCreateDb = sqlCreateDb + " WITH KEY " + "'" + Key + "'" + Var sqlCreateDb As String = "CREATE DATABASE '" + Name.EscapeSqlQuotes + "'" + If (Key <> "") Then sqlCreateDb = sqlCreateDb + " WITH KEY '" + Key.EscapeSqlQuotes + "'" If (Encoding <> "UTF-8") Then sqlCreateDb = sqlCreateDb + " WITH ENCODING " + Encoding Session.DB.ExecuteSQL(sqlCreateDb) @@ -302,7 +302,7 @@ End If (sDropDatabasename = "") Then Return Try - Session.DB.ExecuteSQL("DROP DATABASE '" + sDropDatabasename + "' IF EXISTS") + Session.DB.ExecuteSQL("DROP DATABASE '" + sDropDatabasename.EscapeSqlQuotes + "' IF EXISTS") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -346,7 +346,7 @@ End Try - Session.DB.ExecuteSQL("RENAME DATABASE '" + esActionDatabasename + "' TO " + "'" + Name + "'") + Session.DB.ExecuteSQL("RENAME DATABASE '" + esActionDatabasename.EscapeSqlQuotes + "' TO '" + Name.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -374,7 +374,7 @@ End If (databasename = "") Then Return Try - Session.DB.ExecuteSQL("START DATABASE '" + databasename + "'") + Session.DB.ExecuteSQL("START DATABASE '" + databasename.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -400,7 +400,7 @@ End If (databasename = "") Then Return Try - Session.DB.ExecuteSQL("STOP DATABASE '" + databasename + "'") + Session.DB.ExecuteSQL("STOP DATABASE '" + databasename.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -424,7 +424,7 @@ End Sub Constructor() Super.Constructor - Me.Area = "Server" + Me.Area = "Data" Me.Title = "Databases" Me.SearchAvailable = True diff --git a/webapp/containers/security/cntEnginePreferences.xojo_code b/webapp/containers/security/cntEnginePreferences.xojo_code index bc7f824..b05c752 100644 --- a/webapp/containers/security/cntEnginePreferences.xojo_code +++ b/webapp/containers/security/cntEnginePreferences.xojo_code @@ -425,7 +425,7 @@ End Var prefDb As String = dictDropEnginePreference.Lookup("databasename", "") Var prefKey As String = dictDropEnginePreference.Lookup("key", "") - Var sql As String = "DROP ENGINE PREFERENCE '" + prefEngine + "' FOR '" + prefDB + "' GROUP '" + prefGroup + "' KEY '" + prefKey + "'" + Var sql As String = "DROP ENGINE PREFERENCE '" + prefEngine.EscapeSqlQuotes + "' FOR '" + prefDB.EscapeSqlQuotes + "' GROUP '" + prefGroup.EscapeSqlQuotes + "' KEY '" + prefKey.EscapeSqlQuotes + "'" Session.DB.ExecuteSQL(sql) @@ -488,7 +488,7 @@ End Try - Var sql As String = "SET ENGINE PREFERENCE '" + Engine + "' FOR '" + Database + "' GROUP '" + Group + "' KEY '" + Key+ "' VALUE '" + Value + "'" + Var sql As String = "SET ENGINE PREFERENCE '" + Engine.EscapeSqlQuotes + "' FOR '" + Database.EscapeSqlQuotes + "' GROUP '" + Group.EscapeSqlQuotes + "' KEY '" + Key.EscapeSqlQuotes + "' VALUE '" + Value.EscapeSqlQuotes + "'" Session.DB.ExecuteSQL(sql) diff --git a/webapp/containers/security/cntGroups.xojo_code b/webapp/containers/security/cntGroups.xojo_code index 4b16971..8c827ee 100644 --- a/webapp/containers/security/cntGroups.xojo_code +++ b/webapp/containers/security/cntGroups.xojo_code @@ -201,7 +201,7 @@ End Try - Session.DB.ExecuteSQL("CREATE GROUP " + "'" + Name + "'") + Session.DB.ExecuteSQL("CREATE GROUP '" + Name.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -251,7 +251,7 @@ End If (sDropGroupname = "") Then Return Try - Session.DB.ExecuteSQL("DROP GROUP '" + sDropGroupname) + Session.DB.ExecuteSQL("DROP GROUP '" + sDropGroupname.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -295,7 +295,7 @@ End Try - Session.DB.ExecuteSQL("RENAME GROUP '" + esActionGroupname + "' TO " + "'" + Name + "'") + Session.DB.ExecuteSQL("RENAME GROUP '" + esActionGroupname.EscapeSqlQuotes + "' TO '" + Name.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -468,7 +468,7 @@ End groupname = dictRow.Lookup("groupname", "").StringValue if (groupname = "") then continue - Var rs As RowSet = Session.DB.SelectSQL("SHOW USERS IN GROUP '" + groupname + "'") + Var rs As RowSet = Session.DB.SelectSQL("SHOW USERS IN GROUP '" + groupname.EscapeSqlQuotes + "'") Var iCount As Integer = 0 Var sUsers() As String diff --git a/webapp/containers/security/cntPrivileges.xojo_code b/webapp/containers/security/cntPrivileges.xojo_code index d053ab0..356cba1 100644 --- a/webapp/containers/security/cntPrivileges.xojo_code +++ b/webapp/containers/security/cntPrivileges.xojo_code @@ -373,9 +373,9 @@ End Try - Var sql As String = "GRANT '" + Privilege + "' TO GROUP '" + Group + "'" - If (Database <> "*") And (Table <> "*") Then sql = sql + " FOR TABLE '" + Table + "' IN DATABASE '" + Database + "'" - If (Database <> "*") And (Table = "*") Then sql = sql + " FOR DATABASE '" + Database + "'" + Var sql As String = "GRANT '" + Privilege.EscapeSqlQuotes + "' TO GROUP '" + Group.EscapeSqlQuotes + "'" + If (Database <> "*") And (Table <> "*") Then sql = sql + " FOR TABLE '" + Table.EscapeSqlQuotes + "' IN DATABASE '" + Database.EscapeSqlQuotes + "'" + If (Database <> "*") And (Table = "*") Then sql = sql + " FOR DATABASE '" + Database.EscapeSqlQuotes + "'" Session.DB.ExecuteSQL(sql) @@ -467,9 +467,9 @@ End Var privDB As String = dictRevokePrivilege.Lookup("databasename", "") Var privTable As String = dictRevokePrivilege.Lookup("tablename", "") - Var sql As String = "REVOKE " + privName + " FROM GROUP '" + privGroup + "'" - If (privDB <> "*" And privTable = "*") Then sql = sql + " FOR DATABASE '" + privDB + "'" - If (privDB <> "*" And privTable <> "*") Then sql = sql + " FOR TABLE '" + privTable + "' IN DATABASE '" + privDB + "'" + Var sql As String = "REVOKE " + privName.EscapeSqlQuotes + " FROM GROUP '" + privGroup.EscapeSqlQuotes + "'" + If (privDB <> "*" And privTable = "*") Then sql = sql + " FOR DATABASE '" + privDB.EscapeSqlQuotes + "'" + If (privDB <> "*" And privTable <> "*") Then sql = sql + " FOR TABLE '" + privTable.EscapeSqlQuotes + "' IN DATABASE '" + privDB.EscapeSqlQuotes + "'" Session.DB.ExecuteSQL(sql) diff --git a/webapp/containers/security/cntUsers.xojo_code b/webapp/containers/security/cntUsers.xojo_code index 2ac17a5..560bdf6 100644 --- a/webapp/containers/security/cntUsers.xojo_code +++ b/webapp/containers/security/cntUsers.xojo_code @@ -395,10 +395,10 @@ End Try - Session.DB.ExecuteSQL("CREATE USER " + "'" + Name + "' WITH PASSWORD '" + Password + "'") + Session.DB.ExecuteSQL("CREATE USER '" + Name.EscapeSqlQuotes + "' WITH PASSWORD '" + Password.EscapeSqlQuotes + "'") If (Group <> "") Then - Session.DB.ExecuteSQL("ADD USER " + "'" + Name + "' TO GROUP '" + Group + "'") + Session.DB.ExecuteSQL("ADD USER '" + Name.EscapeSqlQuotes + "' TO GROUP '" + Group.EscapeSqlQuotes + "'") End If Catch err As DatabaseException @@ -465,7 +465,7 @@ End If (sDropUsername = "") Then Return Try - Session.DB.ExecuteSQL("DROP USER '" + sDropUsername) + Session.DB.ExecuteSQL("DROP USER '" + sDropUsername.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -531,7 +531,7 @@ End Try - Session.DB.ExecuteSQL("SET PASSWORD '" + Password + "' FOR USER " + "'" + Name) + Session.DB.ExecuteSQL("SET PASSWORD '" + Password.EscapeSqlQuotes + "' FOR USER '" + Name.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -577,7 +577,7 @@ End Try - Session.DB.ExecuteSQL("RENAME USER '" + esActionUsername + "' TO " + "'" + Name + "'") + Session.DB.ExecuteSQL("RENAME USER '" + esActionUsername + "' TO '" + Name.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -797,7 +797,7 @@ End Var username As String = dictRow.Lookup("username", "").StringValue if (username = "") then continue - Var rs As RowSet = Session.DB.SelectSQL("SHOW GROUPS FOR USER '" + username + "'") + Var rs As RowSet = Session.DB.SelectSQL("SHOW GROUPS FOR USER '" + username.EscapeSqlQuotes + "'") Var iCount As Integer = 0 Var sGroups() As String @@ -837,7 +837,7 @@ End If (filterGroupname = kGroupTagUnassigned) Then Me.LoadDatasource(Session.DB.SelectSQL("SHOW USERS IN GROUP ''")) Else - Me.LoadDatasource(Session.DB.SelectSQL("SHOW USERS IN GROUP '" + filterGroupname + "'")) + Me.LoadDatasource(Session.DB.SelectSQL("SHOW USERS IN GROUP '" + filterGroupname.EscapeSqlQuotes + "'")) End If Else Me.LoadDatasource(Session.DB.SelectSQL("SHOW USERS")) diff --git a/webapp/containers/server/cntConsole.xojo_code b/webapp/containers/server/cntConsole.xojo_code index 8181365..68745a1 100644 --- a/webapp/containers/server/cntConsole.xojo_code +++ b/webapp/containers/server/cntConsole.xojo_code @@ -379,7 +379,7 @@ End If (Me.SelectedRowIndex < 1) Then Session.DB.ExecuteSQL("CLEAR CURRENT DATABASE") Else - Session.DB.ExecuteSQL("USE DATABASE '" + Me.SelectedRowText + "'") + Session.DB.ExecuteSQL("USE DATABASE '" + Me.SelectedRowText.EscapeSqlQuotes + "'") End If diff --git a/webapp/containers/server/cntRegistrationAction.xojo_code b/webapp/containers/server/cntRegistrationAction.xojo_code index c1a9e89..87a8b62 100644 --- a/webapp/containers/server/cntRegistrationAction.xojo_code +++ b/webapp/containers/server/cntRegistrationAction.xojo_code @@ -165,9 +165,9 @@ End Try If Name.Contains("'", ComparisonOptions.CaseInsensitive) Then - Session.DB.ExecuteSQL("SET BASE64 REGISTRATION TO '" + EncodeBase64(Name) + "' WITH KEY '" + Key + "'") + Session.DB.ExecuteSQL("SET BASE64 REGISTRATION TO '" + EncodeBase64(Name).EscapeSqlQuotes + "' WITH KEY '" + Key.EscapeSqlQuotes + "'") Else - Session.DB.ExecuteSQL("SET REGISTRATION TO '" + Name + "' WITH KEY '" + Key + "'") + Session.DB.ExecuteSQL("SET REGISTRATION TO '" + Name.EscapeSqlQuotes + "' WITH KEY '" + Key.EscapeSqlQuotes + "'") End If Catch err As DatabaseException diff --git a/webapp/dialogs/dlgPrivilegeGrant.xojo_code b/webapp/dialogs/dlgPrivilegeGrant.xojo_code index e2220f9..d2b3789 100644 --- a/webapp/dialogs/dlgPrivilegeGrant.xojo_code +++ b/webapp/dialogs/dlgPrivilegeGrant.xojo_code @@ -543,7 +543,7 @@ End lstTable.AddRow("-", "*") Try - Var rs As RowSet = Session.DB.SelectSQL("SHOW TABLES FOR DATABASE '" + databaseName + "'") + Var rs As RowSet = Session.DB.SelectSQL("SHOW TABLES FOR DATABASE '" + databaseName.EscapeSqlQuotes + "'") If (rs = Nil) Then Return If (rs.RowCount > 0) Then @@ -904,12 +904,4 @@ End "3 - BottomToTop" #tag EndEnumValues #tag EndViewProperty - #tag ViewProperty - Name="esPreSelectGroup" - Visible=false - Group="Behavior" - InitialValue="" - Type="String" - EditorType="MultiLineEditor" - #tag EndViewProperty #tag EndViewBehavior diff --git a/webapp/dialogs/dlgUserGroups.xojo_code b/webapp/dialogs/dlgUserGroups.xojo_code index 98fd282..2a71ba6 100644 --- a/webapp/dialogs/dlgUserGroups.xojo_code +++ b/webapp/dialogs/dlgUserGroups.xojo_code @@ -22,7 +22,6 @@ Begin WebDialog dlgUserGroups Width = 750 _mDesignHeight = 0 _mDesignWidth = 0 - _mName = "" _mPanelIndex = -1 Begin WebLabel labTitle Bold = True @@ -195,7 +194,7 @@ Begin WebDialog dlgUserGroups LockRight = True LockTop = False LockVertical = False - PanelIndex = 0 + PanelIndex = "0" Scope = 2 TabIndex = 4 TabStop = True @@ -285,7 +284,7 @@ End lstUserGroups.RemoveAllRows Try - Var rs As RowSet = Session.DB.SelectSQL("SHOW GROUPS FOR USER '" + esUsername + "'") + Var rs As RowSet = Session.DB.SelectSQL("SHOW GROUPS FOR USER '" + esUsername.EscapeSqlQuotes + "'") If (rs = Nil) Then Return If (rs.RowCount > 0) Then @@ -371,7 +370,7 @@ End Try - Session.DB.ExecuteSQL("ADD USER " + "'" + esUsername + "' TO GROUP '" + group + "'") + Session.DB.ExecuteSQL("ADD USER '" + esUsername.EscapeSqlQuotes + "' TO GROUP '" + group.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog @@ -439,7 +438,7 @@ End Try - Session.DB.ExecuteSQL("REMOVE USER " + "'" + esUsername + "' FROM GROUP '" + group + "'") + Session.DB.ExecuteSQL("REMOVE USER '" + esUsername.EscapeSqlQuotes + "' FROM GROUP '" + group.EscapeSqlQuotes + "'") Catch err As DatabaseException Var dialog As New WebMessageDialog diff --git a/webapp/main/CubeSQLAdminPage.xojo_code b/webapp/main/CubeSQLAdminPage.xojo_code index c1c5acd..7af853a 100644 --- a/webapp/main/CubeSQLAdminPage.xojo_code +++ b/webapp/main/CubeSQLAdminPage.xojo_code @@ -189,11 +189,14 @@ End Case ContainerKey.Registration showContainer = New cntRegistration + Case ContainerKey.Groups + showContainer = New cntGroups + Case ContainerKey.Databases showContainer = New cntDatabases - Case ContainerKey.Groups - showContainer = New cntGroups + Case ContainerKey.Backups + showContainer = New cntBackups Case ContainerKey.Users showContainer = New cntUsers @@ -262,10 +265,16 @@ End btn.Style = WebToolbarButton.ButtonStyles.Menu btn.Caption = "Server" btn.Menu.AddMenuItem(New WebMenuItem("Registration", ContainerKey.Registration)) - btn.Menu.AddMenuItem(New WebMenuItem("Databases", ContainerKey.Databases)) btn.Menu.AddMenuItem(New WebMenuItem("Console", ContainerKey.Console)) Me.AddItem(btn) + btn = New WebToolbarButton + btn.Style = WebToolbarButton.ButtonStyles.Menu + btn.Caption = "Data" + btn.Menu.AddMenuItem(New WebMenuItem("Databases", ContainerKey.Databases)) + btn.Menu.AddMenuItem(New WebMenuItem("Backups", ContainerKey.Backups)) + Me.AddItem(btn) + btn = New WebToolbarButton btn.Style = WebToolbarButton.ButtonStyles.Menu btn.Caption = "Security" diff --git a/webapp/modCubeSQLAdmin.xojo_code b/webapp/modCubeSQLAdmin.xojo_code index b76957a..d721230 100644 --- a/webapp/modCubeSQLAdmin.xojo_code +++ b/webapp/modCubeSQLAdmin.xojo_code @@ -1,5 +1,12 @@ #tag Module Protected Module modCubeSQLAdmin + #tag Method, Flags = &h0 + Function EscapeSqlQuotes(Extends sql As String) As String + Return sql.ReplaceAll("'", "''") + + End Function + #tag EndMethod + #tag Method, Flags = &h1 Protected Function LaunchArgumentGetValue(argKey As String, envKey As String, ByRef argValue As String) As Boolean // Gets the Launch Argument from @@ -14,6 +21,18 @@ Protected Module modCubeSQLAdmin End Function #tag EndMethod + #tag Method, Flags = &h0 + Sub SleepAndYieldToNext(Extends ThreadInstance As WebThread, Milliseconds As Integer) + Var SleepInterval As Integer = Milliseconds / 10 + + For i As Integer = 1 To 10 + ThreadInstance.Sleep SleepInterval + ThreadInstance.YieldToNext + Next + + End Sub + #tag EndMethod + #tag Method, Flags = &h1, Description = 436F6E766572747320636F6D6D616E64206C696E6520617267756D656E747320746F20612064696374696F6E6172792E2045616368206B657920697320616E20617267756D656E74206E616D6520616E642074686520636F72726573706F6E64696E672076616C75652069732074686520617267756D656E742076616C75652E Protected Sub StoreLaunchArguments(args() As String) dictArgs = New Dictionary @@ -61,15 +80,16 @@ Protected Module modCubeSQLAdmin None = -1 Status = 0 Registration=1 - Databases = 2 - Console = 3 - Groups = 11 - Users = 12 - Privileges = 13 - Commands = 21 - Clients = 22 - Log = 23 - EnginePreferences = 14 + Console = 2 + Databases = 11 + Backups = 12 + Groups = 21 + Users = 22 + Privileges = 23 + EnginePreferences = 24 + Commands = 31 + Clients = 32 + Log = 33 #tag EndEnum