diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/AssemblyInitializer.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/AssemblyInitializer.cs deleted file mode 100644 index 417e9244..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/AssemblyInitializer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using FastReport.Utils; - -namespace FastReport.Data -{ - public class GoogleAssemblyInitializer : AssemblyInitializerBase - { - public GoogleAssemblyInitializer() - { - RegisteredObjects.AddConnection(typeof(GoogleSheetsDataConnection)); - } - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleAuthService.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleAuthService.cs deleted file mode 100644 index 55eec019..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleAuthService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Google.Apis.Auth.OAuth2; -using Google.Apis.Sheets.v4; -using System; -using System.IO; -using System.Threading; - -namespace FastReport.Data -{ - public class GoogleAuthService - { - #region Public Methods - - /// - /// Getting a token by connecting to a .json file - /// - /// Path to the location of the .json file containing the Google client secret data - /// UserCredential with access token - public static UserCredential GetAccessToken(string path) - { - string[] scopes = new string[] { SheetsService.Scope.Spreadsheets }; - - using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) - { - var credential = GoogleWebAuthorizationBroker.AuthorizeAsync( - GoogleClientSecrets.FromStream(stream).Secrets, - scopes, - "userName", - CancellationToken.None).Result; - - return credential; - } - } - - /// - /// Getting a token over an OAuth 2.0 connection - /// - /// Google Client ID - /// Google Client Secret - /// UserCredential with access token - public static UserCredential GetAccessToken(string clientId, string clientSecret) - { - string[] scopes = new string[] { SheetsService.Scope.Spreadsheets }; - - var credential = GoogleWebAuthorizationBroker.AuthorizeAsync( - new ClientSecrets - { - ClientId = clientId, - ClientSecret = clientSecret - }, - scopes, - Environment.UserName, - CancellationToken.None).Result; - - return credential; - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheets.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheets.cs deleted file mode 100644 index 7b396c07..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheets.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Google.Apis.Auth.OAuth2; -using Google.Apis.Services; -using Google.Apis.Sheets.v4; -using Google.Apis.Sheets.v4.Data; -using System.Collections.Generic; -using System.Windows.Forms; - -namespace FastReport.Data -{ - /// - /// Provides connection, reading and writing data from Google Sheets - /// - public class GoogleSheets - { - #region Private Fields - - private static SheetsService service; - - #endregion Private Fields - - #region Public Method - - /// - /// Initializing the Sheets service with an Access Token - /// - /// Contains an access token for the Google Sheets API - public static void InitService(UserCredential credential) - { - service = new SheetsService(new BaseClientService.Initializer() - { - ApplicationName = " ", - HttpClientInitializer = credential, - }); - } - - /// - /// Initializing the Sheets service using an API key - /// - /// Contains an API key to access the Google Sheets API - /// SheetsService for performing operations with the Google Sheets API - public static SheetsService InitService(string APIkey) - { - service = new SheetsService(new BaseClientService.Initializer() - { - ApplicationName = " ", - ApiKey = APIkey, - }); - - return service; - } - - /// - /// Read data from a sheet specifying a range of cells - /// - /// Google Sheets Table ID - /// Range of cells to be read - /// A list of lists of objects (IList>) that contains the data read - public static IList> ReadData(string spreadsheetsId, string range) - { - var response = service.Spreadsheets.Values.Get(spreadsheetsId, range).Execute(); - - return response.Values; - } - - /// - /// Read data from a sheet specifying a range of cells - /// - /// Google Sheets Table ID - /// Range start column to be read - /// Range end column to be read - /// A list of lists of objects (IList>) that contains the data read - public static IList> ReadData(string spreadsheetsId, string startColumn, string endColumn) - { - var range = startColumn + ":" + endColumn; - - var response = service.Spreadsheets.Values.Get(spreadsheetsId, range).Execute(); - - return response.Values; - } - - /// - /// Reading data from a table - /// - /// Google Sheets Table ID - /// Returns a Spreadsheet with information about the table - public static Spreadsheet ReadSpreadSheet (string spreadsheetsId) - { - var spreadsheet = service.Spreadsheets.Get(spreadsheetsId).Execute(); - - return spreadsheet; - } - - #endregion Public Method - } -} \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.cs deleted file mode 100644 index 2cdd603b..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using FastReport.Data.ConnectionEditors; -using FastReport.Utils; - -namespace FastReport.Data -{ - internal partial class GoogleSheetsConnectionEditor : ConnectionEditorBase - { - #region Fields - - private bool updating; - - #endregion Fields - - #region Constructors - public GoogleSheetsConnectionEditor() - { - updating = true; - InitializeComponent(); - CheckSignInGoogleAPI(); - Localize(); - updating = false; - } - - #endregion Constructors - - #region Events Handlers - - private void btSignInGoogle_Click(object sender, EventArgs e) - { - using (SignInGoogle signInGoogle = new SignInGoogle()) - { - signInGoogle.ShowDialog(); - } - } - - #endregion Events Handlers - - #region Protected Methods - - protected override string GetConnectionString() - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(); - builder.Sheets = tbGoogleId.Text; - builder.FieldNamesInFirstString = cbxFieldNames.Checked; - return builder.ToString(); - } - - protected override void SetConnectionString(string value) - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(value); - tbGoogleId.Text = builder.Sheets; - cbxFieldNames.Checked = builder.FieldNamesInFirstString; - } - - #endregion Protected Methods - - #region Private Methods - - private void Localize() - { - MyRes res = new MyRes("ConnectionEditors,GoogleSheets"); - gbSelect.Text = res.Get("ConfigureDatabase"); - lblSelectGId.Text = res.Get("SelectSheetsId"); - cbxFieldNames.Text = res.Get("FieldNames"); - btSignInGoogle.Text = res.Get("SignIn"); - } - - private void CheckSignInGoogleAPI () - { - XmlItem xi = Config.Root.FindItem("GoogleSheets").FindItem("StorageSettings"); - string id = xi.GetProp("ClientId"); - string secret = xi.GetProp("ClientSecret"); - string pathToJson = xi.GetProp("PathToJson"); - string apiKey = xi.GetProp("ApiKey"); - if (String.IsNullOrEmpty(id) && String.IsNullOrEmpty(secret) && String.IsNullOrEmpty(pathToJson) && String.IsNullOrEmpty(apiKey)) - { - using (SignInGoogle signInGoogle = new SignInGoogle()) - signInGoogle.ShowDialog(); - } - } - - #endregion Private Methods - - #region Public Methods - - public override void UpdateDpiDependencies() - { - base.UpdateDpiDependencies(); - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.designer.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.designer.cs deleted file mode 100644 index 83a8b3fa..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.designer.cs +++ /dev/null @@ -1,107 +0,0 @@ -namespace FastReport.Data -{ - partial class GoogleSheetsConnectionEditor - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.gbSelect = new System.Windows.Forms.GroupBox(); - this.btSignInGoogle = new System.Windows.Forms.Button(); - this.cbxFieldNames = new System.Windows.Forms.CheckBox(); - this.tbGoogleId = new System.Windows.Forms.TextBox(); - this.lblSelectGId = new System.Windows.Forms.Label(); - this.gbSelect.SuspendLayout(); - this.SuspendLayout(); - // - // gbSelect - // - this.gbSelect.Controls.Add(this.btSignInGoogle); - this.gbSelect.Controls.Add(this.cbxFieldNames); - this.gbSelect.Controls.Add(this.tbGoogleId); - this.gbSelect.Controls.Add(this.lblSelectGId); - this.gbSelect.Location = new System.Drawing.Point(8, 4); - this.gbSelect.Name = "gbSelect"; - this.gbSelect.Size = new System.Drawing.Size(320, 135); - this.gbSelect.TabIndex = 1; - this.gbSelect.TabStop = false; - this.gbSelect.Text = "Select database file"; - // - // btSignInGoogle - // - this.btSignInGoogle.Location = new System.Drawing.Point(239, 106); - this.btSignInGoogle.Name = "btSignInGoogle"; - this.btSignInGoogle.Size = new System.Drawing.Size(75, 23); - this.btSignInGoogle.TabIndex = 8; - this.btSignInGoogle.Text = "Sign in"; - this.btSignInGoogle.UseVisualStyleBackColor = true; - this.btSignInGoogle.Click += new System.EventHandler(this.btSignInGoogle_Click); - // - // cbxFieldNames - // - this.cbxFieldNames.AutoSize = true; - this.cbxFieldNames.Location = new System.Drawing.Point(15, 73); - this.cbxFieldNames.Name = "cbxFieldNames"; - this.cbxFieldNames.Size = new System.Drawing.Size(174, 20); - this.cbxFieldNames.TabIndex = 7; - this.cbxFieldNames.Text = "Field names in first string"; - this.cbxFieldNames.UseVisualStyleBackColor = true; - // - // tbGoogleId - // - this.tbGoogleId.Location = new System.Drawing.Point(15, 36); - this.tbGoogleId.Name = "tbGoogleId"; - this.tbGoogleId.Size = new System.Drawing.Size(299, 22); - this.tbGoogleId.TabIndex = 1; - // - // lblSelectGId - // - this.lblSelectGId.AutoSize = true; - this.lblSelectGId.Location = new System.Drawing.Point(12, 20); - this.lblSelectGId.Name = "lblSelectGId"; - this.lblSelectGId.Size = new System.Drawing.Size(102, 16); - this.lblSelectGId.TabIndex = 0; - this.lblSelectGId.Text = "Select sheetsId:"; - // - // GoogleSheetsConnectionEditor - // - this.Controls.Add(this.gbSelect); - this.Name = "GoogleSheetsConnectionEditor"; - this.Size = new System.Drawing.Size(336, 145); - this.gbSelect.ResumeLayout(false); - this.gbSelect.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.GroupBox gbSelect; - private System.Windows.Forms.Label lblSelectGId; - private System.Windows.Forms.TextBox tbGoogleId; - private System.Windows.Forms.CheckBox cbxFieldNames; - private System.Windows.Forms.Button btSignInGoogle; - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.resx b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.resx deleted file mode 100644 index d58980a3..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionEditor.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionStringBuilder.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionStringBuilder.cs deleted file mode 100644 index f4426b4b..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsConnectionStringBuilder.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Data.Common; - -namespace FastReport.Data -{ - /// - /// Represents the GoogleDataConnection connection string builder. - /// - /// - /// Use this class to parse connection string returned by the GoogleDataConnection class. - /// - public class GoogleSheetsConnectionStringBuilder : DbConnectionStringBuilder - { - #region Properties - - /// - /// Gets or sets id Google Sheets. - /// - public string Sheets - { - get - { - object gSheets; - if (TryGetValue("GoogleSheets", out gSheets)) - { - return (string)gSheets; - } - return ""; - } - - set { base["GoogleSheets"] = value; } - } - - /// - /// Gets or sets table name. - /// - public string TableName - { - get - { - object tableName; - if (TryGetValue("TableName", out tableName)) - { - return (string)tableName; - } - return ""; - } - - set { base["TableName"] = value; } - } - - /// - /// Gets or sets first column in the Google Sheets. - /// - public string StartColumn - { - get - { - object startColumn; - if (TryGetValue("StartColumn", out startColumn)) - { - return (string)startColumn; - } - return ""; - } - - set { base["StartColumn"] = value; } - } - - /// - /// Gets or sets last column in the Google Sheets. - /// - public string EndColumn - { - get - { - object endColumn; - if (TryGetValue("EndColumn", out endColumn)) - { - return (string)endColumn; - } - return ""; - } - - set { base["EndColumn"] = value; } - } - - /// - /// Gets or sets the value indicating that field names should be loaded from the first string of the file. - /// - public bool FieldNamesInFirstString - { - get - { - object fieldNamesInFirstString; - if (TryGetValue("FieldNamesInFirstString", out fieldNamesInFirstString)) - { - return fieldNamesInFirstString.ToString().ToLower() == "true"; - } - return false; - } - set { base["FieldNamesInFirstString"] = value.ToString().ToLower(); } - } - - #endregion Properties - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public GoogleSheetsConnectionStringBuilder() - { - ConnectionString = ""; - } - - /// - /// Initializes a new instance of the class with a specified connection string. - /// - /// The connection string. - public GoogleSheetsConnectionStringBuilder(string connectionString) : base() - { - ConnectionString = connectionString; - } - - #endregion Constructors - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsDataConnection.DesignExt.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsDataConnection.DesignExt.cs deleted file mode 100644 index cc736ec9..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsDataConnection.DesignExt.cs +++ /dev/null @@ -1,34 +0,0 @@ -using FastReport.Data.ConnectionEditors; -using System.Data; -using System; - -namespace FastReport.Data -{ - public partial class GoogleSheetsDataConnection - { - #region Public Methods - - /// - public override void TestConnection() - { - using (DataSet dataset = CreateDataSet()) - { - - } - } - - /// - public override ConnectionEditorBase GetEditor() - { - return new GoogleSheetsConnectionEditor(); - } - - /// - public override string GetConnectionId() - { - return "GoogleSheets: " + Sheets; - } - - #endregion Public Methods - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsDataConnection.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsDataConnection.cs deleted file mode 100644 index 1b9b25fc..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsDataConnection.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Data.Common; -using System.Data; -using Google.Apis.Sheets.v4.Data; - -namespace FastReport.Data -{ - public partial class GoogleSheetsDataConnection : DataConnectionBase - { - #region Properties - /// - /// Gets or sets id Google Sheets. - /// - [Category("Data")] - public string Sheets - { - get - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - return builder.Sheets; - } - set - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - builder.Sheets = value; - ConnectionString = builder.ToString(); - } - } - - /// - /// Gets or sets table name. - /// - [Category("Data")] - public string TableName - { - get - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - return builder.TableName; - } - set - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - builder.TableName = value; - ConnectionString = builder.ToString(); - } - } - - /// - /// Gets or sets first column in the Google Sheets. - /// - [Category("Data")] - public string StartColumn - { - get - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - return builder.StartColumn; - } - set - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - builder.StartColumn = value; - ConnectionString = builder.ToString(); - } - } - - /// - /// Gets or sets last column in the Google Sheets. - /// - public string EndColumn - { - get - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - return builder.EndColumn; - } - set - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - builder.EndColumn = value; - ConnectionString = builder.ToString(); - } - } - - /// - /// Gets or sets the value indicating that field names should be loaded from the first string of the file. - /// - public bool FieldNamesInFirstString - { - get - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - return builder.FieldNamesInFirstString; - } - set - { - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - builder.FieldNamesInFirstString = value; - ConnectionString = builder.ToString(); - } - } - - #endregion Properties - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - public GoogleSheetsDataConnection() - { - IsSqlBased = false; - } - - #endregion Constructors - - #region Protected Methods - - /// - protected override DataSet CreateDataSet() - { - DataSet dataset = base.CreateDataSet(); - GoogleSheetsConnectionStringBuilder builder = new GoogleSheetsConnectionStringBuilder(ConnectionString); - Spreadsheet spreadsheet = GoogleSheetsUtils.ReadTable(builder); - - for (int i = 0; i < spreadsheet.Sheets.Count; i++) - { - builder.TableName = spreadsheet.Sheets[i].Properties.Title; - DataTable table = GoogleSheetsUtils.CreateDataTable(spreadsheet.SpreadsheetId, builder); - dataset.Tables.Add(table); - } - - return dataset; - } - - /// - protected override void SetConnectionString(string value) - { - DisposeDataSet(); - base.SetConnectionString(value); - } - - #endregion Protected Methods - - #region Public Methods - - /// - public override void FillTableSchema(DataTable table, string selectCommand, CommandParameterCollection parameters) - { - // do nothing - } - - /// - public override void FillTableData(DataTable table, string selectCommand, CommandParameterCollection parameters) - { - // do nothing - } - - /// - public override void CreateTable(TableDataSource source) - { - if (DataSet.Tables.Contains(source.TableName)) - { - source.Table = DataSet.Tables[source.TableName]; - base.CreateTable(source); - } - else - { - source.Table = null; - } - } - - /// - public override void DeleteTable(TableDataSource source) - { - // do nothing - } - - /// - public override string QuoteIdentifier(string value, DbConnection connection) - { - return value; - } - - /// - public override string[] GetTableNames() - { - string[] result = new string[DataSet.Tables.Count]; - for (int i = 0; i < DataSet.Tables.Count; i++) - { - result[i] = DataSet.Tables[i].TableName; - } - return result; - } - #endregion Public Methods - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsUtils.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsUtils.cs deleted file mode 100644 index c977640a..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/GoogleSheetsUtils.cs +++ /dev/null @@ -1,125 +0,0 @@ -using FastReport.Utils; -using Google.Apis.Sheets.v4.Data; -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; - -namespace FastReport.Data -{ - internal static class GoogleSheetsUtils - { - /// - /// The default field name. - /// - private const string DEFAULT_FIELD_NAME = "Field"; - - /// - /// Maximum speaker range. - /// - private const string ALL_RANGE = "!A:ZZZ"; - - internal static Spreadsheet ReadTable(GoogleSheetsConnectionStringBuilder builder) - { - XmlItem xi = Config.Root.FindItem("GoogleSheets").FindItem("StorageSettings"); - string id = xi.GetProp("ClientId"); - string secret = xi.GetProp("ClientSecret"); - string pathToJson = xi.GetProp("PathToJson"); - string apiKey = xi.GetProp("ApiKey"); - - // checking for empty account data - if (!String.IsNullOrEmpty(apiKey)) - GoogleSheets.InitService(apiKey); - else if (!String.IsNullOrEmpty(pathToJson)) - GoogleSheets.InitService(GoogleAuthService.GetAccessToken(pathToJson)); - else if (!String.IsNullOrEmpty(id) && !String.IsNullOrEmpty(secret)) - GoogleSheets.InitService(GoogleAuthService.GetAccessToken(id, secret)); - else - throw new Exception(Res.Get("ConnectionEditors,GoogleSheets,FailedToLogin")); - - // checking for an empty URL string - if (String.IsNullOrEmpty(builder.Sheets)) - throw new Exception(Res.Get("ConnectionEditors,Common,OnlyUrlException")); - - string gId = builder.Sheets; - - if (builder.Sheets.StartsWith("https://docs.google.com/spreadsheets/d/")) - { - string idGoogle = builder.Sheets.Remove(0, 39); - int startIndex = idGoogle.IndexOf("/"); - - if (startIndex == -1) - throw new Exception(Res.Get("ConnectionEditors,Common,OnlyUrlException")); - - gId = idGoogle.Substring(0, startIndex); - } - - var objects = GoogleSheets.ReadSpreadSheet(gId); - - return objects; - } - - internal static DataTable CreateDataTable(string spreadSheetsId, GoogleSheetsConnectionStringBuilder builder) - { - //Receiving a sheet - var rawLines = GoogleSheets.ReadData(spreadSheetsId, builder.TableName + ALL_RANGE); - - if (rawLines == null) - return null; - - //maxCount is needed to determine the maximum number of cells in the row width - int maxCount = rawLines.Max(l => l.Count); - DataTable table = new DataTable(builder.TableName); - - //Adding empty columns to align the first row - for (int i = 0; i < maxCount; i++) - if (rawLines[0].Count < maxCount) - rawLines[0].Add(""); - - if (builder.FieldNamesInFirstString == true) - { - foreach (var column in rawLines[0]) - { - table.Columns.Add(column.ToString()); - } - for (int i = 1; i < rawLines.Count; i++) - { - var row = rawLines[i]; - var dataRow = table.NewRow(); - - for (int j = 0; j < row.Count; j++) - { - dataRow[j] = row[j].ToString(); - } - - table.Rows.Add(dataRow); - } - } - else - { - int count = 0; - - foreach (var column in rawLines[0]) - { - table.Columns.Add(DEFAULT_FIELD_NAME + count.ToString()); - count++; - } - - for (int i = 1; i < rawLines.Count; i++) - { - var row = rawLines[i]; - var dataRow = table.NewRow(); - - for (int j = 0; j < row.Count; j++) - { - dataRow[j] = row[j].ToString(); - } - - table.Rows.Add(dataRow); - } - } - - return table; - } - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/Shared.props b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/Shared.props deleted file mode 100644 index e30cd4ba..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/Shared.props +++ /dev/null @@ -1,22 +0,0 @@ - - - FastReport.Data.GoogleSheets - FastReport.Data.GoogleSheets - - - - - - - - - - - - - true - false - Never - - - \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.cs deleted file mode 100644 index 50225264..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.Windows.Forms; -using FastReport.Forms; -using FastReport.Utils; -using Google.Apis.Auth.OAuth2; - -namespace FastReport.Data -{ - internal partial class SignInGoogle : BaseDialogForm - { - #region Fields - - private string apiKey; - private string clientId; - private string clientSecret; - private string pathToJson; - private bool isUserAuthorized; - - #endregion Fields - - #region Properties - - /// - /// Gets or sets user's api key. - /// - public string ApiKey - { - get { return apiKey; } - set { apiKey = value; } - } - - /// - /// Gets or sets client identifier from the OAuth2 specification. - /// - public string ClientId - { - get { return clientId; } - set { clientId = value; } - } - - /// - /// Gets or sets client secret from the OAuth2 specification. - /// - public string ClientSecret - { - get { return clientSecret; } - set { clientSecret = value; } - } - - /// - /// Gets or sets client file .json from the OAuth2 specification. - /// - public string PathToJson - { - get { return pathToJson; } - set { pathToJson = value; } - } - - /// - /// Gets or sets the information is user authorized or not. - /// - public bool IsUserAuthorized - { - get { return isUserAuthorized; } - set { isUserAuthorized = value; } - } - - #endregion Properties - - #region Constructors - public SignInGoogle() - { - this.clientId = ""; - this.clientSecret = ""; - this.pathToJson = ""; - this.apiKey = ""; - this.isUserAuthorized = false; - - InitializeComponent(); - Localize(); - InitSignInList(); - UIUtils.CheckRTL(this); - UpdateDpiDependencies(); - } - - #endregion Constructors - - #region Events Handlers - - private void tbPathToJsonFile_ButtonClick(object sender, EventArgs e) - { - using (OpenFileDialog dialog = new OpenFileDialog()) - { - dialog.Filter = Res.Get("FileFilters,JsonFile"); - if (dialog.ShowDialog() == DialogResult.OK) - tbPathToJsonFile.Text = dialog.FileName; - } - } - - private void cbxPathToJsonFile_CheckedChanged(object sender, EventArgs e) - { - if (cbxPathToJsonFile.Checked) - { - lblPath.Visible = true; - lblClientId.Visible = false; - lblClientSecret.Visible = false; - - tbPathToJsonFile.Visible = true; - tbClientId.Visible = false; - tbClientSecret.Visible = false; - } - else - { - lblPath.Visible = false; - lblClientId.Visible = true; - lblClientSecret.Visible = true; - - tbPathToJsonFile.Visible = false; - tbClientId.Visible = true; - tbClientSecret.Visible = true; - } - } - - private void btnSignIn_Click(object sender, EventArgs e) - { - if (!String.IsNullOrEmpty(tbClientId.Text) && !String.IsNullOrEmpty(tbClientSecret.Text)) - { - clientId = tbClientId.Text; - clientSecret = tbClientSecret.Text; - var token = GoogleAuthService.GetAccessToken(ClientId, ClientSecret); - IsUserAuthorized = true; - XmlItem xi = Config.Root.FindItem("GoogleSheets").FindItem("StorageSettings"); - xi.SetProp("ClientId", ClientId); - xi.SetProp("ClientSecret", ClientSecret); - xi.SetProp("PathToJson", ""); - xi.SetProp("ApiKey", ""); - xi.SetProp("IsUserAuthorized", IsUserAuthorized.ToString()); - xi.SetProp("AccessToken", token.ToString()); - DialogResult = DialogResult.OK; - this.Close(); - } - else if (!String.IsNullOrEmpty(tbPathToJsonFile.Text) && cbxPathToJsonFile.Checked) - { - pathToJson = tbPathToJsonFile.Text; - var token = GoogleAuthService.GetAccessToken(PathToJson); - IsUserAuthorized = true; - XmlItem xi = Config.Root.FindItem("GoogleSheets").FindItem("StorageSettings"); - xi.SetProp("ClientId", ""); - xi.SetProp("ClientSecret", ""); - xi.SetProp("PathToJson", PathToJson); - xi.SetProp("ApiKey", ""); - xi.SetProp("IsUserAuthorized", IsUserAuthorized.ToString()); - xi.SetProp("AccessToken", token.ToString()); - DialogResult = DialogResult.OK; - this.Close(); - } - else if (!String.IsNullOrEmpty(tbApiKey.Text)) - { - apiKey = tbApiKey.Text; - IsUserAuthorized = true; - XmlItem xi = Config.Root.FindItem("GoogleSheets").FindItem("StorageSettings"); - xi.SetProp("ClientId", ""); - xi.SetProp("ClientSecret", ""); - xi.SetProp("PathToJson", ""); - xi.SetProp("ApiKey", ApiKey); - xi.SetProp("IsUserAuthorized", IsUserAuthorized.ToString()); - DialogResult = DialogResult.OK; - this.Close(); - } - - if (IsUserAuthorized == true) - { - MessageBox.Show(Res.Get("Forms,SignInGoogle,OnConnection")); - } - else - { - MessageBox.Show(Res.Get("Forms,SignInGoogle,OffConnection")); - } - } - - private void cbxChangeSignIn_SelectedIndexChanged(object sender, EventArgs e) - { - if (cbxChangeSignIn.SelectedIndex == 0) - { - gbxSignInGoogleAPI.Visible = true; - gbxSignInGoogleAPI.Enabled = true; - - gbxGoogleApiKey.Visible = false; - gbxGoogleApiKey.Enabled = false; - } - else - { - gbxSignInGoogleAPI.Visible = false; - gbxSignInGoogleAPI.Enabled = false; - - gbxGoogleApiKey.Visible = true; - gbxGoogleApiKey.Enabled = true; - } - } - - #endregion Events Handlers - - #region Private Methods - - private void InitSignInList() - { - cbxChangeSignIn.Items.Add("OAuth 2.0"); - cbxChangeSignIn.Items.Add("API key"); - cbxChangeSignIn.SelectedIndex = 0; - } - - #endregion Private Methods - - #region Public Methods - - public override void Localize() - { - base.Localize(); - MyRes res = new MyRes("Forms,SignInGoogle"); - - lblCaption.Text = res.Get("Caption"); - gbxSignInGoogleAPI.Text = res.Get("SignInGoogleApi"); - gbxGoogleApiKey.Text = res.Get("SignInApiKey"); - lblClientId.Text = res.Get("ClientId"); - lblClientSecret.Text = res.Get("ClientSecret"); - lblPath.Text = res.Get("PathToFile"); - lblApiKey.Text = res.Get("ApiKey"); - cbxPathToJsonFile.Text = res.Get("CheckPathToJson"); - btnSignIn.Text = res.Get("SignIn"); - } - - public override void UpdateDpiDependencies() - { - base.UpdateDpiDependencies(); - tbPathToJsonFile.Image = this.GetImage(1); - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.designer.cs b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.designer.cs deleted file mode 100644 index 58be95ab..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.designer.cs +++ /dev/null @@ -1,263 +0,0 @@ -namespace FastReport.Data -{ - partial class SignInGoogle - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.cbxPathToJsonFile = new System.Windows.Forms.CheckBox(); - this.tbPathToJsonFile = new FastReport.Controls.TextBoxButton(); - this.lblPath = new System.Windows.Forms.Label(); - this.lblClientSecret = new System.Windows.Forms.Label(); - this.tbClientSecret = new System.Windows.Forms.TextBox(); - this.lblClientId = new System.Windows.Forms.Label(); - this.tbClientId = new System.Windows.Forms.TextBox(); - this.lblCaption = new System.Windows.Forms.Label(); - this.btnSignIn = new System.Windows.Forms.Button(); - this.gbxSignInGoogleAPI = new System.Windows.Forms.GroupBox(); - this.gbxGoogleApiKey = new System.Windows.Forms.GroupBox(); - this.lblApiKey = new System.Windows.Forms.Label(); - this.tbApiKey = new System.Windows.Forms.TextBox(); - this.cbxChangeSignIn = new System.Windows.Forms.ComboBox(); - this.gbxSignInGoogleAPI.SuspendLayout(); - this.gbxGoogleApiKey.SuspendLayout(); - this.SuspendLayout(); - // - // btnOk - // - this.btnOk.Location = new System.Drawing.Point(151, 315); - this.btnOk.Margin = new System.Windows.Forms.Padding(4); - this.btnOk.Size = new System.Drawing.Size(94, 29); - // - // btnCancel - // - this.btnCancel.Location = new System.Drawing.Point(252, 315); - this.btnCancel.Margin = new System.Windows.Forms.Padding(4); - this.btnCancel.Size = new System.Drawing.Size(94, 29); - // - // cbxPathToJsonFile - // - this.cbxPathToJsonFile.AutoSize = true; - this.cbxPathToJsonFile.Location = new System.Drawing.Point(21, 126); - this.cbxPathToJsonFile.Margin = new System.Windows.Forms.Padding(4); - this.cbxPathToJsonFile.Name = "cbxPathToJsonFile"; - this.cbxPathToJsonFile.Size = new System.Drawing.Size(121, 21); - this.cbxPathToJsonFile.TabIndex = 17; - this.cbxPathToJsonFile.Text = "Check .json file"; - this.cbxPathToJsonFile.UseVisualStyleBackColor = true; - this.cbxPathToJsonFile.CheckedChanged += new System.EventHandler(this.cbxPathToJsonFile_CheckedChanged); - // - // tbPathToJsonFile - // - this.tbPathToJsonFile.ButtonText = ""; - this.tbPathToJsonFile.Image = null; - this.tbPathToJsonFile.Location = new System.Drawing.Point(22, 39); - this.tbPathToJsonFile.Margin = new System.Windows.Forms.Padding(4); - this.tbPathToJsonFile.Name = "tbPathToJsonFile"; - this.tbPathToJsonFile.Size = new System.Drawing.Size(291, 26); - this.tbPathToJsonFile.TabIndex = 16; - this.tbPathToJsonFile.Visible = false; - this.tbPathToJsonFile.ButtonClick += new System.EventHandler(this.tbPathToJsonFile_ButtonClick); - // - // lblPath - // - this.lblPath.AutoSize = true; - this.lblPath.Location = new System.Drawing.Point(18, 20); - this.lblPath.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.lblPath.Name = "lblPath"; - this.lblPath.Size = new System.Drawing.Size(87, 17); - this.lblPath.TabIndex = 14; - this.lblPath.Text = "Path to .json"; - this.lblPath.Visible = false; - // - // lblClientSecret - // - this.lblClientSecret.AutoSize = true; - this.lblClientSecret.Location = new System.Drawing.Point(19, 74); - this.lblClientSecret.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.lblClientSecret.Name = "lblClientSecret"; - this.lblClientSecret.Size = new System.Drawing.Size(84, 17); - this.lblClientSecret.TabIndex = 12; - this.lblClientSecret.Text = "Client Secret"; - // - // tbClientSecret - // - this.tbClientSecret.Location = new System.Drawing.Point(22, 94); - this.tbClientSecret.Margin = new System.Windows.Forms.Padding(4); - this.tbClientSecret.Name = "tbClientSecret"; - this.tbClientSecret.Size = new System.Drawing.Size(290, 24); - this.tbClientSecret.TabIndex = 13; - this.tbClientSecret.UseSystemPasswordChar = true; - // - // lblClientId - // - this.lblClientId.AutoSize = true; - this.lblClientId.Location = new System.Drawing.Point(19, 20); - this.lblClientId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.lblClientId.Name = "lblClientId"; - this.lblClientId.Size = new System.Drawing.Size(59, 17); - this.lblClientId.TabIndex = 10; - this.lblClientId.Text = "Client ID"; - // - // tbClientId - // - this.tbClientId.Location = new System.Drawing.Point(22, 39); - this.tbClientId.Margin = new System.Windows.Forms.Padding(4); - this.tbClientId.Name = "tbClientId"; - this.tbClientId.Size = new System.Drawing.Size(290, 24); - this.tbClientId.TabIndex = 11; - this.tbClientId.UseSystemPasswordChar = true; - // - // lblCaption - // - this.lblCaption.AutoSize = true; - this.lblCaption.Font = new System.Drawing.Font("Calibri Light", 19.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.lblCaption.Location = new System.Drawing.Point(15, 11); - this.lblCaption.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.lblCaption.Name = "lblCaption"; - this.lblCaption.Size = new System.Drawing.Size(253, 40); - this.lblCaption.TabIndex = 9; - this.lblCaption.Text = "Sign in Google API"; - // - // btnSignIn - // - this.btnSignIn.Location = new System.Drawing.Point(220, 158); - this.btnSignIn.Margin = new System.Windows.Forms.Padding(4); - this.btnSignIn.Name = "btnSignIn"; - this.btnSignIn.RightToLeft = System.Windows.Forms.RightToLeft.No; - this.btnSignIn.Size = new System.Drawing.Size(94, 29); - this.btnSignIn.TabIndex = 0; - this.btnSignIn.Text = "Sign In"; - this.btnSignIn.UseVisualStyleBackColor = true; - this.btnSignIn.Click += new System.EventHandler(this.btnSignIn_Click); - // - // gbxSignInGoogleAPI - // - this.gbxSignInGoogleAPI.Controls.Add(this.btnSignIn); - this.gbxSignInGoogleAPI.Controls.Add(this.lblClientId); - this.gbxSignInGoogleAPI.Controls.Add(this.cbxPathToJsonFile); - this.gbxSignInGoogleAPI.Controls.Add(this.tbClientId); - this.gbxSignInGoogleAPI.Controls.Add(this.tbClientSecret); - this.gbxSignInGoogleAPI.Controls.Add(this.tbPathToJsonFile); - this.gbxSignInGoogleAPI.Controls.Add(this.lblClientSecret); - this.gbxSignInGoogleAPI.Controls.Add(this.lblPath); - this.gbxSignInGoogleAPI.Location = new System.Drawing.Point(15, 114); - this.gbxSignInGoogleAPI.Margin = new System.Windows.Forms.Padding(4); - this.gbxSignInGoogleAPI.Name = "gbxSignInGoogleAPI"; - this.gbxSignInGoogleAPI.Padding = new System.Windows.Forms.Padding(4); - this.gbxSignInGoogleAPI.Size = new System.Drawing.Size(331, 194); - this.gbxSignInGoogleAPI.TabIndex = 19; - this.gbxSignInGoogleAPI.TabStop = false; - this.gbxSignInGoogleAPI.Text = "Sign in Google API with OAuth 2.0"; - // - // gbxGoogleApiKey - // - this.gbxGoogleApiKey.Controls.Add(this.lblApiKey); - this.gbxGoogleApiKey.Controls.Add(this.tbApiKey); - this.gbxGoogleApiKey.Enabled = false; - this.gbxGoogleApiKey.Location = new System.Drawing.Point(15, 114); - this.gbxGoogleApiKey.Margin = new System.Windows.Forms.Padding(4); - this.gbxGoogleApiKey.Name = "gbxGoogleApiKey"; - this.gbxGoogleApiKey.Padding = new System.Windows.Forms.Padding(4); - this.gbxGoogleApiKey.Size = new System.Drawing.Size(331, 152); - this.gbxGoogleApiKey.TabIndex = 22; - this.gbxGoogleApiKey.TabStop = false; - this.gbxGoogleApiKey.Text = "Sign in Google API with API key"; - this.gbxGoogleApiKey.Visible = false; - // - // lblApiKey - // - this.lblApiKey.AutoSize = true; - this.lblApiKey.Location = new System.Drawing.Point(19, 20); - this.lblApiKey.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.lblApiKey.Name = "lblApiKey"; - this.lblApiKey.Size = new System.Drawing.Size(54, 17); - this.lblApiKey.TabIndex = 10; - this.lblApiKey.Text = "API key"; - // - // tbApiKey - // - this.tbApiKey.Location = new System.Drawing.Point(22, 45); - this.tbApiKey.Margin = new System.Windows.Forms.Padding(4); - this.tbApiKey.Name = "tbApiKey"; - this.tbApiKey.Size = new System.Drawing.Size(290, 24); - this.tbApiKey.TabIndex = 11; - this.tbApiKey.UseSystemPasswordChar = true; - // - // cbxChangeSignIn - // - this.cbxChangeSignIn.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.cbxChangeSignIn.FormattingEnabled = true; - this.cbxChangeSignIn.Location = new System.Drawing.Point(15, 68); - this.cbxChangeSignIn.Margin = new System.Windows.Forms.Padding(4); - this.cbxChangeSignIn.Name = "cbxChangeSignIn"; - this.cbxChangeSignIn.Size = new System.Drawing.Size(145, 24); - this.cbxChangeSignIn.TabIndex = 18; - this.cbxChangeSignIn.SelectedIndexChanged += new System.EventHandler(this.cbxChangeSignIn_SelectedIndexChanged); - // - // SignInGoogle - // - this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(364, 359); - this.Controls.Add(this.gbxSignInGoogleAPI); - this.Controls.Add(this.cbxChangeSignIn); - this.Controls.Add(this.lblCaption); - this.Controls.Add(this.gbxGoogleApiKey); - this.Margin = new System.Windows.Forms.Padding(4); - this.Name = "SignInGoogle"; - this.Controls.SetChildIndex(this.gbxGoogleApiKey, 0); - this.Controls.SetChildIndex(this.lblCaption, 0); - this.Controls.SetChildIndex(this.cbxChangeSignIn, 0); - this.Controls.SetChildIndex(this.gbxSignInGoogleAPI, 0); - this.Controls.SetChildIndex(this.btnOk, 0); - this.Controls.SetChildIndex(this.btnCancel, 0); - this.gbxSignInGoogleAPI.ResumeLayout(false); - this.gbxSignInGoogleAPI.PerformLayout(); - this.gbxGoogleApiKey.ResumeLayout(false); - this.gbxGoogleApiKey.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - private System.Windows.Forms.CheckBox cbxPathToJsonFile; - private Controls.TextBoxButton tbPathToJsonFile; - private System.Windows.Forms.Label lblPath; - private System.Windows.Forms.Label lblClientSecret; - private System.Windows.Forms.TextBox tbClientSecret; - private System.Windows.Forms.Label lblClientId; - private System.Windows.Forms.TextBox tbClientId; - private System.Windows.Forms.Label lblCaption; - private System.Windows.Forms.Button btnSignIn; - private System.Windows.Forms.GroupBox gbxSignInGoogleAPI; - private System.Windows.Forms.ComboBox cbxChangeSignIn; - private System.Windows.Forms.GroupBox gbxGoogleApiKey; - private System.Windows.Forms.Label lblApiKey; - private System.Windows.Forms.TextBox tbApiKey; - } -} diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.resx b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.resx deleted file mode 100644 index d58980a3..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/SignInGoogle.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/readme.txt b/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/readme.txt deleted file mode 100644 index e270c9b7..00000000 --- a/Extras/Core/FastReport.Data/FastReport.Data.GoogleSheets/readme.txt +++ /dev/null @@ -1,12 +0,0 @@ -How to use it: -- execute the following code once at the application start: -FastReport.Utils.RegisteredObjects.AddConnection(typeof(GoogleSheetsDataConnection)); -- you should now be able to create a new Google Sheets data connection from code: -Report report = new Report(); -report.Load(@"YourReport.frx"); -//... -GoogleSheetsDataConnection conn = new GoogleSheetsDataConnection(); -conn.ConnectionString = ""; -conn.Sheets = "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit#gid=0"; -conn.CreateAllTables(); -report.Dictionary.Connections.Add(conn); \ No newline at end of file diff --git a/FastReport.Base/LineObject.cs b/FastReport.Base/LineObject.cs index 33b55d0a..27094e59 100644 --- a/FastReport.Base/LineObject.cs +++ b/FastReport.Base/LineObject.cs @@ -5,6 +5,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using FastReport.Utils; +using System.Linq; namespace FastReport { @@ -22,6 +23,7 @@ public partial class LineObject : ReportComponentBase private bool diagonal; private CapSettings startCap; private CapSettings endCap; + private FloatCollection dashPattern; #endregion #region Properties @@ -58,6 +60,20 @@ public CapSettings EndCap get { return endCap; } set { endCap = value; } } + + /// + /// Gets or sets collection of values for custom dash pattern. + /// + /// + /// Each element should be a non-zero positive number. + /// If the number is negative or zero, that number is replaced by one. + /// + [Category("Appearance")] + public FloatCollection DashPattern + { + get { return dashPattern; } + set { dashPattern = value; } + } #endregion #region Public Methods @@ -70,6 +86,7 @@ public override void Assign(Base source) Diagonal = src.Diagonal; StartCap.Assign(src.StartCap); EndCap.Assign(src.EndCap); + DashPattern.Assign(src.DashPattern); } /// @@ -93,6 +110,8 @@ public override void Draw(FRPaintEventArgs e) Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); + DrawUtils.SetPenDashPatternOrStyle(DashPattern, pen, Border); + float width = Width; float height = Height; if (!Diagonal) @@ -195,6 +214,8 @@ public override void Serialize(FRWriter writer) writer.WriteBool("Diagonal", Diagonal); StartCap.Serialize("StartCap", writer, c.StartCap); EndCap.Serialize("EndCap", writer, c.EndCap); + if (DashPattern?.Count > 0) + writer.WriteValue("DashPattern", DashPattern); } #endregion @@ -207,6 +228,7 @@ public LineObject() endCap = new CapSettings(); FlagSimpleBorder = true; FlagUseFill = false; + dashPattern = new FloatCollection(); } } } diff --git a/FastReport.Base/PolyLineObject.cs b/FastReport.Base/PolyLineObject.cs index 4c9a1c8e..da126197 100644 --- a/FastReport.Base/PolyLineObject.cs +++ b/FastReport.Base/PolyLineObject.cs @@ -6,6 +6,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Globalization; +using System.Linq; using System.Text; namespace FastReport @@ -32,10 +33,24 @@ public partial class PolyLineObject : ReportComponentBase private PointF center; private PolyPointCollection pointsCollection; + private FloatCollection dashPattern; #endregion Private Fields #region Public Properties + /// + /// Gets or sets collection of values for custom dash pattern. + /// + /// + /// Each element should be a non-zero positive number. + /// If the number is negative or zero, that number is replaced by one. + /// + [Category("Appearance")] + public FloatCollection DashPattern + { + get { return dashPattern; } + set { dashPattern = value; } + } /// /// Return points collection. @@ -111,6 +126,7 @@ public PolyLineObject() FlagUseFill = false; pointsCollection = new PolyPointCollection(); center = PointF.Empty; + dashPattern = new FloatCollection(); InitDesign(); } @@ -127,6 +143,7 @@ public override void Assign(Base source) pointsCollection = src.pointsCollection.Clone(); center = src.center; + DashPattern.Assign(src.DashPattern); //recalculateBounds(); } @@ -477,6 +494,8 @@ public override void Serialize(FRWriter writer) writer.WriteFloat("CenterX", center.X); writer.WriteFloat("CenterY", center.Y); + if (DashPattern?.Count > 0) + writer.WriteValue("DashPattern", DashPattern); } public void SetPolyLine(PointF[] newPoints) @@ -565,6 +584,8 @@ protected virtual void drawPoly(FRPaintEventArgs e) pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); else pen = e.Cache.GetPen(Border.Color, 1, DashStyle.Solid); + DrawUtils.SetPenDashPatternOrStyle(DashPattern, pen, Border); + using (GraphicsPath path = GetPath(pen, AbsLeft, AbsTop, AbsRight, AbsBottom, e.ScaleX, e.ScaleY)) e.Graphics.DrawPath(pen, path); } diff --git a/FastReport.Base/PolygonObject.cs b/FastReport.Base/PolygonObject.cs index bb3e753c..cf9f5b24 100644 --- a/FastReport.Base/PolygonObject.cs +++ b/FastReport.Base/PolygonObject.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.Drawing.Drawing2D; +using System.Linq; using FastReport.Utils; namespace FastReport @@ -54,6 +55,8 @@ protected override void drawPoly(FRPaintEventArgs e) else brush = Fill.CreateBrush(new RectangleF(x, y, dx, dy), e.ScaleX, e.ScaleY); + DrawUtils.SetPenDashPatternOrStyle(DashPattern, pen, Border); + using (GraphicsPath path = getPolygonPath(pen, e.ScaleX, e.ScaleY)) { if (polygonSelectionMode == PolygonSelectionMode.MoveAndScale) diff --git a/FastReport.Base/ShapeObject.cs b/FastReport.Base/ShapeObject.cs index 7053c647..8d82ccce 100644 --- a/FastReport.Base/ShapeObject.cs +++ b/FastReport.Base/ShapeObject.cs @@ -3,6 +3,7 @@ using System.Drawing.Drawing2D; using System.ComponentModel; using FastReport.Utils; +using System.Linq; namespace FastReport { @@ -49,9 +50,24 @@ public partial class ShapeObject : ReportComponentBase #region Fields private ShapeKind shape; private float curve; + private FloatCollection dashPattern; #endregion #region Properties + /// + /// Gets or sets collection of values for custom dash pattern. + /// + /// + /// Each element should be a non-zero positive number. + /// If the number is negative or zero, that number is replaced by one. + /// + [Category("Appearance")] + public FloatCollection DashPattern + { + get { return dashPattern; } + set { dashPattern = value; } + } + /// /// Gets or sets a shape kind. /// @@ -103,6 +119,7 @@ public override void Assign(Base source) ShapeObject src = source as ShapeObject; Shape = src.Shape; Curve = src.Curve; + DashPattern.Assign(src.DashPattern); } /// @@ -120,6 +137,9 @@ public override void Draw(FRPaintEventArgs e) float y1 = y + dy; Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); + + DrawUtils.SetPenDashPatternOrStyle(DashPattern, pen, Border); + Brush brush = null; if (Fill is SolidFill) brush = e.Cache.GetBrush((Fill as SolidFill).Color); @@ -188,6 +208,8 @@ public override void Serialize(FRWriter writer) writer.WriteValue("Shape", Shape); if (Curve != c.Curve) writer.WriteFloat("Curve", Curve); + if (DashPattern?.Count > 0) + writer.WriteValue("DashPattern", DashPattern); } #endregion @@ -198,6 +220,7 @@ public ShapeObject() { shape = ShapeKind.Rectangle; FlagSimpleBorder = true; + dashPattern = new FloatCollection(); } } } \ No newline at end of file diff --git a/FastReport.Base/Table/TableObject.cs b/FastReport.Base/Table/TableObject.cs index 64c9bdb0..2fd922a8 100644 --- a/FastReport.Base/Table/TableObject.cs +++ b/FastReport.Base/Table/TableObject.cs @@ -217,6 +217,10 @@ internal bool IsManualBuild } #endregion + #region Private Methods + partial void InitTag(); + #endregion + #region Public Methods /// public override void Assign(Base source) @@ -487,6 +491,7 @@ public TableObject() { manualBuildEvent = ""; manualBuildAutoSpans = true; + InitTag(); } } } diff --git a/FastReport.Base/TypeConverters/FloatCollectionConverter.cs b/FastReport.Base/TypeConverters/FloatCollectionConverter.cs index bfc20c9a..57c8d61e 100644 --- a/FastReport.Base/TypeConverters/FloatCollectionConverter.cs +++ b/FastReport.Base/TypeConverters/FloatCollectionConverter.cs @@ -32,7 +32,9 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c string[] values = (value as string).Split(','); foreach (string s in values) { - result.Add((float)Converter.FromString(typeof(float), s)); + float f; + if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out f)) + result.Add(f); } return result; } diff --git a/FastReport.Base/Utils/Converter.cs b/FastReport.Base/Utils/Converter.cs index c4e8f1bf..e7d928db 100644 --- a/FastReport.Base/Utils/Converter.cs +++ b/FastReport.Base/Utils/Converter.cs @@ -12,10 +12,8 @@ namespace FastReport.Utils /// /// Contains methods that peform string to object and vice versa conversions. /// - public static class Converter + public static partial class Converter { - - /// /// Converts an object to a string. /// diff --git a/FastReport.Base/Utils/DrawUtils.cs b/FastReport.Base/Utils/DrawUtils.cs index 4ed483e2..6bb27fc0 100644 --- a/FastReport.Base/Utils/DrawUtils.cs +++ b/FastReport.Base/Utils/DrawUtils.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using System.Linq; namespace FastReport.Utils { @@ -237,5 +238,36 @@ internal static MonoRendering GetMonoRendering(IGraphics printerGraphics) } return FMonoRendering; } + + + /// + /// The method adjusts the dotted line style for the in a graphical context. + /// + /// Collection of values for custom dash pattern. + /// Pen for lines. + /// Border around the report object. + /// + /// If a DashPattern pattern is specified and contains elements, the method checks each element. + /// If the element is less than or equal to 0, it is replaced by 1.
+ /// Then the resulting array of patterns is converted to the type and set as a dotted line pattern for the .
+ /// If the pattern is empty or not specified, + /// the method sets the style of the dotted line of the equal to the style of the dotted line of the object. + ///
+ internal static void SetPenDashPatternOrStyle(FloatCollection dashPattern, Pen pen, Border border) + { + if (dashPattern?.Count > 0) + { + for (int i = 0; i < dashPattern.Count; i++) + { + if (dashPattern[i] <= 0) + dashPattern[i] = 1; + } + pen.DashPattern = dashPattern.Cast().ToArray(); + } + else + { + pen.DashStyle = border.DashStyle; + } + } } } \ No newline at end of file diff --git a/FastReport.Base/Utils/HtmlTextRenderer.cs b/FastReport.Base/Utils/HtmlTextRenderer.cs index 62b6c86c..5b540baa 100644 --- a/FastReport.Base/Utils/HtmlTextRenderer.cs +++ b/FastReport.Base/Utils/HtmlTextRenderer.cs @@ -437,9 +437,10 @@ internal void Draw() { // set clipping IGraphicsState state = graphics.Save(); - //RectangleF rect = new RectangleF(FDisplayRect.Location, SizeF.Add(FDisplayRect.Size, new SizeF(width_dotnet, 0))); - //FGraphics.SetClip(rect, CombineMode.Intersect); - graphics.SetClip(displayRect, CombineMode.Intersect); + RectangleF dRect = displayRect; + // round x and y to an integer to avoid clipping the characters of the first line + dRect.Inflate(displayRect.Left % 1, displayRect.Top % 1); + graphics.SetClip(dRect, CombineMode.Intersect); // reset alignment //StringAlignment saveAlign = FFormat.Alignment; //StringAlignment saveLineAlign = FFormat.LineAlignment; diff --git a/FastReport.Base/Utils/StorageService.cs b/FastReport.Base/Utils/StorageService.cs index 21fdc0c7..b207b3f7 100644 --- a/FastReport.Base/Utils/StorageService.cs +++ b/FastReport.Base/Utils/StorageService.cs @@ -11,7 +11,7 @@ public class StorageService private string path; private XmlItem root; - private XmlItem Root + internal XmlItem Root { get { diff --git a/FastReport.Core.Web/Application/ExportMenuSettings.cs b/FastReport.Core.Web/Application/ExportMenuSettings.cs index 2003bd32..1cc531df 100644 --- a/FastReport.Core.Web/Application/ExportMenuSettings.cs +++ b/FastReport.Core.Web/Application/ExportMenuSettings.cs @@ -230,17 +230,24 @@ public bool ShowHpglExport get => GetExport(Exports.Hpgl); set => SetExport(value, Exports.Hpgl); } - //public bool ShowEmailExport - //{ - // get => (ExportTypes & Exports.Email) > 0; - // set - // { - // if (value) - // ExportTypes |= Exports.Email; - // else - // ExportTypes &= ~Exports.Email; - // } - //} + +#if !WASM + /// + /// Switches visibility the Email export in toolbar. + /// + public bool ShowEmailExport + { + get => GetExport(Exports.Email); + set + { + if (Infrastructure.FastReportGlobal.InternalEmailExportOptions is null) + throw new Exception("Please add your account information when registering for services. Use services.AddFastReport(options => options.EmailExportOptions = new EmailExportOptions() {...} )"); + + SetExport(value, Exports.Email); + } + } +#endif + /// /// Switches visibility the DXF export in toolbar. /// @@ -359,7 +366,7 @@ public enum Exports Mht = 8192, HTML = 16384, Hpgl = 32768, - //Email = 65536, + Email = 65536, Dxf = 131_072, Json = 262_144, LaTeX = 524_288, diff --git a/FastReport.Core.Web/Application/ExportsHelper.cs b/FastReport.Core.Web/Application/ExportsHelper.cs index 4dba7219..6225a921 100644 --- a/FastReport.Core.Web/Application/ExportsHelper.cs +++ b/FastReport.Core.Web/Application/ExportsHelper.cs @@ -26,6 +26,7 @@ using FastReport.Export.PS; using FastReport.Export.Json; using FastReport.Export.Dxf; +using FastReport.Export.Email; #endif namespace FastReport.Web @@ -62,6 +63,8 @@ static ExportsHelper() new ExportInfo("ps", Exports.PS, typeof(PSExport), false), new ExportInfo("json", Exports.Json, typeof(JsonExport), false), new ExportInfo("dxf", Exports.Dxf, typeof(DxfExport), false), + new ExportInfo("email", Exports.Email, typeof(EmailExport), true), + #endif new ExportInfo("html", Exports.HTML, typeof(HTMLExport), true), //new ExportInfo("png", Exports.Image, typeof(ImageExport), true), diff --git a/FastReport.Core.Web/Application/Infrastructure/ControllerBuilder.cs b/FastReport.Core.Web/Application/Infrastructure/ControllerBuilder.cs index 9cb77e9f..027e6990 100644 --- a/FastReport.Core.Web/Application/Infrastructure/ControllerBuilder.cs +++ b/FastReport.Core.Web/Application/Infrastructure/ControllerBuilder.cs @@ -251,11 +251,7 @@ public static Task HandleResult(HttpContext httpContext, object result) { Debug.Assert(result.GetType() != typeof(IActionResult)); -#if NETCOREAPP3_1_OR_GREATER string content = System.Text.Json.JsonSerializer.Serialize(result); -#else - string content = result.ToString(); -#endif var contentResult = Results.Content(content, "text/json"); return contentResult.ExecuteAsync(httpContext); } @@ -304,10 +300,8 @@ private static bool TryKnownTypesSearching(List> param if (request.Headers.TryGetValue(paramName, out var headerValue)) return ParseToType(headerValue, paramType); -#if NETCOREAPP3_1_OR_GREATER if (request.RouteValues.TryGetValue(paramName, out var routeValue)) return ParseToType(routeValue, paramType); -#endif if (request.Form.TryGetValue(paramName, out var formValue)) return ParseToType(formValue, paramType); @@ -362,7 +356,6 @@ private static bool TryAttributesSearching(List> param parameters.Add(func); return true; } -#if NETCOREAPP3_1_OR_GREATER // not available in .Net Core 2 else if (attribute is FromRouteAttribute fromRoute) { string name = fromRoute.Name ?? parameterInfo.Name; @@ -381,7 +374,6 @@ private static bool TryAttributesSearching(List> param parameters.Add(func); return true; } -#endif else if (attribute is FromServicesAttribute) { parameters.Add((httpContext) => diff --git a/FastReport.Core.Web/Application/Infrastructure/FastReportBuilderExtensions.cs b/FastReport.Core.Web/Application/Infrastructure/FastReportBuilderExtensions.cs index c775ed92..32713edd 100644 --- a/FastReport.Core.Web/Application/Infrastructure/FastReportBuilderExtensions.cs +++ b/FastReport.Core.Web/Application/Infrastructure/FastReportBuilderExtensions.cs @@ -40,11 +40,7 @@ private static FastReportOptions SetupFastReport(Action setup WebReportCache.Instance = serviceProvider.GetService(); // TODO: find better way to share global objects -#if BLAZOR FastReportGlobal.HostingEnvironment = serviceProvider.GetService(); -#else - FastReportGlobal.HostingEnvironment = serviceProvider.GetService(); -#endif WebReport.ResourceLoader = serviceProvider.GetService(); return options; diff --git a/FastReport.Core.Web/Application/Infrastructure/FastReportGlobal.cs b/FastReport.Core.Web/Application/Infrastructure/FastReportGlobal.cs index 67caea4b..36df45fe 100644 --- a/FastReport.Core.Web/Application/Infrastructure/FastReportGlobal.cs +++ b/FastReport.Core.Web/Application/Infrastructure/FastReportGlobal.cs @@ -8,13 +8,13 @@ namespace FastReport.Web.Infrastructure { internal static class FastReportGlobal { -#if BLAZOR internal static IWebHostEnvironment HostingEnvironment = null; -#else - internal static IHostingEnvironment HostingEnvironment = null; -#endif internal static FastReportOptions FastReportOptions = new FastReportOptions(); +#if !WASM + internal static EmailExportOptions InternalEmailExportOptions = null; +#endif + } } #endif diff --git a/FastReport.Core.Web/Application/Infrastructure/FastReportServiceCollectionExtensions.Backend.cs b/FastReport.Core.Web/Application/Infrastructure/FastReportServiceCollectionExtensions.Backend.cs index d0cdde36..581e3ab6 100644 --- a/FastReport.Core.Web/Application/Infrastructure/FastReportServiceCollectionExtensions.Backend.cs +++ b/FastReport.Core.Web/Application/Infrastructure/FastReportServiceCollectionExtensions.Backend.cs @@ -52,6 +52,8 @@ private static void AddFastReportWebServices(IServiceCollection services, WebRep } } + FastReportGlobal.InternalEmailExportOptions = options.EmailExportOptions; + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/FastReport.Core.Web/Application/Localizations/EmailExportSettingsLocalization.cs b/FastReport.Core.Web/Application/Localizations/EmailExportSettingsLocalization.cs new file mode 100644 index 00000000..44bb3e78 --- /dev/null +++ b/FastReport.Core.Web/Application/Localizations/EmailExportSettingsLocalization.cs @@ -0,0 +1,49 @@ +namespace FastReport.Web.Application.Localizations +{ + internal class EmailExportSettingsLocalization + { + internal readonly string Title; + + internal readonly string Email; + internal readonly string Address; + internal readonly string Subject; + internal readonly string Message; + + internal readonly string Account; + internal readonly string Host; + internal readonly string Password; + internal readonly string EnableSSL; + internal readonly string NameAttachmentFile; + internal readonly string Name; + internal readonly string Attachment; + internal readonly string Template; + internal readonly string Username; + internal readonly string Port; + internal readonly string FailureMessage; + internal readonly string SuccessMessage; + internal readonly string Settings; + + public EmailExportSettingsLocalization(IWebRes res) + { + res.Root("Export,Email"); + Title = res.Get(""); + Email = res.Get("Email"); + Settings = res.Get("Settings"); + Address = res.Get("Address"); + Subject = res.Get("Subject"); + Message = res.Get("Message"); + Account = res.Get("Account"); + Host = res.Get("Host"); + Password = res.Get("Password"); + EnableSSL = res.Get("EnableSSL"); + NameAttachmentFile = res.Get("NameAttachmentFile"); + Attachment = res.Get("Attachment"); + Name = res.Get("Name"); + Template = res.Get("Template"); + Username = res.Get("UserName"); + Port = res.Get("Port"); + FailureMessage = res.Get("ErrorEmailSending"); + SuccessMessage = res.Get("SuccessfulEmailSending"); + } + } +} \ No newline at end of file diff --git a/FastReport.Core.Web/Application/Toolbar.Localization.cs b/FastReport.Core.Web/Application/Toolbar.Localization.cs index bdae40b6..9d07f160 100644 --- a/FastReport.Core.Web/Application/Toolbar.Localization.cs +++ b/FastReport.Core.Web/Application/Toolbar.Localization.cs @@ -76,7 +76,7 @@ public ToolbarLocalization() csvTxt = "CSV file"; dxfTxt = "DXF file"; excel97Txt = "MS Office Excel 97-2003"; - //emailTxt = "Email"; // Required modal window + emailTxt = "Email"; // Required modal window hpglTxt = "HPGL"; htmlTxt = "HTML"; svgTxt = "SVG"; @@ -156,7 +156,7 @@ public ToolbarLocalization(IWebRes Res) xamlTxt = Res.Get("Xaml"); zplTxt = Res.Get("Zpl"); mhtTxt = Res.Get("Mht"); - //emailTxt = Res.Get("Email"); // Required modal window + emailTxt = Res.Get("Email"); // Required modal window imageTxt = Res.Get("Image"); } diff --git a/FastReport.Core.Web/Application/ToolbarSettings.cs b/FastReport.Core.Web/Application/ToolbarSettings.cs index e700c6df..4417e7d2 100644 --- a/FastReport.Core.Web/Application/ToolbarSettings.cs +++ b/FastReport.Core.Web/Application/ToolbarSettings.cs @@ -45,17 +45,10 @@ public bool ShowBottomToolbar public bool ShowRefreshButton { get; set; } = true; public bool ShowZoomButton { get; set; } = true; -#if WASM - /// - /// Show Print menu. Not supported in Wasm at the moment - /// - public bool ShowPrint { get => false; set => throw new NotSupportedException("Not supported in Wasm at the moment"); } -#else /// /// Show Print menu /// public bool ShowPrint { get; set; } = true; -#endif public bool PrintInHtml { get; set; } = true; /// diff --git a/FastReport.Core.Web/Application/WebReportOptions.cs b/FastReport.Core.Web/Application/WebReportOptions.cs index a160fcb7..a457f9ec 100644 --- a/FastReport.Core.Web/Application/WebReportOptions.cs +++ b/FastReport.Core.Web/Application/WebReportOptions.cs @@ -11,10 +11,13 @@ namespace FastReport.Web { public sealed class WebReportOptions { - #if !WASM public CacheOptions CacheOptions { get; set; } = new CacheOptions(); + /// + /// SMTP server settings for sending the report by e-mail + /// + public EmailExportOptions EmailExportOptions { get; set; } = null; #else /// /// Used to access .NET libraries to compile the report script diff --git a/FastReport.Core.Web/Controllers/Preview/ExportReportController.cs b/FastReport.Core.Web/Controllers/Preview/ExportReportController.cs index b56548c0..dc8682b2 100644 --- a/FastReport.Core.Web/Controllers/Preview/ExportReportController.cs +++ b/FastReport.Core.Web/Controllers/Preview/ExportReportController.cs @@ -6,9 +6,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; namespace FastReport.Web.Controllers { @@ -56,6 +59,40 @@ public static IResult ExportReport([FromQuery] ExportReportParams query, fileDownloadName: $"{filename}.{exportFormat}"); } +#if !OPENSOURCE + [HttpPost("/preview.sendEmail")] + public static async Task SendEmail([FromQuery] string reportId, + IReportService reportService, + IExportsService exportsService, + HttpRequest request) + { + if (!reportService.TryFindWebReport(reportId, out var webReport)) + return Results.NotFound(); + + try + { + var form = await request.ReadFormAsync(); + + var emailExportParams = new EmailExportParams + { + Address = form["Address"], + Subject = form["Subject"], + MessageBody = form["MessageBody"], + ExportFormat = form["ExportFormat"], + NameAttachmentFile = form["NameAttachmentFile"] + }; + + exportsService.ExportEmail(webReport, emailExportParams); + } + catch (Exception e) + { + return Results.BadRequest(e.Message); + } + + return Results.Ok(); + } + +#endif internal sealed class ExportSettingsParams { diff --git a/FastReport.Core.Web/FastReport.OpenSource.Web.csproj b/FastReport.Core.Web/FastReport.OpenSource.Web.csproj index 326231fa..65a4776f 100644 --- a/FastReport.Core.Web/FastReport.OpenSource.Web.csproj +++ b/FastReport.Core.Web/FastReport.OpenSource.Web.csproj @@ -5,7 +5,7 @@ true - netstandard2.0 + netcoreapp3.1;net6.0 OPENSOURCE; 1.0.0 FastReport MIT license.md @@ -33,6 +33,7 @@ + diff --git a/FastReport.Core.Web/FastReport.Web.Shared.props b/FastReport.Core.Web/FastReport.Web.Shared.props index dad063af..138d9397 100644 --- a/FastReport.Core.Web/FastReport.Web.Shared.props +++ b/FastReport.Core.Web/FastReport.Web.Shared.props @@ -53,11 +53,5 @@ - - - - - - diff --git a/FastReport.Core.Web/Resources/notification-bell.svg b/FastReport.Core.Web/Resources/notification-bell.svg new file mode 100644 index 00000000..770d3e08 --- /dev/null +++ b/FastReport.Core.Web/Resources/notification-bell.svg @@ -0,0 +1,4 @@ + + + + diff --git a/FastReport.Core.Web/Services/Abstract/IExportsService.cs b/FastReport.Core.Web/Services/Abstract/IExportsService.cs index 01dc2af8..8e0926fb 100644 --- a/FastReport.Core.Web/Services/Abstract/IExportsService.cs +++ b/FastReport.Core.Web/Services/Abstract/IExportsService.cs @@ -25,5 +25,14 @@ public interface IExportsService /// Export format. Like "pdf", "html", "image", etc. /// Returns an HTML string with the export settings container of the selected format. If the format is not found, it returns an empty string. string GetExportSettings(WebReport webReport, string format); + +#if !OPENSOURCE + /// + /// Creates an email export, assigns parameters to it and sends the email + /// + /// WebReport to be sent + /// Email export settings + void ExportEmail(WebReport webReport, EmailExportParams emailExportParameters); +#endif } } diff --git a/FastReport.Core.Web/Services/EmailExportParams.cs b/FastReport.Core.Web/Services/EmailExportParams.cs new file mode 100644 index 00000000..1dc7ea22 --- /dev/null +++ b/FastReport.Core.Web/Services/EmailExportParams.cs @@ -0,0 +1,77 @@ +namespace FastReport.Web +{ + /// + /// SMTP server options for sending the report by mail + /// + public sealed class EmailExportOptions + { + /// + /// Determines whether to enable the SSL protocol. + /// + /// + /// The default value for this property is false. + /// + public bool EnableSSL { get; set; } + + /// + /// SMTP account username. + /// + /// + /// Specify the and properties if your host requires authentication. + /// + public string Username { get; set; } + + /// + /// Template that will be used to create a new message. + /// + public string MessageTemplate { get; set; } + + /// + /// The name that will appear next to the address from which the e-mail is sent. + /// + /// + /// This property contains your name (for example, "John Smith"). + /// + public string Name { get; set; } + + /// + /// SMTP host name or IP address. + /// + public string Host { get; set; } + + /// + /// The address from which the e-mail will be sent + /// + public string Address { get; set; } + + /// + /// SMTP server password. + /// + /// + /// Specify the and properties if your host requires + /// authentication. + /// + public string Password { get; set; } + + /// + /// SMTP port. + /// + /// + /// The default value for this property is 25. + /// + public int Port { get; set; } = 25; + } + + public sealed class EmailExportParams + { + public string ExportFormat { get; set; } + + public string MessageBody { get; set; } + + public string NameAttachmentFile { get; set; } + + public string Subject { get; set; } + + public string Address { get; set; } + } +} \ No newline at end of file diff --git a/FastReport.Core.Web/Services/Implementation/ExportService.cs b/FastReport.Core.Web/Services/Implementation/ExportService.cs index 64d3fa41..e87ac0e8 100644 --- a/FastReport.Core.Web/Services/Implementation/ExportService.cs +++ b/FastReport.Core.Web/Services/Implementation/ExportService.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text; +using FastReport.Web.Infrastructure; namespace FastReport.Web.Services { @@ -24,6 +25,42 @@ public byte[] ExportReport(WebReport webReport, KeyValuePair[] e } } +#if !OPENSOURCE + public void ExportEmail(WebReport webReport, EmailExportParams exportParams) + { + var exportInfo = ExportsHelper.GetInfoFromExt(exportParams.ExportFormat); + var export = exportInfo.CreateExport(); + var accountSettings = FastReportGlobal.InternalEmailExportOptions; + + var cc = exportParams.Address.Split(';'); + var address = cc[0]; + cc = cc.Skip(1).Select(s => s.Trim()).ToArray(); + + var emailExport = new Export.Email.EmailExport + { + Export = export, + MessageBody = exportParams.MessageBody, + NameAttachmentFile = exportParams.NameAttachmentFile, + Subject = exportParams.Subject, + Address = address, + CC = cc, + Account = new Export.Email.EmailSettings + { + Host = accountSettings.Host, + Address = accountSettings.Address, + Name = accountSettings.Name, + MessageTemplate = accountSettings.MessageTemplate, + UserName = accountSettings.Username, + Port = accountSettings.Port, + Password = accountSettings.Password, + EnableSSL = accountSettings.EnableSSL + } + }; + + emailExport.SendEmail(webReport.Report); + } +#endif + public string GetExportSettings(WebReport webReport, string format) { string msg = string.Empty; @@ -63,6 +100,9 @@ public string GetExportSettings(WebReport webReport, string format) case "pptx": msg = webReport.template_PptxExportSettings(); break; + case "email": + msg = webReport.template_EmailExportSettings(); + break; #endif } diff --git a/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs b/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs new file mode 100644 index 00000000..4026d752 --- /dev/null +++ b/FastReport.Core.Web/Templates/ExportSettings/EmailExportSettings.cs @@ -0,0 +1,134 @@ +#if !OPENSOURCE +using FastReport.Web.Application.Localizations; +using System.IO; + +namespace FastReport.Web +{ + partial class WebReport + { + internal string template_EmailExportSettings() + { + var localizationEmail = new EmailExportSettingsLocalization(Res); + var localizationPageSelector = new PageSelectorLocalization(Res); + var localization = new ToolbarLocalization(Res); + var exports = Toolbar.Exports; + + return $@" +
+
+
+ {localizationEmail.Title} +
+
+ +
+
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+ +
+ + +
+
+ +"; + + } + + } + +} +#endif \ No newline at end of file diff --git a/FastReport.Core.Web/Templates/main.cs b/FastReport.Core.Web/Templates/main.cs index 8ab02fa9..2f3a2ad2 100644 --- a/FastReport.Core.Web/Templates/main.cs +++ b/FastReport.Core.Web/Templates/main.cs @@ -10,11 +10,18 @@ partial class WebReport internal string template_ROUTE_BASE_PATH => WebUtils.ToUrl(FastReportGlobal.FastReportOptions.RoutePathBaseRoot, FastReportGlobal.FastReportOptions.RouteBasePath); string template_resource_url(string resourceName, string contentType) => $"{template_ROUTE_BASE_PATH}/resources.getResource?resourceName={WebUtility.UrlEncode(resourceName)}&contentType={WebUtility.UrlEncode(contentType)}"; internal string template_export_url(string exportFormat) => $"{template_ROUTE_BASE_PATH}/preview.exportReport?reportId={ID}&exportFormat={exportFormat}"; + internal string templte_email_export_url => $"{template_ROUTE_BASE_PATH}/preview.sendEmail?reportId={ID}"; internal string template_print_url(string printMode) => $"{template_ROUTE_BASE_PATH}/preview.printReport?reportId={ID}&printMode={printMode}"; //string template_TOOLBAR_HEIGHT_FACTOR => 40px * ToolbarHeight; string template_render(bool renderBody) { +#if !OPENSOURCE + var needModal = Toolbar.Exports.EnableSettings || Toolbar.Exports.ShowEmailExport; +#else + var needModal = Toolbar.Exports.EnableSettings; +#endif + return $@"
@@ -33,7 +40,7 @@ string template_render(bool renderBody) {template_body(renderBody)} -{(Toolbar.Exports.EnableSettings ? template_modalcontainer() : "")} +{(needModal ? template_modalcontainer() : "")} "; } } diff --git a/FastReport.Core.Web/Templates/script.cs b/FastReport.Core.Web/Templates/script.cs index c7490c9e..3b8d2c82 100644 --- a/FastReport.Core.Web/Templates/script.cs +++ b/FastReport.Core.Web/Templates/script.cs @@ -222,6 +222,56 @@ string template_script() => $@" }}); }}, + showEmailExportModal: function() {{ + var modalcontainer = this._findModalContainer(); + const emailExportLink = document.getElementById('emailexport'); + const buttons = document.querySelectorAll('.fr-webreport-settings-btn'); + const Overlay = document.querySelector('.modalcontainer-overlay'); + var that = this; + + this._fetch({{ + method: 'POST', + url: '{template_ROUTE_BASE_PATH}/exportsettings.getSettings?reportId={ID}&format=email', + onSuccess: function (xhr) {{ + modalcontainer.innerHTML = xhr.responseText; + that._execModalScripts(); + document.querySelector(`[data-target=email]`).classList.add('modalcontainer--visible'); + Overlay.classList.add('modalcontainer-overlay--visible'); + }}, + }}) + }}, + +showPopup: function (message, isSuccess) {{ + var popup = document.createElement(""div""); + popup.className = ""fr-notification""; + if (isSuccess) {{ + popup.classList.add(""positive""); + }} else {{ + popup.classList.add(""negative""); + }} + + var content = document.createElement(""div""); + content.className = ""fr-notification-content""; + + var image = document.createElement(""img""); + image.src = ""/_fr/resources.getResource?resourceName=notification-bell.svg&contentType=image%2Fsvg%2Bxml""; + + var text = document.createElement(""div""); + text.innerText = message; + + content.appendChild(image); + content.appendChild(text); + popup.appendChild(content); + document.body.appendChild(popup); + + setTimeout(function () {{ + popup.style.opacity = ""0""; + setTimeout(function () {{ + popup.remove(); + }}, 500); + }}, 2000); +}}, + getExportSettings: function () {{ this._getExportSettings(); }}, @@ -246,11 +296,11 @@ string template_script() => $@" document.querySelector(`[data-target=${{fileformat}}]`).classList.add('modalcontainer--visible'); Overlay.classList.add('modalcontainer-overlay--visible'); }}, - }}); }}) }}); }}, + _execScripts: function () {{ var container = this._findContainer(); var scripts = container.getElementsByTagName('script'); diff --git a/FastReport.Core.Web/Templates/style.cs b/FastReport.Core.Web/Templates/style.cs index 01663dcf..15b55407 100644 --- a/FastReport.Core.Web/Templates/style.cs +++ b/FastReport.Core.Web/Templates/style.cs @@ -834,6 +834,107 @@ TOOLBAR NAVIGATION .{template_FR}-outline-children {{ padding-left: 20px; }} + +/******************* + + EMAIL EXPORT + +*******************/ +.fr-notification {{ + position: fixed; + bottom: 20px; + right: 20px; + display: flex; + align-items: center; + padding: 10px 20px; + border-radius: 4px; + font-size: 14px; + color: white; + opacity: 1; + transition: opacity 0.5s; + z-index: 9999; + font-family: Arial, sans-serif; +}} + +.fr-notification-content {{ + display: flex; + align-items: center; +}} + +.fr-notification-content img {{ + margin-right: 10px; +}} + +.fr-notification.positive {{ + background-color: #44cc44; +}} + +.fr-required-star {{ + color: red; +}} + + +.fr-notification.negative {{ + background-color: #cc4444; +}} + + +.fr-email-export-form {{ + display: flex; + flex-direction: column; + padding: 5px; + box-sizing: border-box; + width: 100%; +}} + +.fr-email-export-field {{ + display: flex; + margin-bottom: 5px; + justify-content: space-between; + width: 100%; + font-size: 12px; +}} + +.fr-email-export-input{{ + width: 244px; + padding: 8px; + border: none; + border-radius: 4px; + background: #FFF; + display: flex; + margin-left: 30px; + font-size: 12px; +}} + +.fr-email-export-textarea{{ + margin - left: 10px; + width: 244px; + height: 146px; + padding: 8px; + border: none; + border-radius: 5px; + resize: none; + font-size: 12px; +}} + +.fr-email-export-select{{ + overflow: hidden; + -moz-appearance:none; /* Firefox */ + -webkit-appearance:none; /* Safari and Chrome */ + background: #ffffff url(/_fr/resources.getResource?resourceName=select-arrow.svg&contentType=image%2Fsvg%2Bxml) no-repeat; + background-position: calc(100% - 10px) center; + margin - left: 10px; + width: 244px; + padding: 8px; + border-radius: 5px; + border: none; + font-size: 12px; +}} + +.fr-email-export-label{{ + font-weight: normal; + font-size: 12px; +}} "; } } \ No newline at end of file diff --git a/FastReport.Core.Web/Templates/toolbar.cs b/FastReport.Core.Web/Templates/toolbar.cs index 6adb4368..781cc888 100644 --- a/FastReport.Core.Web/Templates/toolbar.cs +++ b/FastReport.Core.Web/Templates/toolbar.cs @@ -48,7 +48,7 @@ string template_toolbar(bool renderBody) + (exports.EnableSettings && exports.ShowSvgExport? $@"" : "") + (exports.ShowMhtExport ? $@"{localization.mhtTxt}" : "") + (exports.ShowExcel97Export ? $@"{localization.excel97Txt}" : "") - //(exports.ShowEmailExport ? $@"{emailTxt}" : "") + + + (exports.ShowEmailExport ? $@"{localization.emailTxt}" : "") + (exports.ShowHpglExport ? $@"{localization.hpglTxt}" : "") + (exports.ShowHTMLExport ? $@"{localization.htmlTxt}" : "") + (exports.EnableSettings && exports.ShowHTMLExport ? $@"" : "") diff --git a/FastReport/Resources/en.xml b/FastReport/Resources/en.xml index 240ba0a3..a86227db 100644 --- a/FastReport/Resources/en.xml +++ b/FastReport/Resources/en.xml @@ -134,7 +134,6 @@ - @@ -2127,6 +2126,7 @@ + @@ -2358,19 +2358,36 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2469,17 +2486,6 @@ - - - - - - - - - - - @@ -2540,17 +2546,22 @@ - - + + - - + + + + + + + diff --git a/Localization/Russian.frl b/Localization/Russian.frl index acafbe10..de14bc00 100644 --- a/Localization/Russian.frl +++ b/Localization/Russian.frl @@ -134,7 +134,6 @@ - @@ -1942,6 +1941,7 @@ + @@ -2157,19 +2157,36 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2268,17 +2285,6 @@ - - - - - - - - - - - @@ -2339,17 +2345,22 @@ - - + + - - + + + + + + +