last version-refactoring

parent 123c4383
...@@ -5985,6 +5985,14 @@ ...@@ -5985,6 +5985,14 @@
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true "dev": true
}, },
"ng-lazyload-image": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/ng-lazyload-image/-/ng-lazyload-image-9.1.2.tgz",
"integrity": "sha512-E5oz5HdTRtYW/TH+jceT4VMcRXKdX9Ut82eEwt2K0/bFAXKU14HluCFa8cMidPBgSa08Mlf+gmoKCTvAfUPgag==",
"requires": {
"tslib": "^2.3.0"
}
},
"nice-napi": { "nice-napi": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"@ngxs/storage-plugin": "^3.5.0", "@ngxs/storage-plugin": "^3.5.0",
"@ngxs/store": "^3.5.0", "@ngxs/store": "^3.5.0",
"lazysizes": "^5.3.2", "lazysizes": "^5.3.2",
"ng-lazyload-image": "^9.1.2",
"primeflex": "~3.1.3", "primeflex": "~3.1.3",
"primeicons": "~5.0.0", "primeicons": "~5.0.0",
"primeng": "~13.2.1", "primeng": "~13.2.1",
......
...@@ -6,15 +6,17 @@ import {AddResourceComponent} from "./component/add-resource/add-resource.compon ...@@ -6,15 +6,17 @@ import {AddResourceComponent} from "./component/add-resource/add-resource.compon
import {ApproveResourceComponent} from "./component/approve-resource/approve-resource.component"; import {ApproveResourceComponent} from "./component/approve-resource/approve-resource.component";
import {LoginComponent} from "./component/login/login.component"; import {LoginComponent} from "./component/login/login.component";
import {AuthGuard} from "./guard/auth.guard"; import {AuthGuard} from "./guard/auth.guard";
import {ChangePasswordComponent} from "./component/change-password/change-password.component";
const routes: Routes = [ const routes: Routes = [
{path: '', component: HomeComponent, pathMatch: 'full'}, {path: '', component: HomeComponent, pathMatch: 'full'},
{path: 'home', component: HomeComponent, pathMatch: 'full',runGuardsAndResolvers: 'always'}, {path: 'home', component: HomeComponent, pathMatch: 'full'},
{path:'resource/approve', component:ApproveResourceComponent, pathMatch:'full',canActivate:[AuthGuard]}, {path:'resource/approve', component:ApproveResourceComponent, pathMatch:'full',canActivate:[AuthGuard]},
{path:'resource/add', component:AddResourceComponent, pathMatch:'full'}, {path:'resource/add', component:AddResourceComponent, pathMatch:'full'},
{path:'resource/edit/:id',component:AddResourceComponent,pathMatch:'full',canActivate:[AuthGuard]},
{path:'resource/:id', component:ResourceComponent, pathMatch:'full'}, {path:'resource/:id', component:ResourceComponent, pathMatch:'full'},
{path:'login', component:LoginComponent, pathMatch:'full'}, {path:'login', component:LoginComponent, pathMatch:'full'},
{path:'changePassword/:token', component:ChangePasswordComponent, pathMatch:'full'}
......
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
<div class="container-fluid py-4"> <div class="container-fluid py-4">
<router-outlet></router-outlet> <router-outlet></router-outlet>
</div> </div>
<app-footer></app-footer>
...@@ -47,7 +47,10 @@ import {ImageModule} from "primeng/image"; ...@@ -47,7 +47,10 @@ import {ImageModule} from "primeng/image";
import {ConfirmPopupModule} from 'primeng/confirmpopup'; import {ConfirmPopupModule} from 'primeng/confirmpopup';
import {ConfirmationService} from 'primeng/api'; import {ConfirmationService} from 'primeng/api';
import {ConfirmDialogModule} from "primeng/confirmdialog"; import {ConfirmDialogModule} from "primeng/confirmdialog";
import {LAZYLOAD_IMAGE_HOOKS, LazyLoadImageModule, ScrollHooks} from 'ng-lazyload-image';
import { FooterComponent } from './component/footer/footer.component';
import { ChangePasswordComponent } from './component/change-password/change-password.component';
import { CheckPasswordDirective } from './validator/check-password.directive';
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -57,7 +60,10 @@ import {ConfirmDialogModule} from "primeng/confirmdialog"; ...@@ -57,7 +60,10 @@ import {ConfirmDialogModule} from "primeng/confirmdialog";
AddResourceComponent, AddResourceComponent,
ApproveResourceComponent, ApproveResourceComponent,
LoginComponent, LoginComponent,
HeaderMenuComponent HeaderMenuComponent,
FooterComponent,
ChangePasswordComponent,
CheckPasswordDirective
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
...@@ -100,9 +106,11 @@ import {ConfirmDialogModule} from "primeng/confirmdialog"; ...@@ -100,9 +106,11 @@ import {ConfirmDialogModule} from "primeng/confirmdialog";
ToastModule, ToastModule,
ImageModule, ImageModule,
ConfirmPopupModule, ConfirmPopupModule,
ConfirmDialogModule ConfirmDialogModule,
LazyLoadImageModule
], ],
providers: [MessageService,ConfirmationService,{ providers: [MessageService,ConfirmationService,
{
provide: LocationStrategy, useClass: HashLocationStrategy, provide: LocationStrategy, useClass: HashLocationStrategy,
},{ },{
provide: HTTP_INTERCEPTORS, provide: HTTP_INTERCEPTORS,
......
.imageSizeHome{
max-width: 100%;
max-height: 120px;
display: block;
margin-left: auto;
margin-right: auto;
}
<div class="card pt-6 pl-6 pr-6"> <div class="card pt-6 pl-6 pr-6">
<p class="text-3xl"> Add resource</p> <p *ngIf="(!edit)" class="text-3xl"> Add resource</p>
<p *ngIf="(edit)" class="text-3xl"> Edit resource</p>
<form #resourceForm="ngForm" (ngSubmit)="saveResource()"> <form #resourceForm="ngForm" (ngSubmit)="saveResource()">
<div class="p-fluid"> <div class="p-fluid">
<div class="field grid"> <div class="field grid">
...@@ -103,14 +104,39 @@ ...@@ -103,14 +104,39 @@
<div class="field grid"> <div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0">Language</label> <label class="col-12 mb-2 md:col-2 md:mb-0">Language</label>
<div class="col-12 md:col-10"> <div class="col-12 md:col-10">
<p-dropdown [options]="languages" optionLabel="name" name="language" placeholder="Select language" [(ngModel)]="resource.language"></p-dropdown> <p-dropdown [options]="languages" optionLabel="name" name="languages" placeholder="Select language" [(ngModel)]="resource.language"></p-dropdown>
</div> </div>
</div> </div>
<div class="field grid"> <div *ngIf="logoExist" class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0">Project logo</label>
<div class="col-12 md:col-10">
<p-fileUpload name="logo" (onRemove) = removeLogo() [maxFileSize]=5242880 chooseLabel="Change project logo" (onSelect)=hideOldLogo() [previewWidth]=250 [auto]=true accept="image/*" [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('logo',$event)">
<ng-template pTemplate="content" let-files >
<p-image [src]="imagePath+'/'+resource.idResource+'/logo'" *ngIf="showOldLogo" [preview]="true" width="250"></p-image>
</ng-template>
</p-fileUpload>
</div>
</div>
<div class="field grid" *ngIf="!edit || !logoExist">
<label class="col-12 mb-2 md:col-2 md:mb-0">Upload project logo</label>
<div class="col-12 md:col-10">
<p-fileUpload name="logo" [previewWidth]=250 [auto]=true accept="image/*" [maxFileSize]=5242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('logo',$event)"></p-fileUpload>
</div>
</div>
<div *ngIf="imageExist" class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0">Uploaded image</label>
<div class="col-12 md:col-10">
<p-fileUpload name="image" (onRemove) = removeImage() [maxFileSize]=5242880 chooseLabel="Change image" (onSelect)=hideOldImage() [previewWidth]=250 [auto]=true accept="image/*" [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('image',$event)">
<ng-template pTemplate="content" let-files >
<p-image [src]="imagePath+'/'+resource.idResource+'/image'" *ngIf="showOldImg" [preview]="true" width="250"></p-image>
</ng-template>
</p-fileUpload>
</div>
</div>
<div class="field grid" *ngIf="!edit || !imageExist">
<label class="col-12 mb-2 md:col-2 md:mb-0">Upload image</label> <label class="col-12 mb-2 md:col-2 md:mb-0">Upload image</label>
<div class="col-12 md:col-10"> <div class="col-12 md:col-10">
<p-fileUpload name="image" [maxFileSize]=5242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('image',$event)"></p-fileUpload> <p-fileUpload name="image" [previewWidth]=250 [auto]=true accept="image/*" [maxFileSize]=5242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('image',$event)"></p-fileUpload>
</div> </div>
</div> </div>
<div class="field grid"> <div class="field grid">
...@@ -164,10 +190,15 @@ ...@@ -164,10 +190,15 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-12 pt-3 justify-content-center flex" > <div class="col-12 pt-3 justify-content-center flex" *ngIf="!edit">
<p-button label="Back" icon="pi pi-step-backward" class="pr-5"routerLink="/home" type="button" ></p-button> <p-button label="Back" icon="pi pi-step-backward" class="pr-5"routerLink="/home" type="button" ></p-button>
<p-button label="Save resource" icon="pi pi-save" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid"></p-button> <p-button label="Save resource" icon="pi pi-save" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid"></p-button>
</div> </div>
<div class="col-12 pt-3 justify-content-center flex" *ngIf="edit" >
<p-button label="Back" icon="pi pi-step-backward" class="pr-5"routerLink="/resource/{{resource.idResource}}" type="button" ></p-button>
<p-button label="Save resource" icon="pi pi-save" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid"></p-button>
</div>
</form> </form>
</div> </div>
<p-toast></p-toast> <p-toast></p-toast>
......
...@@ -2,8 +2,9 @@ import { Component, OnInit } from '@angular/core'; ...@@ -2,8 +2,9 @@ import { Component, OnInit } from '@angular/core';
import {ResourceType, Language, Region, Sector, Project, Resource, Pest, Crop} from "../../model/resource"; import {ResourceType, Language, Region, Sector, Project, Resource, Pest, Crop} from "../../model/resource";
import {ResourceService} from "../../service/resource.service"; import {ResourceService} from "../../service/resource.service";
import {MessageService} from 'primeng/api'; import {MessageService} from 'primeng/api';
import {Router} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {FormControl} from "@angular/forms"; import {FormControl} from "@angular/forms";
import {environment} from "../../../environments/environment";
@Component({ @Component({
...@@ -27,8 +28,16 @@ export class AddResourceComponent implements OnInit { ...@@ -27,8 +28,16 @@ export class AddResourceComponent implements OnInit {
newPest:Pest = {}; newPest:Pest = {};
newCrop: Crop = {}; newCrop: Crop = {};
resourceControl = new FormControl(''); resourceControl = new FormControl('');
resourceId?:string;
edit:boolean = false;
imageExist:boolean = false;
imagePath = environment.baseUrl+"/resource/image/raw";
showOldImg = true;
logo: any;
showOldLogo = true;
logoExist:boolean = false;
constructor(private resourceService:ResourceService,private messageService: MessageService, private router: Router) { } constructor(private resourceService:ResourceService, private route: ActivatedRoute, private messageService: MessageService, private router: Router) { }
ngOnInit(): void { ngOnInit(): void {
this.resourceService.getAllSectors().subscribe((sectors: Sector[]) => { this.resourceService.getAllSectors().subscribe((sectors: Sector[]) => {
...@@ -46,14 +55,39 @@ export class AddResourceComponent implements OnInit { ...@@ -46,14 +55,39 @@ export class AddResourceComponent implements OnInit {
this.resourceService.getAllCrops().subscribe((crops: Crop[]) => { this.resourceService.getAllCrops().subscribe((crops: Crop[]) => {
this.crops = crops;}); this.crops = crops;});
// @ts-ignore
this.resourceId = this.route.snapshot.paramMap.get('id');
if(this.resourceId != undefined){
// @ts-ignore
this.resourceService.getResource(this.resourceId).subscribe(data =>{
this.resource = data;
this.edit = true;
});
this.resourceService.hasImage(this.resourceId,"image").subscribe( data =>{
this.imageExist = data
});
this.resourceService.hasImage(this.resourceId,"logo").subscribe( data =>{
this.logoExist = data
});
}
} }
saveResource(){ saveResource(){
this.resourceService.saveResource(this.resource).subscribe((data: Resource) => { this.resourceService.saveResource(this.resource,this.edit).subscribe((data: Resource) => {
this.resource = data; this.resource = data;
this.resourceService.addFiles(this.image, this.resourceContent, this.resource.idResource).subscribe(data => { console.log(this.image)
console.log(this.logo)
this.resourceService.addFiles(this.image, this.logo, this.resourceContent, this.resource.idResource).subscribe(data => {
if(!this.edit){
this.messageService.add({severity: 'success', detail: 'Resource is saved, but need to be approved by administrator!'}); this.messageService.add({severity: 'success', detail: 'Resource is saved, but need to be approved by administrator!'});
this.router.navigate(['/resource/add']); this.router.navigate(['/home']);
}else{
this.messageService.add({severity: 'success', detail: 'Resource is updated!'});
this.router.navigate(['/resource/'+this.resourceId]);
}
}, error => { }, error => {
this.messageService.add({severity: 'error', detail: 'Some error occurred!'}) this.messageService.add({severity: 'error', detail: 'Some error occurred!'})
...@@ -67,7 +101,11 @@ export class AddResourceComponent implements OnInit { ...@@ -67,7 +101,11 @@ export class AddResourceComponent implements OnInit {
public fileUploader(type:string,event:any){ public fileUploader(type:string,event:any){
if(type === 'image'){ if(type === 'image'){
this.image = event.files[0] this.image = event.files[0]
}else{ }
else if(type === 'logo'){
this.logo = event.files[0]
}
else{
this.resourceContent = event.files; this.resourceContent = event.files;
} }
} }
...@@ -104,4 +142,18 @@ export class AddResourceComponent implements OnInit { ...@@ -104,4 +142,18 @@ export class AddResourceComponent implements OnInit {
this.newCrop={}; this.newCrop={};
this.displayCropModal=false; this.displayCropModal=false;
} }
hideOldImage(){
this.showOldImg = false;
}
removeImage(){
this.image=undefined;
this.showOldImg = true;
}
hideOldLogo(){
this.showOldLogo = false;
}
removeLogo(){
this.logo=undefined;
this.showOldLogo = true;
}
} }
<div class="p-fluid grid flex justify-content-center col-12">
<div class="pt-8 w-3" *ngIf="show">
<form [formGroup]="changeForm" #formDir="ngForm">
<div [hidden]="formDir.submitted">
<div class="field">
<span class="p-float-label">
<input type="password" id="password" pInputText formControlName="password">
<label for="password">Enter new password...</label>
</span>
</div>
<div class="field">
<span class="p-float-label">
<input type="password" id="confirmedPassword" pInputText formControlName="confirmedPassword">
<label for="confirmedPassword">Retype password again...</label>
</span>
</div>
<div *ngIf="changeForm.errors?.['notSame'] && (changeForm.touched || changeForm.dirty)" class="text-xs p-error ">
Passwords does not match!
</div>
</div>
<div class="field flex justify-content-center pt-4">
<p-button class="pr-4" type="submit" [disabled]="changeForm.invalid" (click)="changePassword()">Change password</p-button>
</div>
</form>
</div>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChangePasswordComponent } from './change-password.component';
describe('ChangePasswordComponent', () => {
let component: ChangePasswordComponent;
let fixture: ComponentFixture<ChangePasswordComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ChangePasswordComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ChangePasswordComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute, Router} from "@angular/router";
import {LoginService} from "../../service/login.service";
import {MessageService} from "primeng/api";
import {FormControl, FormGroup} from "@angular/forms";
import {checkValidator} from "../../validator/check-password.directive";
@Component({
selector: 'app-change-password',
templateUrl: './change-password.component.html',
styleUrls: ['./change-password.component.css']
})
export class ChangePasswordComponent implements OnInit {
show:boolean=false;
username?:string;
changeForm!: FormGroup;
constructor(private route: ActivatedRoute,private loginService: LoginService,private messageService: MessageService,private router:Router) {
}
ngOnInit(): void {
this.changeForm = new FormGroup({
password: new FormControl(),
confirmedPassword: new FormControl()
},{ validators: checkValidator })
var token = this.route.snapshot.paramMap.get('token');
if(token != undefined){
this.loginService.checkToken(token).subscribe(data =>{
this.show = true;
this.username = data.username;
},
error => {
this.show = false;
this.messageService.add({severity: 'error', detail: 'This change password request has expired! Try again!'});
this.router.navigate(['/login']);
})
}
}
changePassword(){
// @ts-ignore
this.loginService.changePassword(this.username,this.password.value).subscribe(data =>{
this.router.navigate(['/login']);
},error => {
this.messageService.add({severity: 'error', detail: 'Something went wrong...'});
}
)
}
get password() { return this.changeForm.get('password')!; }
get confirmedPassword() { return this.changeForm.get('confirmedPassword')!; }
}
.footer{
background-image: url('/toolbox/assets/footer.jpg');
height: 415px;
background-position: center;
padding: 0;
}
.footer-ribbon{
background-color: #00662e;
color:white;
}
.footer-white{
background-color: white;
align-self: center;
width: 100%;
}
<footer class="footer flex align-items-end col-12">
<div class="footer-white flex flex-row">
<div>
<img src="">
</div>
<div>
<img src="">
</div>
<div>
<img src="">
</div>
</div>
<div class="footer-ribbon flex col-12 align-items-center">
<div class="pl-8 pt-2">
<img src="assets/EUFlag.png"/>
</div>
<div>
<p class="pl-5 pt-2 align-self-center">
This project has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement No. 101000339.
</p>
</div>
</div>
</footer>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
describe('FooterComponent', () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ FooterComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
<p-menubar [model]="items"> <p-menubar [model]="items">
<ng-template pTemplate="start"> <ng-template pTemplate="start">
<img src="assets/logo-white.png" height="50" class="p-mr-2" routerLink="/home" alt="brand logo"> <img src="assets/logo.jpg" height="97" class="pl-6 mr-8" routerLink="/home" alt="brand logo">
</ng-template>
<ng-template pTemplate="end">
<div *ngIf="!logged">
<p-button label="Login" icon="pi pi-login" iconPos="left" class="p-menuitem-text" routerLink="/login"></p-button>
</div>
<div *ngIf="logged">
<p-button label="Logout" icon="pi pi-login" iconPos="left" class="p-menuitem-text" routerLink="" (click)="logout()"></p-button>
</div>
</ng-template> </ng-template>
</p-menubar> </p-menubar>
<p-toast></p-toast> <p-toast></p-toast>
...@@ -28,7 +28,7 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{ ...@@ -28,7 +28,7 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{
{ {
label: 'Home', label: 'Home',
routerLink:'/home', routerLink:'/home',
styleClass:"ml-5 pr-2 ", styleClass:"pr-2 ",
}, },
{ {
label: 'Add resource', label: 'Add resource',
...@@ -41,6 +41,24 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{ ...@@ -41,6 +41,24 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{
routerLink:'/resource/approve', routerLink:'/resource/approve',
styleClass:"pr-2", styleClass:"pr-2",
visible:this.isUserAdmin() visible:this.isUserAdmin()
},
{
label: 'IPMWORKS',
url:'http://ipmworks.net',
styleClass:"pr-2",
target:"_blank"
},
{
label: 'Logout',
command:(event) => {this.logout()},
styleClass:"pr-2",
visible:this.logged
},
{
label: 'Login',
routerLink:'/login',
styleClass:"pr-2",
visible:!this.logged
} }
] ]
} }
...@@ -48,6 +66,7 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{ ...@@ -48,6 +66,7 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{
this.router.events.pipe(filter((event) => event instanceof NavigationEnd), this.router.events.pipe(filter((event) => event instanceof NavigationEnd),
takeUntil(this.destroyed) takeUntil(this.destroyed)
).subscribe(() => { ).subscribe(() => {
this.router.routeReuseStrategy.shouldReuseRoute = function() { return false; };
this.initialise(); this.initialise();
}); });
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12); box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12);
border-radius: 4px; border-radius: 4px;
margin-bottom: 2rem; margin-bottom: 2rem;
justify-content: space-between;
} }
.button-center{ .button-center{
display: flex; display: flex;
......
...@@ -3,18 +3,17 @@ ...@@ -3,18 +3,17 @@
<div class="col-3"> <div class="col-3">
<form #searchForm="ngForm" (ngSubmit)="searchResource()"> <form #searchForm="ngForm" (ngSubmit)="searchResource()">
<p class="text-xl">Sectors</p> <p class="text-xl">Sectors</p>
<p-multiSelect [selectionLimit]="1" defaultLabel="Select sector" [options]="sectors" name="sector" [(ngModel)]="searchModel.sector" optionLabel="name"></p-multiSelect> <p-multiSelect defaultLabel="Select sector" [options]="sectors" name="sector" [(ngModel)]="searchModel.sector" optionLabel="name"></p-multiSelect>
<p class="text-xl">Country of origin</p> <p class="text-xl">Country of origin</p>
<p-multiSelect [selectionLimit]="1" defaultLabel="Select region" [options]="regions" name="region" [(ngModel)]="searchModel.region" optionLabel="name"></p-multiSelect> <p-multiSelect defaultLabel="Select region" [options]="regions" name="region" [(ngModel)]="searchModel.region" optionLabel="name"></p-multiSelect>
<!-- <div class="field"> <!-- <div class="field">
<p class="text-xl">Pest type</p> <p class="text-xl">Pest type</p>
<p-dropdown autoWidth="false" [style]="{'width':'100%'}" placeholder="Select pest type" [options]="pestType" name="pestType"[(ngModel)]="searchModel.pestType" optionLabel="name" ></p-dropdown> <p-dropdown autoWidth="false" [style]="{'width':'100%'}" placeholder="Select pest type" [options]="pestType" name="pestType"[(ngModel)]="searchModel.pestType" optionLabel="name" ></p-dropdown>
</div>--> </div>-->
<p class="text-xl">Project</p> <p class="text-xl">Project</p>
<input id="project" type="text" pInputText name="project" [(ngModel)]="searchModel.project" placeholder="Add project"> <p-dropdown autoWidth="false" [style]="{'width':'100%'}" placeholder="Select projecte" [(ngModel)]="searchModel.project" [options]="projects" name="project" optionLabel="name" ></p-dropdown>
<p class="text-xl">Resource types</p> <p class="text-xl">Resource types</p>
<p-multiSelect placeholder="Select resource type" [selectionLimit]="1" name="resourceType" [(ngModel)]="searchModel.resourceType" [options]="contentTypes" optionLabel="name"> <p-multiSelect placeholder="Select resource type" name="resourceType" [(ngModel)]="searchModel.resourceType" [options]="contentTypes" optionLabel="name">
</p-multiSelect> </p-multiSelect>
...@@ -27,7 +26,7 @@ ...@@ -27,7 +26,7 @@
</div> </div>
<div *ngIf="more"> <div *ngIf="more">
<p class="text-xl">Specific pest</p> <p class="text-xl">Specific pest</p>
<p-multiSelect defaultLabel="Select pests" [selectionLimit]="1" [options]="pests" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.pest" name="pest"> <p-multiSelect defaultLabel="Select pests" [options]="pests" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.pest" name="pest">
<ng-template let-pest pTemplate="item"> <ng-template let-pest pTemplate="item">
<div>{{pest.commonName}} <i *ngIf="pest.latinName !=undefined"> <div>{{pest.commonName}} <i *ngIf="pest.latinName !=undefined">
({{pest.latinName}}, {{pest.eppo}})</i></div> ({{pest.latinName}}, {{pest.eppo}})</i></div>
...@@ -36,7 +35,7 @@ ...@@ -36,7 +35,7 @@
<p class="text-xl">Specific crop</p> <p class="text-xl">Specific crop</p>
<p-multiSelect defaultLabel="Select crops" [selectionLimit]="1" [options]="crops" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.crop" name="crop"> <p-multiSelect defaultLabel="Select crops" [options]="crops" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.crop" name="crop">
<ng-template let-crop pTemplate="item"> <ng-template let-crop pTemplate="item">
<div>{{crop.commonName}} <i *ngIf="crop.latinName !=undefined"> <div>{{crop.commonName}} <i *ngIf="crop.latinName !=undefined">
({{crop.latinName}}, {{crop.eppo}})</i></div> ({{crop.latinName}}, {{crop.eppo}})</i></div>
...@@ -44,20 +43,25 @@ ...@@ -44,20 +43,25 @@
</p-multiSelect> </p-multiSelect>
<p class="text-xl">Languages</p> <p class="text-xl">Languages</p>
<p-multiSelect defaultLabel="Select language" [selectionLimit]="1" [options]="languages" name="language" [(ngModel)]="searchModel.language" optionLabel="name"></p-multiSelect> <p-multiSelect defaultLabel="Select language" [options]="languages" name="language" [(ngModel)]="searchModel.language" optionLabel="name"></p-multiSelect>
<!--<h3>Arbitrary text search</h3> <!--<h3>Arbitrary text search</h3>
<input type="text" pInputText [(ngModel)]="searchTerm"/>--> <input type="text" pInputText [(ngModel)]="searchTerm"/>-->
</div> </div>
<div class="pt-3 button-center"> <div class="flex justify-content-center">
<p-button type="submit" label="Search" icon="pi pi-search" [loading]="false"></p-button> <div class="pt-3 pr-3">
<p-button type="submit" label="Search" [disabled] = "isEmptySearch()" icon="pi pi-search" [loading]="false"></p-button>
</div>
<div class="pt-3 pl-3">
<p-button type="submit" label="Reset" icon="pi pi-refresh" (click)="resetSearch()" [loading]="false"></p-button>
</div>
</div> </div>
</form> </form>
</div> </div>
<div class="col-9"> <div class="col-9">
<p-card> <p-card>
<p-dataView [value]="resources" [lazy]="true" (onLazyLoad)="onPageChange($event)" (onPage)="onPageChange($event)" [totalRecords]="totalElements" [paginator]="true" [rowsPerPageOptions]=[10,50,100] [rows]="10" layout="grid"> <p-dataView [value]="resources" [lazy]="true" (onLazyLoad)="onPageChange($event)" (onPage)="onPageChange($event)" [totalRecords]="totalElements" [paginator]="true" [rowsPerPageOptions]=[12,24,48,96] [rows]="12" layout="grid">
<ng-template let-resource pTemplate="gridItem"> <ng-template let-resource pTemplate="gridItem">
<div class="card col-12 md:col-4 flex flex-column p-3 mt-3" routerLink="/resource/{{resource.idResource}}"> <div class="card col-12 md:col-4 flex flex-column p-3 mt-3" routerLink="/resource/{{resource.idResource}}">
<div class="pb-1 align-self-end"> <div class="pb-1 align-self-end">
...@@ -65,7 +69,7 @@ ...@@ -65,7 +69,7 @@
</p-tag> </p-tag>
</div> </div>
<div class=""> <div class="">
<img [src]="imagePath+'/'+resource.idResource" class="imageSizeHome"/> <img [defaultImage]="'assets/sectors/multi.jpg'" [useSrcset]="true" [lazyLoad]="imagePath+'/'+resource.idResource" class="imageSizeHome"/>
<p class="text-center">{{resource.resourceName}}</p> <p class="text-center">{{resource.resourceName}}</p>
</div> </div>
<div class="align-self-center"> <div class="align-self-center">
......
...@@ -25,9 +25,7 @@ export class HomeComponent implements OnInit{ ...@@ -25,9 +25,7 @@ export class HomeComponent implements OnInit{
resources: Resource[] = []; resources: Resource[] = [];
pageableResponse?: PageableResource; pageableResponse?: PageableResource;
pageSize = 10; pageSize = 10;
currentPage = 0;
totalElements: number = 0; totalElements: number = 0;
elements?: Resource[] = [];
sectors: Sector[] = []; sectors: Sector[] = [];
regions: Region[] = []; regions: Region[] = [];
projects: Project[] = []; projects: Project[] = [];
...@@ -50,7 +48,8 @@ export class HomeComponent implements OnInit{ ...@@ -50,7 +48,8 @@ export class HomeComponent implements OnInit{
searchTerm: string = ""; searchTerm: string = "";
more= false; more= false;
imagePath = environment.baseUrl+"/resource/image"; imagePath = environment.baseUrl+"/resource/image";
searchModel:SearchModel={}; imagePathRaw = environment.baseUrl+"/resource/image/raw";
searchModel:SearchModel = {};
constructor(private resourceService:ResourceService, private router:Router) { constructor(private resourceService:ResourceService, private router:Router) {
this.pageableResponse = {totalElements:0} this.pageableResponse = {totalElements:0}
...@@ -85,8 +84,11 @@ export class HomeComponent implements OnInit{ ...@@ -85,8 +84,11 @@ export class HomeComponent implements OnInit{
this.more = !this.more; this.more = !this.more;
} }
public searchResource(){ public searchResource(){
// @ts-ignore
this.resourceService.searchResource(this.searchModel).subscribe((resources: Resource[]) => { this.resourceService.searchResource(this.searchModel).subscribe((resources: Resource[]) => {
this.resources = resources;}); this.resources = resources;
this.totalElements = resources.length
});
} }
onPageChange(event:any) { onPageChange(event:any) {
...@@ -101,4 +103,17 @@ export class HomeComponent implements OnInit{ ...@@ -101,4 +103,17 @@ export class HomeComponent implements OnInit{
// @ts-ignore // @ts-ignore
this.totalElements = this.pageableResponse.totalElements; this.totalElements = this.pageableResponse.totalElements;
} }
public resetSearch(){
this.resourceService.getAllResources().subscribe((resources: PageableResource) => {
// @ts-ignore
this.resources = resources.content;
// @ts-ignore
this.totalElements = resources.totalElements;
this.searchModel = {};
});
}
isEmptySearch(){
return JSON.stringify(this.searchModel) === '{}';
}
} }
...@@ -14,8 +14,17 @@ ...@@ -14,8 +14,17 @@
</span> </span>
</div> </div>
<div class="field flex justify-content-center pt-4"> <div class="field flex justify-content-center pt-4">
<p-button class="" type="submit" (click)="signIn()">Login</p-button> <p-button class="pr-4" type="submit" (click)="signIn()">Login</p-button>
<p-button label="Forgot password?" (click)="displayDialog()" styleClass="p-button-link"></p-button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
<p-dialog [(visible)]="display" [breakpoints]="{'960px': '75vw', '640px': '100vw'}" [style]="{width: '50vw'} ">
<p>If you want to change your password, please enter your e-mail used to login. If we find email in our system, we will send you instructions to follow.</p>
<input type="text" pInputText [(ngModel)]="email">
<div class="pt-4" >
<button type="button" pButton autofocus (click)="sendPasswordChange()" [disabled]="email.length == 0" > Send email</button>
</div>
</p-dialog>
...@@ -4,6 +4,7 @@ import {Actions, ofActionCompleted, Store} from '@ngxs/store'; ...@@ -4,6 +4,7 @@ import {Actions, ofActionCompleted, Store} from '@ngxs/store';
import {LoginAction, LogoutAction, UserState} from '../../states/user.state'; import {LoginAction, LogoutAction, UserState} from '../../states/user.state';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {MessageService} from "primeng/api"; import {MessageService} from "primeng/api";
import {LoginService} from "../../service/login.service";
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
...@@ -15,9 +16,10 @@ export class LoginComponent implements OnInit { ...@@ -15,9 +16,10 @@ export class LoginComponent implements OnInit {
username: new FormControl(), username: new FormControl(),
password: new FormControl(), password: new FormControl(),
}); });
display:boolean = false;
email:string = "";
// tslint:disable-next-line:max-line-length // tslint:disable-next-line:max-line-length
constructor(private action: Actions, private router: Router, private messageService: MessageService, private store: Store) { } constructor(private action: Actions, private router: Router, private messageService: MessageService, private store: Store, private loginService:LoginService) { }
ngOnInit() { ngOnInit() {
this.action.pipe(ofActionCompleted(LoginAction)).subscribe(res => { this.action.pipe(ofActionCompleted(LoginAction)).subscribe(res => {
if (res.result.error) { if (res.result.error) {
...@@ -38,4 +40,13 @@ export class LoginComponent implements OnInit { ...@@ -38,4 +40,13 @@ export class LoginComponent implements OnInit {
const password = this.loginForm.value.password.trim(); const password = this.loginForm.value.password.trim();
this.store.dispatch(new LoginAction(username, password)); this.store.dispatch(new LoginAction(username, password));
} }
displayDialog(){
this.display = true;
}
sendPasswordChange(){
// @ts-ignore
this.loginService.startChangingPassword(this.email).subscribe(d =>{
})
this.display = false;
}
} }
...@@ -21,3 +21,9 @@ ...@@ -21,3 +21,9 @@
.overflow-text{ .overflow-text{
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.link-wrap {
white-space: pre-wrap; /* CSS3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<div class="flex col-12 justify-content-center"> <div class="flex col-12 justify-content-center">
<p class="text-3xl">{{resource.resourceName}}</p> <p class="text-3xl">{{resource.resourceName}}</p>
</div> </div>
<div class="col-6 flex flex-column justify-content-center"> <div class="col-6 flex flex-column">
<div class="col-12 text-center"> <div class="col-12 text-center">
<img [src]="imagePath+'/'+resource.idResource" class="imageSize" > <img [src]="imagePath+'/'+resourceId" class="imageSize" >
</div> </div>
<div class="col-12"> <div class="col-12">
<p-panel class="col-12 inline"> <p-panel class="col-12 inline">
...@@ -14,23 +14,21 @@ ...@@ -14,23 +14,21 @@
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}">Organization name</div><div class="my-0">{{resource.contactInstitution}}</div></div> <div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}">Organization name</div><div class="my-0">{{resource.contactInstitution}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0"[ngStyle]="{color:'var(--surface-500)'}">Contact email</div><div class="my-0"></div>{{resource.contactEmail}}</div> <div class="flex align-items-center"><div class="col-3 inline my-0"[ngStyle]="{color:'var(--surface-500)'}">Contact email</div><div class="my-0"></div>{{resource.contactEmail}}</div>
<div class="flex align-items-center"><div class="col-3 inline my-0"[ngStyle]="{color:'var(--surface-500)'}">Contact phone</div><div class="my-0">{{resource.contactPhone}}</div></div> <div class="flex align-items-center"><div class="col-3 inline my-0"[ngStyle]="{color:'var(--surface-500)'}">Contact phone</div><div class="my-0">{{resource.contactPhone}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}">Resource main url</div><div class="overflow-text my-0"><a href="{{resource.mainURL}}">{{resource.mainURL}}</a></div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}">Citation (DOI)</div><div class="overflow-text my-0">{{resource.citation}}</div></div> <div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}">Citation (DOI)</div><div class="overflow-text my-0">{{resource.citation}}</div></div>
</p-panel> </p-panel>
</div> </div>
</div> </div>
<div class="col-6 flex flex-column"> <div class="col-6 flex flex-column">
<p-panel header="Short summary" class="col-12 p-d-block"> <p-panel header="Short summary" class="col-12 p-d-block">
<div class="flex "> {{resource.description}}</div> <div class="flex"> {{resource.description}}</div>
<div class="flex mt-5 "> <div class="flex mt-5">
<div class="inline col-3 my-0"[ngStyle]="{color:'var(--surface-500)'}">Sectors</div> <div class="inline col-3 my-0"[ngStyle]="{color:'var(--surface-500)'}">Sectors</div>
<div class="inline my-0" *ngFor="let sector of resource.sectors"> <div class="inline my-0" *ngFor="let sector of resource.sectors">
<img class="sector mx-2" [src]="'assets/sectors/'+sector.sectorIcon" pTooltip="{{sector.name}}"> <img class="sector mx-2" [src]="'assets/sectors/'+sector.sectorIcon" pTooltip="{{sector.name}}">
</div> </div>
</div> </div>
<div class="flex "> <div class="flex flex-wrap">
<div class="inline col-3 my-0" [ngStyle]="{color:'var(--surface-500)'}">Regions</div> <div class="inline col-3 my-0" [ngStyle]="{color:'var(--surface-500)'}">Regions</div>
<div *ngFor="let region of resource.regions" class="inline my-0"> <div *ngFor="let region of resource.regions" class="inline my-0">
<p class=" my-0 py-2 mx-2" >{{region.name}}</p> <p class=" my-0 py-2 mx-2" >{{region.name}}</p>
</div> </div>
...@@ -50,14 +48,14 @@ ...@@ -50,14 +48,14 @@
</div> </div>
</div> </div>
</p-panel> </p-panel>
<p-panel class="col-12" header="Find out more"> <p-panel class="col-12 p-d-block" header="Find out more" *ngIf="(resource.fileNames != undefined) || (resource.links != undefined)">
<div *ngFor="let file of resource.fileNames" > <div *ngFor="let file of resource.fileNames" >
<i class="pi pi-file p-mr-2" style="font-size: 2rem"></i> <i class="pi pi-file p-mr-2" style="font-size: 2rem"></i>
<button pButton type="button" label="{{file}}" class="p-button-link button-link" (click)="downloadFile(file)"></button> <button pButton type="button" label="{{file}}" class="p-button-link button-link" (click)="downloadFile(file)"></button>
</div> </div>
<div class="mt-2" *ngFor="let link of resource.links" > <div class="mt-2" *ngFor="let link of resource.links" >
<i class="pi pi-link p-mr-2" style="font-size: 2rem"></i> <i class="pi pi-link p-mr-2" style="font-size: 2rem"></i>
<a href="{{link}}">{{link}}</a> <a class="link-wrap" href="{{link}}">{{link}}</a>
</div> </div>
</p-panel> </p-panel>
</div> </div>
...@@ -68,8 +66,11 @@ ...@@ -68,8 +66,11 @@
<div class="pr-2" *ngIf="!resource.approved && (loggeduser| async)?.roles?.includes('ADMIN')"> <div class="pr-2" *ngIf="!resource.approved && (loggeduser| async)?.roles?.includes('ADMIN')">
<p-button label="Approve" icon="pi pi-check" (onClick)="approve($event)" [loading]="false"></p-button> <p-button label="Approve" icon="pi pi-check" (onClick)="approve($event)" [loading]="false"></p-button>
</div> </div>
<div class="pr-2" *ngIf="(loggeduser| async)?.roles?.includes('ADMIN')">
<p-button label="Edit" icon="pi pi-pencil" routerLink="/resource/edit/{{resourceId}}" [loading]="false"></p-button>
</div>
<div *ngIf="(loggeduser| async)?.roles?.includes('ADMIN')"> <div *ngIf="(loggeduser| async)?.roles?.includes('ADMIN')">
<p-button label="Edit" icon="pi pi-pencil" (onClick)="showInfo()" routerLink="/resource/edit" [loading]="false"></p-button> <p-button label="Delete" icon="pi pi-trash" (onClick)="delete($event)" [loading]="false"></p-button>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -66,6 +66,22 @@ export class ResourceComponent implements OnInit { ...@@ -66,6 +66,22 @@ export class ResourceComponent implements OnInit {
} }
}); });
} }
delete(event: Event) {
this.confirmationService.confirm({
message: 'Are you sure that you want to delete resource?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
// @ts-ignore
this.resourceService.deleteResource(this.resourceId).subscribe(r =>{
this.messageService.add({severity:'success', detail:'Resource has been deletede.'});
this.router.navigate(['/home'])
},error =>{
this.messageService.add({severity:'error', detail:'Some error occured!'});
}
);
}
});
}
showInfo() { showInfo() {
this.messageService.add({severity:'info', summary: 'Info', detail: 'This feature has not been implemented yet!'}); this.messageService.add({severity:'info', summary: 'Info', detail: 'This feature has not been implemented yet!'});
} }
......
...@@ -6,32 +6,25 @@ export interface Resource { ...@@ -6,32 +6,25 @@ export interface Resource {
links?:string[]; links?:string[];
fileNames?:string[]; fileNames?:string[];
resourceOrigin?: string; resourceOrigin?: string;
countryOrigin?:Country;
resourceType?: ResourceType; resourceType?: ResourceType;
sectors?: Sector[]; sectors?: Sector[];
regions?: Region[]; regions?: Region[];
crops?:Crop[]; crops?:Crop[];
pests?:Pest[]; pests?:Pest[];
keywordsTemp?:string[]; //keywordsTemp?:string[];
keywords?: Keyword[]; //keywords?: Keyword[];
language?: Language; language?: Language;
project?: Project; project?: Project;
projectWeb?: string; projectWeb?: string;
projectGrantNo?:string; projectGrantNo?:string;
contactName?: string;
contactInstitution?: string; contactInstitution?: string;
contactEmail?: string; contactEmail?: string;
contactPhone?: string; contactPhone?: string;
mainURL?:string;
citation?:string; citation?:string;
creationDate?:Date; creationDate?:Date;
approved?:boolean; approved?:boolean;
} }
export class Country{
public idCountry!:string;
public name!: string;
}
export class Crop{ export class Crop{
public idCrop?:string; public idCrop?:string;
public commonName?: string; public commonName?: string;
......
import {Crop, Language, Pest, Region, ResourceType, Sector} from "./resource"; import {Crop, Language, Pest, Project, Region, ResourceType, Sector} from "./resource";
export class SearchModel { export class SearchModel {
sector?:Sector[]; sector?:Sector[];
region?: Region[]; region?: Region[];
pestType?: string ; pestType?: string ;
project?: string ; project?: Project ;
resourceType?: ResourceType[]; resourceType?: ResourceType[];
pest?: Pest[]; pest?: Pest[];
crop?: Crop[]; crop?: Crop[];
......
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {AppConfig} from "../../config/app.config"; import {AppConfig} from "../../config/app.config";
import {User} from "../model/user";
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
...@@ -12,4 +13,14 @@ export class LoginService { ...@@ -12,4 +13,14 @@ export class LoginService {
const data = {username, password}; const data = {username, password};
return this.httpClient.post(`${AppConfig.ApiPaths.login}`, data); return this.httpClient.post(`${AppConfig.ApiPaths.login}`, data);
} }
public startChangingPassword(username: string) {
return this.httpClient.post(`${AppConfig.ApiPaths.startChangingPassword}`, username);
}
public checkToken(token: string) {
return this.httpClient.get<User>(`${AppConfig.ApiPaths.getUserName}`+"/"+token);
}
public changePassword(username: string,password:string) {
const data = {username, password};
return this.httpClient.post(`${AppConfig.ApiPaths.changePassword}`, data);
}
} }
...@@ -37,18 +37,26 @@ export class ResourceService { ...@@ -37,18 +37,26 @@ export class ResourceService {
public getResource(id:string) { public getResource(id:string) {
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.getResource}`+"/"+id); return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.getResource}`+"/"+id);
} }
public hasImage(id:string,type:string) {
return this._httpClient.get<boolean>(`${AppConfig.ApiPaths.hasImage}`+"/"+type+"/"+id);
}
public approveResource(id:string) { public approveResource(id:string) {
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.approveResource}`+"/"+id); return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.approveResource}`+"/"+id);
} }
public deleteResource(id:string) {
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.deleteResource}`+"/"+id);
}
public downloadFile(name: string) { public downloadFile(name: string) {
const httpOptions = { const httpOptions = {
responseType: 'blob' as 'json', responseType: 'blob' as 'json',
}; };
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.getFile}`+"/"+name, httpOptions); return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.getFile}`+"/"+name, httpOptions);
} }
public saveResource(resource: Resource) { public saveResource(resource: Resource,edit:boolean) {
resource.creationDate = new Date(); resource.creationDate = new Date();
if(!edit){
resource.approved = false; resource.approved = false;
}
return this._httpClient.post<Resource>(`${AppConfig.ApiPaths.saveResource}`, resource); return this._httpClient.post<Resource>(`${AppConfig.ApiPaths.saveResource}`, resource);
} }
...@@ -56,12 +64,15 @@ export class ResourceService { ...@@ -56,12 +64,15 @@ export class ResourceService {
return this._httpClient.post<Resource[]>(`${AppConfig.ApiPaths.searchResource}`, search); return this._httpClient.post<Resource[]>(`${AppConfig.ApiPaths.searchResource}`, search);
} }
public addFiles(image:File,resourceContent:File[],idResource:any){ public addFiles(image:File,logo:File,resourceContent:File[],idResource:any){
const formData: FormData = new FormData(); const formData: FormData = new FormData();
if(image != undefined) { if(image != undefined) {
formData.append("image", image); formData.append("image", image);
} }
if(logo != undefined) {
formData.append("logo", logo);
}
resourceContent.forEach(r =>{ resourceContent.forEach(r =>{
formData.append("files",r); formData.append("files",r);
}) })
...@@ -71,7 +82,7 @@ export class ResourceService { ...@@ -71,7 +82,7 @@ export class ResourceService {
return this._httpClient.get<Sector[]>(`${AppConfig.ApiPaths.getAllSectors}`); return this._httpClient.get<Sector[]>(`${AppConfig.ApiPaths.getAllSectors}`);
} }
public getAllRegions() { public getAllRegions() {
return this._httpClient.get<Region[]>(`${AppConfig.ApiPaths.getAllCountries}`); return this._httpClient.get<Region[]>(`${AppConfig.ApiPaths.getAllRegions}`);
} }
public getAllResourceTypes() { public getAllResourceTypes() {
return this._httpClient.get<ResourceType[]>(`${AppConfig.ApiPaths.getAllResourceTypes}`); return this._httpClient.get<ResourceType[]>(`${AppConfig.ApiPaths.getAllResourceTypes}`);
...@@ -90,7 +101,6 @@ export class ResourceService { ...@@ -90,7 +101,6 @@ export class ResourceService {
} }
public getAllKeywords() { public getAllKeywords() {
return this._httpClient.get<Keyword[]>(`${AppConfig.ApiPaths.getAllKeywords}`); return this._httpClient.get<Keyword[]>(`${AppConfig.ApiPaths.getAllKeywords}`);
} }
} }
import { CheckPasswordDirective } from './check-password.directive';
describe('CheckPasswordDirective', () => {
it('should create an instance', () => {
const directive = new CheckPasswordDirective();
expect(directive).toBeTruthy();
});
});
import { Directive } from '@angular/core';
import {AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn} from "@angular/forms";
export const checkValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
var password = control.get('password');
var confirmedPassword = control.get('confirmedPassword');
return password && confirmedPassword && password.value !== confirmedPassword.value ? { notSame: true } : null;
};
@Directive({
selector: '[appCheckPassword]',
providers: [{ provide: NG_VALIDATORS, useExisting: CheckPasswordDirective, multi: true }]
})
export class CheckPasswordDirective implements Validator {
validate(control: AbstractControl): ValidationErrors | null {
return checkValidator(control);
}
}
...@@ -8,7 +8,10 @@ export class AppConfig { ...@@ -8,7 +8,10 @@ export class AppConfig {
getAllResources: `${AppConfig.Origin}/resource/getAllResources`, getAllResources: `${AppConfig.Origin}/resource/getAllResources`,
getResourcesForApproval: `${AppConfig.Origin}/admin/getResourceForApproval`, getResourcesForApproval: `${AppConfig.Origin}/admin/getResourceForApproval`,
getResource: `${AppConfig.Origin}/resource/get`, getResource: `${AppConfig.Origin}/resource/get`,
hasImage: `${AppConfig.Origin}/resource/imageExist`,
approveResource: `${AppConfig.Origin}/admin/approve`, approveResource: `${AppConfig.Origin}/admin/approve`,
deleteResource: `${AppConfig.Origin}/admin/delete`,
getFile: `${AppConfig.Origin}/resource/file`, getFile: `${AppConfig.Origin}/resource/file`,
...@@ -19,19 +22,17 @@ export class AppConfig { ...@@ -19,19 +22,17 @@ export class AppConfig {
getAllLanguages: `${AppConfig.Origin}/codebooks/getAllLanguages`, getAllLanguages: `${AppConfig.Origin}/codebooks/getAllLanguages`,
getAllSectors: `${AppConfig.Origin}/codebooks/getAllSectors`, getAllSectors: `${AppConfig.Origin}/codebooks/getAllSectors`,
getAllCountries: `${AppConfig.Origin}/codebooks/getAllCountries`, getAllRegions: `${AppConfig.Origin}/codebooks/getAllRegions`,
getAllResourceTypes: `${AppConfig.Origin}/codebooks/getAllResourceTypes`, getAllResourceTypes: `${AppConfig.Origin}/codebooks/getAllResourceTypes`,
getAllProjects: `${AppConfig.Origin}/codebooks/getAllProjects`, getAllProjects: `${AppConfig.Origin}/codebooks/getAllProjects`,
getAllPests: `${AppConfig.Origin}/codebooks/getAllPests`, getAllPests: `${AppConfig.Origin}/codebooks/getAllPests`,
getAllCrops: `${AppConfig.Origin}/codebooks/getAllCrops`, getAllCrops: `${AppConfig.Origin}/codebooks/getAllCrops`,
getAllKeywords: `${AppConfig.Origin}/codebooks/getAllKeywords`, getAllKeywords: `${AppConfig.Origin}/codebooks/getAllKeywords`,
login:`${AppConfig.Origin}/authenticate` login:`${AppConfig.Origin}/auth/authenticate`,
startChangingPassword:`${AppConfig.Origin}/auth/startChangingPassword`,
getUserName:`${AppConfig.Origin}/auth/validateToken`,
changePassword:`${AppConfig.Origin}/auth/changePassword`
}; };
......
*{ *{
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
} }
.container-fluid {
min-height: 100vh;
}
.p-menubar{ .p-menubar{
margin:-8px; margin:-8px;
background-color:#00662e !important; background-color:white !important;
min-height:170px;
border-bottom: 10px solid #71B532 !important;
justify-content: space-between !important;
align-items: baseline !important;
}
.p-menuitem-text{
text-transform: uppercase;
}
.p-menubar-root-list{
padding-left:120px !important;
} }
.p-button:not(.p-button-outlined){ .p-button:not(.p-button-outlined){
background-color:#00662e !important; background-color:#00662e !important;
...@@ -53,5 +67,18 @@ ...@@ -53,5 +67,18 @@
} }
} }
.p-menuitem-text{ .p-menuitem-text{
color: white !important; color: #003519 !important;
}
.p-message.p-message-info{
background:#71B532 !important;
color:white !important;
}
.p-message.p-message-info .p-message-icon{
color:white !important;
}
.p-message.p-message-info .p-message-close{
color:white !important;
}
.p-button.p-button-link{
background-color: transparent !important;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment