Login fix and rename columns in DB

This commit is contained in:
2022-12-19 18:36:57 +01:00
parent 120abcaf1d
commit db13b1ab1b
18 changed files with 480 additions and 56 deletions

View File

@@ -1,5 +1,6 @@
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { environment } from 'src/environments/environment'; import { environment } from 'src/environments/environment';
import { User } from '../models/user.model'; import { User } from '../models/user.model';
@@ -12,7 +13,7 @@ export class AuthService {
user!: User; user!: User;
constructor( constructor(
private http$: HttpClient private http$: HttpClient,
) { } ) { }
ping() { ping() {
@@ -33,20 +34,17 @@ export class AuthService {
getAPIToken(credentials: string): Promise<void> { getAPIToken(credentials: string): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const header = new HttpHeaders().set('Content-type', 'application/json'); const header = new HttpHeaders().set('Content-type', 'application/json');
this.http$.post<any>(`${environment.api.url}/auth/apiToken`, JSON.stringify(credentials), { headers: header }).subscribe({ this.http$.post<any>(`${environment.api.url}/auth/apiToken`, JSON.stringify(credentials), { headers: header }).subscribe({
next: (data) => { next: (data) => {
this.user.id = data.id; this.user.id = data.id;
this.apiToken = data.token; this.apiToken = data.token;
resolve(data); resolve(data);
}, },
error: (e) => { error: (e: HttpErrorResponse) => {
console.error('apiToken error', e);
reject(e); reject(e);
} }
} }
); );
}); });
//const header = new HttpHeaders().set('Content-type', 'application/json');
//return this.httpClient.post(this.path + "LoginWithGoogle", JSON.stringify(credentials), { headers: header });
} }
} }

View File

@@ -1,3 +1,6 @@
<div class="loading-container" *ngIf="loading">
<img class="loading-img" src="../../assets/loader.gif" />
</div>
<div class="logo"></div> <div class="logo"></div>
<div class="bg"> <div class="bg">
<div class="container"> <div class="container">

View File

