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 { MatSnackBar } from '@angular/material/snack-bar';
import { environment } from 'src/environments/environment';
import { User } from '../models/user.model';
@@ -12,7 +13,7 @@ export class AuthService {
user!: User;
constructor(
private http$: HttpClient
private http$: HttpClient,
) { }
ping() {
@@ -33,20 +34,17 @@ export class AuthService {
getAPIToken(credentials: string): Promise<void> {
return new Promise((resolve, reject) => {
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) => {
this.user.id = data.id;
this.apiToken = data.token;
resolve(data);
},
error: (e) => {
console.error('apiToken error', e);
error: (e: HttpErrorResponse) => {
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="bg">
<div class="container">

View File

@@ -1,4 +1,6 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, NgZone, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import jwt_decode from "jwt-decode";
import { AuthService } from 'src/app/auth/auth.service';
@@ -14,34 +16,37 @@ import { environment } from 'src/environments/environment';
export class LoginPageComponent implements OnInit {
constructor(
private data$: DataService,
private router$: Router,
private auth$: AuthService,
private ngZone$: NgZone
) {}
private ngZone$: NgZone,
private snackBar$: MatSnackBar
) { }
loading: boolean = false;
ngOnInit(): void {
this.snackBar$.open("", "", { duration: 1 });
// @ts-ignore
window.onGoogleLibraryLoad = () => {
// @ts-ignore
window.onGoogleLibraryLoad = () => {
// @ts-ignore
google.accounts.id.initialize({
client_id: environment.google.clientId,
callback: this.handleCredentialResponse.bind(this),
auto_select: true,
cancel_on_tap_outside: true
});
// @ts-ignore
google.accounts.id.renderButton(
google.accounts.id.initialize({
client_id: environment.google.clientId,
callback: this.handleCredentialResponse.bind(this),
auto_select: true,
cancel_on_tap_outside: true
});
// @ts-ignore
google.accounts.id.renderButton(
// @ts-ignore
document.getElementById("google-button"),
{ theme: "outline", size: "large", width: "100%" }
);
// @ts-ignore
google.accounts.id.prompt((notification: PromptMomentNotification) => {});
};
{ theme: "outline", size: "large", width: "100%" }
);
// @ts-ignore
google.accounts.id.prompt((notification: PromptMomentNotification) => { });
};
}
async handleCredentialResponse(response: any) {
async handleCredentialResponse(response: any) {
try {
const responsePayload: any = jwt_decode(response.credential);
this.auth$.user = new User({
@@ -50,12 +55,20 @@ export class LoginPageComponent implements OnInit {
email: responsePayload.email,
avatar: responsePayload.picture
});
this.ngZone$.run(() => {
this.loading = true;
await this.auth$.getAPIToken(response.credential);
this.ngZone$.run(() => {
this.router$.navigate(['/app']);
});
await this.auth$.getAPIToken(response.credential);
} catch (e) {
console.error('Get user error', e);
} catch (e: any) {
this.loading = false;
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() {
// @ts-ignore
google.accounts.id.disableAutoSelect();
this.router$.navigate(['']);
this.auth$.user = new User({});
this.reloadApp();
}
}

View File

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

View File

@@ -2,12 +2,12 @@ import { Base } from './base.model';
import { UntypedFormBuilder, Validators, UntypedFormGroup } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';
import { DataService } from '../services/data.service';
import { map } from 'rxjs';
import { DataRow } from './dataRow.model copy';
export class DataSet extends Base {
number?: string;
number?: Number;
source?: string;
name?: string;
dataRows: DataRow[] = [];
@@ -22,8 +22,8 @@ export class DataSet extends Base {
static getForm(fb: UntypedFormBuilder) {
return fb.group({
id: [null],
number: ['', Validators.required],
name: ['', Validators.required],
source: ['', Validators.required],
createdAt: '',
modifiedAt: '',
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> {
return new Promise((resolve, reject)=> {

View File

@@ -2,7 +2,7 @@
<form [formGroup]="form" (ngSubmit)="save()" novalidate>
<mat-card appearance="outlined">
<mat-toolbar color="secondary">
Edycja zbioru danych
Edycja warstwy danych
<span class="fill-to-right"></span>
<button mat-button type="submit" [disabled]="form.invalid">Zapisz</button>
<button mat-button type="button" routerLink="../..">Anuluj</button>
@@ -11,9 +11,9 @@
<mat-grid-list cols="2" rowHeight="90px">
<mat-grid-tile>
<mat-form-field class="detail-input">
<mat-label>Numer</mat-label>
<input matInput formControlName="number">
<mat-error *ngIf="form.controls['number'].touched && form.controls['number'].invalid">
<mat-label>Nazwa</mat-label>
<input matInput formControlName="name">
<mat-error *ngIf="form.controls['name'].touched && form.controls['name'].invalid">
Pole obowiązkowe
</mat-error>
</mat-form-field>
@@ -21,19 +21,48 @@
<mat-grid-tile>
<mat-form-field class="detail-input">
<mat-select placeholder="Źródło" formControlName="name" (selectionChange)="generateNumber()">
<mat-option value="Import ręczny">Import ręczny</mat-option>
<mat-option value="Arkusz Google">Arkusz Google</mat-option>
<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['name'].touched && form.controls['name'].invalid">
<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()">
<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>
</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 { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
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 moment from 'moment';
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 { DataService } from 'src/app/services/data.service';
import { v4 as uuidv4 } from 'uuid';
@@ -19,6 +23,12 @@ export class DataSetEditComponent implements OnInit {
public form!: UntypedFormGroup;
private document!: DataSet;
displayedColumns = ['code', 'value', 'desc1'];
dataSource!: MatTableDataSource<DataRow>;
@ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort;
constructor(
private fb$: UntypedFormBuilder,
private router$: Router,
@@ -62,7 +72,17 @@ export class DataSetEditComponent implements OnInit {
}
generateNumber() {
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
{
return BadRequest();
return Unauthorized();
}
}

View File

@@ -9,6 +9,7 @@ using System.Configuration;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using WebAPI.dataParsers;
using WebAPI.Models;
namespace WebAPI.Controllers
@@ -33,5 +34,13 @@ namespace WebAPI.Controllers
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()
.HasColumnType("uniqueidentifier");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
@@ -55,10 +59,6 @@ namespace WebAPI.Migrations
b.Property<bool>("IsDeleted")
.HasColumnType("bit");
b.Property<string>("MPK")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTime>("ModifiedAt")
.HasColumnType("datetime2");
@@ -101,9 +101,14 @@ namespace WebAPI.Migrations
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Number")
b.Property<int?>("Number")
.IsRequired()
.HasColumnType("int");
b.Property<string>("Source")
.IsRequired()
.HasColumnType("nvarchar(max)");

View File

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

View File

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

View File

@@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="Google.Apis.Auth" Version="1.58.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" 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;
}
}
}