Import data from GoogleSheet
This commit is contained in:
@@ -29,6 +29,7 @@ export class DataSet extends Base {
|
|||||||
id: [null],
|
id: [null],
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
source: ['', Validators.required],
|
source: ['', Validators.required],
|
||||||
|
sheetId: '1G_Hu8DTP-PSPNXTaVYhc_ppnTQi6HWoA4oXSSdUmM9E',
|
||||||
createdAt: '',
|
createdAt: '',
|
||||||
modifiedAt: '',
|
modifiedAt: '',
|
||||||
createdBy: '',
|
createdBy: '',
|
||||||
@@ -91,4 +92,16 @@ export class DataSet extends Base {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
static parseGoogleSheet(sheetId: string, _http: HttpClient): Promise<DataRow[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
_http.get<DataRow[]>(`${environment.api.url}/datasets/parseGoogleSheet/${sheetId}`,
|
||||||
|
).pipe(map(data => data.map(x => new DataRow().deserialize(x))))
|
||||||
|
.subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
resolve(data);
|
||||||
|
},
|
||||||
|
error: (e) => reject(e)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,69 +1,82 @@
|
|||||||
<div>
|
<div>
|
||||||
<form [formGroup]="form" (ngSubmit)="save()" novalidate>
|
<form [formGroup]="form" (ngSubmit)="save()" novalidate>
|
||||||
<mat-card appearance="outlined">
|
<mat-card appearance="outlined">
|
||||||
<mat-toolbar color="secondary">
|
<mat-toolbar color="secondary">
|
||||||
Edycja warstwy danych
|
Edycja warstwy danych
|
||||||
<span class="fill-to-right"></span>
|
<span class="fill-to-right"></span>
|
||||||
<button mat-button type="submit" [disabled]="form.invalid">Zapisz</button>
|
<button mat-button type="submit" [disabled]="form.invalid">Zapisz</button>
|
||||||
<button mat-button type="button" routerLink="../..">Anuluj</button>
|
<button mat-button type="button" routerLink="../..">Anuluj</button>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-grid-list cols="2" rowHeight="90px">
|
<mat-grid-list cols="2" rowHeight="90px">
|
||||||
<mat-grid-tile>
|
<mat-grid-tile>
|
||||||
<mat-form-field class="detail-input">
|
<mat-form-field class="detail-input">
|
||||||
<mat-label>Nazwa</mat-label>
|
<mat-label>Nazwa</mat-label>
|
||||||
<input matInput formControlName="name">
|
<input matInput formControlName="name">
|
||||||
<mat-error *ngIf="form.controls['name'].touched && form.controls['name'].invalid">
|
<mat-error *ngIf="form.controls['name'].touched && form.controls['name'].invalid">
|
||||||
Pole obowiązkowe
|
Pole obowiązkowe
|
||||||
</mat-error>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-grid-tile>
|
</mat-grid-tile>
|
||||||
|
|
||||||
<mat-grid-tile>
|
|
||||||
<mat-form-field class="detail-input">
|
|
||||||
<mat-select placeholder="Źródło" formControlName="source" (selectionChange)="generateNumber()">
|
|
||||||
<mat-option value="CSV">CSV</mat-option>
|
|
||||||
<mat-option value="GoogleSheet">GoogleSheet</mat-option>
|
|
||||||
<mat-option value="SAP">SAP</mat-option>
|
|
||||||
<mat-option value="Symfonia">Symfonia</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
<mat-error *ngIf="form.controls['source'].touched && form.controls['source'].invalid">
|
|
||||||
Pole obowiązkowe
|
|
||||||
</mat-error>
|
|
||||||
</mat-form-field>
|
|
||||||
</mat-grid-tile>
|
|
||||||
</mat-grid-list>
|
|
||||||
|
|
||||||
<input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload>
|
<mat-grid-tile>
|
||||||
<button mat-mini-fab color="primary" type="button" class="upload-btn" (click)="fileUpload.click()">
|
<mat-form-field class="detail-input">
|
||||||
<mat-icon>attach_file</mat-icon>
|
<mat-select placeholder="Źródło" formControlName="source" (selectionChange)="generateNumber()">
|
||||||
</button>
|
<mat-option value="CSV">CSV</mat-option>
|
||||||
|
<mat-option value="GoogleSheet">GoogleSheet</mat-option>
|
||||||
|
<mat-option value="SAP">SAP</mat-option>
|
||||||
|
<mat-option value="Symfonia">Symfonia</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error *ngIf="form.controls['source'].touched && form.controls['source'].invalid">
|
||||||
|
Pole obowiązkowe
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-grid-tile>
|
||||||
|
</mat-grid-list>
|
||||||
|
<input type="file" class="file-input" (change)="onFileSelected($event)" #fileUpload>
|
||||||
|
<button mat-mini-fab color="primary" type="button" class="upload-btn" (click)="fileUpload.click()"
|
||||||
|
*ngIf="form.get('source')?.value === 'CSV'">
|
||||||
|
<mat-icon>attach_file</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-grid-list cols="5" rowHeight="90px" *ngIf="form.get('source')?.value === 'GoogleSheet'">
|
||||||
|
<mat-grid-tile>
|
||||||
|
<mat-form-field class>
|
||||||
|
<input matInput formControlName="sheetId">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-grid-tile>
|
||||||
|
<mat-grid-tile>
|
||||||
|
<button mat-mini-fab color="primary" type="button" class="upload-btn" (click)="parseGoogleSheet()">
|
||||||
|
<mat-icon>publish</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-grid-tile>
|
||||||
|
<mat-grid-tile></mat-grid-tile>
|
||||||
|
<mat-grid-tile></mat-grid-tile>
|
||||||
|
<mat-grid-tile></mat-grid-tile>
|
||||||
|
</mat-grid-list>
|
||||||
|
|
||||||
<mat-table #table [dataSource]="dataSource" [trackBy]="trackByUid" matSort class="animate">
|
<mat-table #table [dataSource]="dataSource" [trackBy]="trackByUid" matSort class="animate">
|
||||||
|
|
||||||
<ng-container matColumnDef="code">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header>MPK</mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let item">{{item.code}}</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="desc1">
|
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Konto</mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let item">{{item.desc1}}</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="value">
|
<ng-container matColumnDef="code">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Wartość</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>MPK</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let item">{{item.value | number:'1.2-2'}}</mat-cell>
|
<mat-cell *matCellDef="let item">{{item.code}}</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
<ng-container matColumnDef="desc1">
|
||||||
<mat-row *matRowDef="let item; columns: displayedColumns;"></mat-row>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>Konto</mat-header-cell>
|
||||||
</mat-table>
|
<mat-cell *matCellDef="let item">{{item.desc1}}</mat-cell>
|
||||||
<mat-paginator #paginator
|
</ng-container>
|
||||||
[pageSize]="50"
|
|
||||||
[pageSizeOptions]="[5, 10, 20]">
|
<ng-container matColumnDef="value">
|
||||||
</mat-paginator>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>Wartość</mat-header-cell>
|
||||||
</mat-card-content>
|
<mat-cell *matCellDef="let item">{{item.value | number:'1.2-2'}}</mat-cell>
|
||||||
</mat-card>
|
</ng-container>
|
||||||
</form>
|
|
||||||
</div>
|
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||||
|
<mat-row *matRowDef="let item; columns: displayedColumns;"></mat-row>
|
||||||
|
</mat-table>
|
||||||
|
<mat-paginator #paginator [pageSize]="50" [pageSizeOptions]="[5, 10, 20]">
|
||||||
|
</mat-paginator>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@@ -68,4 +68,11 @@ export class DataSetEditComponent implements OnInit {
|
|||||||
trackByUid(index: number, item: DataRow) {
|
trackByUid(index: number, item: DataRow) {
|
||||||
return item.id;
|
return item.id;
|
||||||
}
|
}
|
||||||
|
async parseGoogleSheet() {
|
||||||
|
const id = this.form.get('sheetId')?.value;
|
||||||
|
this.document.dataRows = await DataSet.parseGoogleSheet(id, this.http$);
|
||||||
|
this.dataSource = new MatTableDataSource(this.document.dataRows);
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Google.Apis.Auth;
|
using Google.Apis.Auth;
|
||||||
using Google.Apis.Http;
|
using Google.Apis.Http;
|
||||||
|
using Google.Apis.Sheets.v4;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -17,11 +18,15 @@ namespace WebAPI.Controllers
|
|||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[Authorize]
|
// [Authorize]
|
||||||
public class DataSetsController : Controller
|
public class DataSetsController : Controller
|
||||||
{
|
{
|
||||||
private readonly AppDbContext db;
|
private readonly AppDbContext db;
|
||||||
public DataSetsController(AppDbContext _db) { db = _db; }
|
private SpreadsheetsResource.ValuesResource googleSheetValues;
|
||||||
|
public DataSetsController(AppDbContext _db, GoogleSheetsHelper _googleSheetsHelper) {
|
||||||
|
db = _db;
|
||||||
|
googleSheetValues = _googleSheetsHelper.Service.Spreadsheets.Values;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult GetAll()
|
public IActionResult GetAll()
|
||||||
@@ -64,6 +69,14 @@ namespace WebAPI.Controllers
|
|||||||
return BadRequest(e.ToString());
|
return BadRequest(e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[HttpGet]
|
||||||
|
[Route("parseGoogleSheet/{sheetId}")]
|
||||||
|
public IActionResult ParseGoogleSheet(string sheetId)
|
||||||
|
{
|
||||||
|
|
||||||
|
var parser = new googleSheetParser(googleSheetValues);
|
||||||
|
return Ok(parser.parse(sheetId));
|
||||||
|
}
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[DisableRequestSizeLimit]
|
[DisableRequestSizeLimit]
|
||||||
[Route("parseFile")]
|
[Route("parseFile")]
|
||||||
|
|||||||
35
WebAPI/GoogleSheetsHelper.cs
Normal file
35
WebAPI/GoogleSheetsHelper.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Google.Apis.Auth.OAuth2;
|
||||||
|
using Google.Apis.Services;
|
||||||
|
using Google.Apis.Sheets.v4;
|
||||||
|
|
||||||
|
namespace WebAPI
|
||||||
|
{
|
||||||
|
public class GoogleSheetsHelper
|
||||||
|
{
|
||||||
|
public SheetsService Service { get; set; }
|
||||||
|
const string APPLICATION_NAME = "Diuna";
|
||||||
|
static readonly string[] Scopes = { SheetsService.Scope.Spreadsheets };
|
||||||
|
public GoogleSheetsHelper()
|
||||||
|
{
|
||||||
|
InitializeService();
|
||||||
|
}
|
||||||
|
private void InitializeService()
|
||||||
|
{
|
||||||
|
var credential = GetCredentialsFromFile();
|
||||||
|
Service = new SheetsService(new BaseClientService.Initializer()
|
||||||
|
{
|
||||||
|
HttpClientInitializer = credential,
|
||||||
|
ApplicationName = APPLICATION_NAME
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private GoogleCredential GetCredentialsFromFile()
|
||||||
|
{
|
||||||
|
GoogleCredential credential;
|
||||||
|
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
credential = GoogleCredential.FromStream(stream).CreateScoped(Scopes);
|
||||||
|
}
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,6 +53,8 @@ builder.Services.AddAuthorization();
|
|||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton(typeof(GoogleSheetsHelper));
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.Use(async (context, next) =>
|
app.Use(async (context, next) =>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
<PackageReference Include="Google.Apis.Auth" Version="1.58.0" />
|
<PackageReference Include="Google.Apis.Auth" Version="1.58.0" />
|
||||||
|
<PackageReference Include="Google.Apis.Sheets.v4" Version="1.58.0.2826" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
||||||
|
|||||||
12
WebAPI/client_secrets.json
Normal file
12
WebAPI/client_secrets.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"type": "service_account",
|
||||||
|
"project_id": "diuna-370117",
|
||||||
|
"private_key_id": "f48fd588724e6733b9639fe7d7933091b96be34f",
|
||||||
|
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCenqveXpGKXA10\npsAQ4Wreeiom9GMbZywnqMAhxc0wobI7EfnbP4FPOjfS8oWFRRrVzRil78zeUGWX\nb1WMHYvUyU3IrGXp6kVxuxbjBvwooOB5cEgz928A3aUUZRXxwjPV3+KuuAeQydVw\nPMQo2a0AQ+YAOK2QMG+BGAPAzYB+/35Zf6JsDOIDgWMaJq3etKgIijk40Nmf+uaG\nRAQlEbMhnAaAYz2B6I7W3z0pFDq2btgYJII+DWRC2DjSrA4UUeuds8Kz5qwfafJ8\nki9N1RdYdbB/q6T74xQ3G/aEOK+CYmkWQz2woY5y8b5RCbKoGGIXpu6FVuWTnVxY\nJpP5QvIFAgMBAAECggEAJC3Evb+MKqa8WvL9s9v2aDAtFR2AzWtG4vTWfd2D46e9\n40NCXgOqFswMl4zBb5hHeqSBDrgXXk2wHk5CkObcUfhoSXEo/aV1mW821SluskWf\nbZNypIe3RddII9K6op3M/OdH6NoIv7mJeUQi6b5ce0cBWuOSkuS5ShSUJpG40T5R\nQfl0iMuEYDpU1tvKmwhFlPTUTUGH7RdeqGFYIfE3kzFQiiSrS8V5L1GJKWcxMLdT\nq4P9JzaSW7eAAYKJiFTMSQvqs7pssCIj1JNLzD9PTsQmid2V2mUJIg3joXMNGbxN\nqMcIqbEesidIsDOkQ06taUIYG39og6rc9bar6XWRgQKBgQDK/+a8jCmUByhedUT5\nZnREtHm4HcVo1tfBcmmqSEV0VJPJd14+CYvaUzCCJ9+xiLo6yOWRUk2h1GANAp50\nAdiVAHNibfwtri7vKWNhpnd111N/ebh6GIksT0ZTvu7sq5qbYXU3q6l6YRCyXSdF\n1oRfQED8I8G1xZP5j6fspBgoKQKBgQDICIKo3gmUEeFSt+o+Lucd2BljaFq/hUMA\n6WFdKbRyyd2iKBmGR15VNihiuJWy5i2nmuFaXMkeHo/PUJeEYC+vkc7M7UCYtD9l\n2xwp78o3ss7vxdPvOKhrcvux/Wpk1nuAEpM459MC0bmtOGIKU+QmDbsBbMHZ6p0R\n8DvECJ9mfQKBgEj60PAOD9CY9ilnTYHAFKKyo2POyC7VtkFkqZo/W0DkOzFdybLR\n6cZ2y+SvAxunRRRnLykchq5cVJ+4xlB8bWm7/L9xPQ0LJvJyVblAiIgD/o/AqdKz\nSXV1lpn69Zh+ZRnhYqu9+jL1/HOzS7Au2+4GgpZjIHwB6R36SGup3slpAoGAZW2j\nSxsjQjh6x2XIWfWQbVqZLQXKFhjta7XrD8FI5XekcUfiAWuI0q5edghgp9D9T2JC\naH5p4GLgyt9zpMTdCSpm8RRQT93905jxw/X51JpPQddO6psRE0K/i3YTD8SN5NgG\nXLF4FpLfkozncZMuOXl23HcYKHZFZMYql/FDWkUCgYAjGQKzYV7IXA7UDAY3ejaw\nWMbsDttSPQ0E1ouuJWIX/eb4SXYr0u/gdLuX1uM7EsxqIGVFWfgtUGopoVGr604S\ng+dfOPZgUzaGAlUE2iRMVp6YoRRbrvPsYJwDrV0Xwil1k6UEzn8bgXO/IQ4fgIWj\nkxS5sDkZ6LVSCfDn5tLThg==\n-----END PRIVATE KEY-----\n",
|
||||||
|
"client_email": "diuna-backend@diuna-370117.iam.gserviceaccount.com",
|
||||||
|
"client_id": "101546901561736131820",
|
||||||
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
"token_uri": "https://oauth2.googleapis.com/token",
|
||||||
|
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||||
|
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/diuna-backend%40diuna-370117.iam.gserviceaccount.com"
|
||||||
|
}
|
||||||
43
WebAPI/dataParsers/googleSheet.parser.cs
Normal file
43
WebAPI/dataParsers/googleSheet.parser.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using Google.Apis.Sheets.v4;
|
||||||
|
using System.Globalization;
|
||||||
|
using WebAPI.Models;
|
||||||
|
|
||||||
|
namespace WebAPI.dataParsers
|
||||||
|
{
|
||||||
|
public class googleSheetParser
|
||||||
|
{
|
||||||
|
private SpreadsheetsResource.ValuesResource googleSheetValues;
|
||||||
|
|
||||||
|
public googleSheetParser(SpreadsheetsResource.ValuesResource _googleSheetValues)
|
||||||
|
{
|
||||||
|
googleSheetValues = _googleSheetValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DataRow> parse(string sheetId)
|
||||||
|
{
|
||||||
|
var range = "Arkusz1!A:B";
|
||||||
|
|
||||||
|
var request = googleSheetValues.Get(sheetId, range);
|
||||||
|
var response = request.Execute();
|
||||||
|
var data = response.Values;
|
||||||
|
|
||||||
|
List<DataRow> dataRows = new List<DataRow>();
|
||||||
|
|
||||||
|
for (int i = 1; i < data.Count; i++)
|
||||||
|
{
|
||||||
|
float value = float.Parse(data[i][1].ToString(), CultureInfo.GetCultureInfo("pl-PL"));
|
||||||
|
if (value > 0)
|
||||||
|
{
|
||||||
|
DataRow dataRow = new DataRow();
|
||||||
|
dataRow.Id = Guid.NewGuid();
|
||||||
|
dataRow.Code = data[i][0].ToString();
|
||||||
|
dataRow.Value = value;
|
||||||
|
dataRow.CreatedAt = DateTime.UtcNow;
|
||||||
|
dataRow.ModifiedAt = DateTime.UtcNow;
|
||||||
|
dataRows.Add(dataRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataRows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user