@@ -1,4 +1,6 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, NgZone, OnInit } from '@angular/core'; import { Component, NgZone, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import jwt_decode from "jwt-decode"; import jwt_decode from "jwt-decode";
import { AuthService } from 'src/app/auth/auth.service'; import { AuthService } from 'src/app/auth/auth.service';
@@ -14,34 +16,37 @@ import { environment } from 'src/environments/environment';
export class LoginPageComponent implements OnInit { export class LoginPageComponent implements OnInit {
constructor( constructor(
private data$: DataService,
private router$: Router, private router$: Router,
private auth$: AuthService, private auth$: AuthService,
private ngZone$: NgZone private ngZone$: NgZone,
) {} private snackBar$: MatSnackBar
) { }
loading: boolean = false;
ngOnInit(): void { ngOnInit(): void {
this.snackBar$.open("", "", { duration: 1 });
// @ts-ignore
window.onGoogleLibraryLoad = () => {
// @ts-ignore // @ts-ignore
window.onGoogleLibraryLoad = () => { google.accounts.id.initialize({
// @ts-ignore client_id: environment.google.clientId,
google.accounts.id.initialize({ callback: this.handleCredentialResponse.bind(this),
client_id: environment.google.clientId, auto_select: true,
callback: this.handleCredentialResponse.bind(this), cancel_on_tap_outside: true
auto_select: true, });
cancel_on_tap_outside: true // @ts-ignore
}); google.accounts.id.renderButton(
// @ts-ignore
google.accounts.id.renderButton(
// @ts-ignore // @ts-ignore
document.getElementById("google-button"), document.getElementById("google-button"),
{ theme: "outline", size: "large", width: "100%" } { theme: "outline", size: "large", width: "100%" }
); );
// @ts-ignore // @ts-ignore
google.accounts.id.prompt((notification: PromptMomentNotification) => {}); google.accounts.id.prompt((notification: PromptMomentNotification) => { });
}; };
} }
async handleCredentialResponse(response: any) { async handleCredentialResponse(response: any) {
try { try {
const responsePayload: any = jwt_decode(response.credential); const responsePayload: any = jwt_decode(response.credential);
this.auth$.user = new User({ this.auth$.user = new User({
@@ -50,12 +55,20 @@ export class LoginPageComponent implements OnInit {
email: responsePayload.email, email: responsePayload.email,
avatar: responsePayload.picture avatar: responsePayload.picture
}); });
this.ngZone$.run(() => { this.loading = true;
await this.auth$.getAPIToken(response.credential);
this.ngZone$.run(() => {
this.router$.navigate(['/app']); this.router$.navigate(['/app']);
}); });
await this.auth$.getAPIToken(response.credential); } catch (e: any) {
} catch (e) { this.loading = false;
console.error('Get user error', e); if (e.status === 401) {
this.snackBar$.open("Użytkownik nie istnieje w bazie danych aplikacji Diuna.", "", { duration: 3000 });
} else {
this.snackBar$.open("Błąd połączenia z serwerem. Skontaktuj się z administratorem.", "", { duration: 3000 });
}
} finally {
this.loading = false;
} }
} }
} }

View File

@@ -53,7 +53,6 @@ export class MainViewComponent {
logout() { logout() {
// @ts-ignore // @ts-ignore
google.accounts.id.disableAutoSelect(); google.accounts.id.disableAutoSelect();
this.router$.navigate(['']); this.reloadApp();
this.auth$.user = new User({});
} }
} }

View File

@@ -6,7 +6,7 @@ import { DataService } from '../services/data.service';
import { map } from 'rxjs'; import { map } from 'rxjs';
export class DataRow extends Base { export class DataRow extends Base {
mpk?: string; code?: string;
value?: number; value?: number;
desc1?: string; desc1?: string;
desc2?: string; desc2?: string;

View File

@@ -2,12 +2,12 @@ import { Base } from './base.model';
import { UntypedFormBuilder, Validators, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, Validators, UntypedFormGroup } from '@angular/forms';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment'; import { environment } from 'src/environments/environment';
import { DataService } from '../services/data.service';
import { map } from 'rxjs'; import { map } from 'rxjs';
import { DataRow } from './dataRow.model copy'; import { DataRow } from './dataRow.model copy';
export class DataSet extends Base { export class DataSet extends Base {
number?: string; number?: Number;
source?: string;
name?: string; name?: string;
dataRows: DataRow[] = []; dataRows: DataRow[] = [];
@@ -22,8 +22,8 @@ export class DataSet extends Base {
static getForm(fb: UntypedFormBuilder) { static getForm(fb: UntypedFormBuilder) {
return fb.group({ return fb.group({
id: [null], id: [null],
number: ['', Validators.required],
name: ['', Validators.required], name: ['', Validators.required],
source: ['', Validators.required],
createdAt: '', createdAt: '',
modifiedAt: '', modifiedAt: '',
createdBy: '', createdBy: '',
@@ -84,6 +84,20 @@ export class DataSet extends Base {
}) })
}); });
} }
static parseFile(file: any, _http: HttpClient): Promise<DataRow[]> {
const formData = new FormData();
formData.append(file.name, file);
return new Promise((resolve, reject) => {
_http.post<DataRow[]>(`${environment.api.url}/datasets/parseFile`, formData,
).pipe(map(data => data.map(x => new DataRow().deserialize(x))))
.subscribe({
next: (data) => {
resolve(data);
},
error: (e) => reject(e)
})
})
}
/* /*
static delete(id: string, _http: HttpClient): Promise<string> { static delete(id: string, _http: HttpClient): Promise<string> {
return new Promise((resolve, reject)=> { return new Promise((resolve, reject)=> {

View File

@@ -2,7 +2,7 @@
<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 zbioru 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>
@@ -11,9 +11,9 @@
<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>Numer</mat-label> <mat-label>Nazwa</mat-label>
<input matInput formControlName="number"> <input matInput formControlName="name">
<mat-error *ngIf="form.controls['number'].touched && form.controls['number'].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>
@@ -21,19 +21,48 @@
<mat-grid-tile> <mat-grid-tile>
<mat-form-field class="detail-input"> <mat-form-field class="detail-input">
<mat-select placeholder="Źródło" formControlName="name" (selectionChange)="generateNumber()"> <mat-select placeholder="Źródło" formControlName="source" (selectionChange)="generateNumber()">
<mat-option value="Import ręczny">Import ręczny</mat-option> <mat-option value="CSV">CSV</mat-option>
<mat-option value="Arkusz Google">Arkusz Google</mat-option> <mat-option value="GoogleSheet">GoogleSheet</mat-option>
<mat-option value="SAP">SAP</mat-option> <mat-option value="SAP">SAP</mat-option>
<mat-option value="Symfonia">Symfonia</mat-option> <mat-option value="Symfonia">Symfonia</mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="form.controls['name'].touched && form.controls['name'].invalid"> <mat-error *ngIf="form.controls['source'].touched && form.controls['source'].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-list> </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()">
<mat-icon>attach_file</mat-icon>
</button>
<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">
<mat-header-cell *matHeaderCellDef mat-sort-header>Wartość</mat-header-cell>
<mat-cell *matCellDef="let item">{{item.value | number:'1.2-2'}}</mat-cell>
</ng-container>
<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-content>
</mat-card> </mat-card>
</form> </form>

View File

@@ -1 +1,5 @@
@import "../../../main-view/main-view.component.scss"; @import "../../../main-view/main-view.component.scss";
.file-input {
display: none;
}

View File

@@ -1,10 +1,14 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import moment from 'moment'; import moment from 'moment';
import { AuthService } from 'src/app/auth/auth.service'; import { AuthService } from 'src/app/auth/auth.service';
import { DataRow } from 'src/app/models/dataRow.model copy';
import { DataSet } from 'src/app/models/dataSet.model'; import { DataSet } from 'src/app/models/dataSet.model';
import { DataService } from 'src/app/services/data.service'; import { DataService } from 'src/app/services/data.service';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@@ -19,6 +23,12 @@ export class DataSetEditComponent implements OnInit {
public form!: UntypedFormGroup; public form!: UntypedFormGroup;
private document!: DataSet; private document!: DataSet;
displayedColumns = ['code', 'value', 'desc1'];
dataSource!: MatTableDataSource<DataRow>;
@ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort;
constructor( constructor(
private fb$: UntypedFormBuilder, private fb$: UntypedFormBuilder,
private router$: Router, private router$: Router,
@@ -62,7 +72,17 @@ export class DataSetEditComponent implements OnInit {
} }
generateNumber() { generateNumber() {
this.form.patchValue({ this.form.patchValue({
number: `${this.form.controls['name'].value}-${moment().format("YYYY")}-${moment().format("MM")}` name: `${this.form.controls['source'].value}-${moment().format("YYYY")}${moment().format("MM")}${moment().format("DD")}${moment().format("HH")}${moment().format("mm")}`
}) })
} }
async onFileSelected(event : any) {
const file = event.target.files[0];
this.document.dataRows = await DataSet.parseFile(file, this.http$);
this.dataSource = new MatTableDataSource(this.document.dataRows);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
trackByUid(index : number, item : DataRow) {
return item.id;
}
} }

View File

@@ -40,7 +40,7 @@ namespace WebAPI.Controllers
} }
else else
{ {
return BadRequest(); return Unauthorized();
} }
} }

View File

@@ -9,6 +9,7 @@ using System.Configuration;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using WebAPI.dataParsers;
using WebAPI.Models; using WebAPI.Models;
namespace WebAPI.Controllers namespace WebAPI.Controllers
@@ -33,5 +34,13 @@ namespace WebAPI.Controllers
return BadRequest(e.ToString()); return BadRequest(e.ToString());
} }
} }
[HttpPost]
[DisableRequestSizeLimit]
[Route("parseFile")]
public IActionResult ParseFile()
{
var parser = new csvParser();
return Ok(parser.parse(Request.Form.Files[0]));
}
} }
} }

View File

@@ -0,0 +1,197 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using WebAPI;
#nullable disable
namespace WebAPI.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20221219163620_RenameFields")]
partial class RenameFields
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("WebAPI.Models.DataRow", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid>("CreatedById")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("DataSetId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Desc1")
.HasColumnType("nvarchar(max)");
b.Property<string>("Desc2")
.HasColumnType("nvarchar(max)");
b.Property<string>("Desc3")
.HasColumnType("nvarchar(max)");
b.Property<string>("Desc4")
.HasColumnType("nvarchar(max)");
b.Property<string>("Desc5")
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<DateTime>("ModifiedAt")
.HasColumnType("datetime2");
b.Property<Guid>("ModifiedById")
.HasColumnType("uniqueidentifier");
b.Property<float>("Value")
.HasColumnType("real");
b.HasKey("Id");
b.HasIndex("CreatedById");
b.HasIndex("DataSetId");
b.HasIndex("ModifiedById");
b.ToTable("DataRows");
});
modelBuilder.Entity("WebAPI.Models.DataSet", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<Guid>("CreatedById")
.HasColumnType("uniqueidentifier");
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<DateTime>("ModifiedAt")
.HasColumnType("datetime2");
b.Property<Guid>("ModifiedById")
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("Number")
.IsRequired()
.HasColumnType("int");
b.Property<string>("Source")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.HasIndex("CreatedById");
b.HasIndex("ModifiedById");
b.ToTable("DataSets");
});
modelBuilder.Entity("WebAPI.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<string>("Email")
.HasColumnType("nvarchar(max)");
b.Property<string>("UserName")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("WebAPI.Models.DataRow", b =>
{
b.HasOne("WebAPI.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("WebAPI.Models.DataSet", null)
.WithMany("DataRows")
.HasForeignKey("DataSetId");
b.HasOne("WebAPI.Models.User", "ModifiedBy")
.WithMany()
.HasForeignKey("ModifiedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreatedBy");
b.Navigation("ModifiedBy");
});
modelBuilder.Entity("WebAPI.Models.DataSet", b =>
{
b.HasOne("WebAPI.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("WebAPI.Models.User", "ModifiedBy")
.WithMany()
.HasForeignKey("ModifiedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreatedBy");
b.Navigation("ModifiedBy");
});
modelBuilder.Entity("WebAPI.Models.DataSet", b =>
{
b.Navigation("DataRows");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,73 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace WebAPI.Migrations
{
/// <inheritdoc />
public partial class RenameFields : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "MPK",
table: "DataRows",
newName: "Code");
migrationBuilder.AlterColumn<int>(
name: "Number",
table: "DataSets",
type: "int",
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DataSets",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AddColumn<string>(
name: "Source",
table: "DataSets",
type: "nvarchar(max)",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Source",
table: "DataSets");
migrationBuilder.RenameColumn(
name: "Code",
table: "DataRows",
newName: "MPK");
migrationBuilder.AlterColumn<string>(
name: "Number",
table: "DataSets",
type: "nvarchar(max)",
nullable: false,
oldClrType: typeof(int),
oldType: "int");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "DataSets",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
}
}
}

View File

@@ -28,6 +28,10 @@ namespace WebAPI.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreatedAt") b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@@ -55,10 +59,6 @@ namespace WebAPI.Migrations
b.Property<bool>("IsDeleted") b.Property<bool>("IsDeleted")
.HasColumnType("bit"); .HasColumnType("bit");
b.Property<string>("MPK")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("ModifiedAt") b.Property<DateTime>("ModifiedAt")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@@ -101,9 +101,14 @@ namespace WebAPI.Migrations
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<string>("Number") b.Property<int?>("Number")
.IsRequired()
.HasColumnType("int");
b.Property<string>("Source")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");

View File

@@ -8,7 +8,7 @@ namespace WebAPI.Models
[Key] [Key]
public Guid Id { get; set; } public Guid Id { get; set; }
[Required] [Required]
public string? MPK { get; set; } public string? Code { get; set; }
[Required] [Required]
public float Value { get; set; } public float Value { get; set; }
//Description fields //Description fields
@@ -22,8 +22,10 @@ namespace WebAPI.Models
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
#endregion #endregion
#region Relations #region Relations
[Required]
public Guid CreatedById { get; set; } public Guid CreatedById { get; set; }
public User? CreatedBy { get; set; } public User? CreatedBy { get; set; }
[Required]
public Guid ModifiedById { get; set; } public Guid ModifiedById { get; set; }
public User? ModifiedBy { get; set; } public User? ModifiedBy { get; set; }
#endregion #endregion

View File

@@ -8,16 +8,24 @@ namespace WebAPI.Models
[Key] [Key]
public Guid Id { get; set; } public Guid Id { get; set; }
[Required] [Required]
public string? Number { get; set; } public int? Number { get; set; }
[Required]
public string? Source { get; set; }
[Required]
public string? Name { get; set; } public string? Name { get; set; }
[Required]
public DateTime CreatedAt { get; set; } public DateTime CreatedAt { get; set; }
[Required]
public DateTime ModifiedAt { get; set; } public DateTime ModifiedAt { get; set; }
[Required]
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
#endregion #endregion
#region Relations #region Relations
public ICollection<DataRow>? DataRows { get; set; } public ICollection<DataRow>? DataRows { get; set; }
[Required]
public Guid CreatedById { get; set; } public Guid CreatedById { get; set; }
public User? CreatedBy { get; set; } public User? CreatedBy { get; set; }
[Required]
public Guid ModifiedById { get; set; } public Guid ModifiedById { get; set; }
public User? ModifiedBy { get; set; } public User? ModifiedBy { get; set; }
#endregion #endregion

View File

@@ -7,6 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<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="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" />

View File

@@ -0,0 +1,49 @@
using CsvHelper;
using CsvHelper.Configuration;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.Formats.Asn1;
using System.Globalization;
using System.Text;
using WebAPI.Models;
namespace WebAPI.dataParsers
{
public class csvParser
{
public List<DataRow> parse(IFormFile file)
{
List<DataRow> dataRows = new List<DataRow>();
var stream = new StreamReader(file.OpenReadStream());
string content = stream.ReadToEnd();
List<string> lines = content.Split("\n").ToList();
List<List<string>> data = new List<List<string>>();
foreach (string line in lines)
{
data.Add(line.Split(";").ToList());
}
for (int i = 1; i < data[0].Count; i++)
{
for (int j = 1; j < data.Count; j++) {
if (data[j][0].Length > 0)
{
float value = float.Parse(data[j][i]);
if (value > 0)
{
DataRow dataRow = new DataRow();
dataRow.Id = Guid.NewGuid();
dataRow.Code = data[0][i];
dataRow.Desc1 = data[j][0];
dataRow.Value = value;
dataRows.Add(dataRow);
}
}
};
}
return dataRows;
}
}
}