fix further bugs

This commit is contained in:
Andreas Knuth 2024-05-16 15:57:39 -05:00
parent 327aef0f21
commit e0ecea5af2
12 changed files with 135 additions and 101 deletions

View File

@ -1,13 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { fstat, readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import { ImageProperty } from '../models/main.model.js';
import sharp from 'sharp';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import path, { join } from 'path';
import sharp from 'sharp';
import { fileURLToPath } from 'url';
import { Logger } from 'winston'; import { Logger } from 'winston';
import { ImageProperty } from '../models/main.model.js';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@ -27,66 +26,66 @@ export class FileService {
this.subscriptions = JSON.parse(rawData); this.subscriptions = JSON.parse(rawData);
} }
getSubscriptions() { getSubscriptions() {
return this.subscriptions return this.subscriptions;
} }
async storeProfilePicture(file: Express.Multer.File, userId: string) { async storeProfilePicture(file: Express.Multer.File, userId: string) {
let quality = 50; let quality = 50;
const output = await sharp(file.buffer) const output = await sharp(file.buffer)
.resize({ width: 300 }) .resize({ width: 300 })
.avif({ quality }) // Verwende AVIF .avif({ quality }) // Verwende AVIF
//.webp({ quality }) // Verwende Webp //.webp({ quality }) // Verwende Webp
.toBuffer(); .toBuffer();
await sharp(output).toFile(`./pictures/profile/${userId}.avif`); await sharp(output).toFile(`./pictures/profile/${userId}.avif`);
} }
hasProfile(userId: string){ hasProfile(userId: string) {
return fs.existsSync(`./pictures/profile/${userId}.avif`) return fs.existsSync(`./pictures/profile/${userId}.avif`);
} }
async storeCompanyLogo(file: Express.Multer.File, userId: string) { async storeCompanyLogo(file: Express.Multer.File, userId: string) {
let quality = 50; let quality = 50;
const output = await sharp(file.buffer) const output = await sharp(file.buffer)
.resize({ width: 300 }) .resize({ width: 300 })
.avif({ quality }) // Verwende AVIF .avif({ quality }) // Verwende AVIF
//.webp({ quality }) // Verwende Webp //.webp({ quality }) // Verwende Webp
.toBuffer(); .toBuffer();
await sharp(output).toFile(`./pictures/logo/${userId}.avif`); // Ersetze Dateierweiterung await sharp(output).toFile(`./pictures/logo/${userId}.avif`); // Ersetze Dateierweiterung
// await fs.outputFile(`./pictures/logo/${userId}`, file.buffer); // await fs.outputFile(`./pictures/logo/${userId}`, file.buffer);
} }
hasCompanyLogo(userId: string){ hasCompanyLogo(userId: string) {
return fs.existsSync(`./pictures/logo/${userId}.avif`)?true:false return fs.existsSync(`./pictures/logo/${userId}.avif`) ? true : false;
} }
async getPropertyImages(listingId: string): Promise<string[]> { async getPropertyImages(listingId: string): Promise<string[]> {
const result: string[] = [] const result: string[] = [];
const directory = `./pictures/property/${listingId}` const directory = `./pictures/property/${listingId}`;
if (fs.existsSync(directory)) { if (fs.existsSync(directory)) {
const files = await fs.readdir(directory); const files = await fs.readdir(directory);
files.forEach(f => { files.forEach(f => {
result.push(f) result.push(f);
}) });
return result; return result;
} else { } else {
return [] return [];
} }
} }
async hasPropertyImages(listingId: string): Promise<boolean> { async hasPropertyImages(listingId: string): Promise<boolean> {
const result: ImageProperty[] = [] const result: ImageProperty[] = [];
const directory = `./pictures/property/${listingId}` const directory = `./pictures/property/${listingId}`;
if (fs.existsSync(directory)) { if (fs.existsSync(directory)) {
const files = await fs.readdir(directory); const files = await fs.readdir(directory);
return files.length>0 return files.length > 0;
} else { } else {
return false return false;
} }
} }
async storePropertyPicture(file: Express.Multer.File, listingId: string) : Promise<string> { async storePropertyPicture(file: Express.Multer.File, listingId: string): Promise<string> {
const suffix = file.mimetype.includes('png') ? 'png' : 'jpg' const suffix = file.mimetype.includes('png') ? 'png' : 'jpg';
const directory = `./pictures/property/${listingId}` const directory = `./pictures/property/${listingId}`;
fs.ensureDirSync(`${directory}`); fs.ensureDirSync(`${directory}`);
const imageName = await this.getNextImageName(directory); const imageName = await this.getNextImageName(directory);
//await fs.outputFile(`${directory}/${imageName}`, file.buffer); //await fs.outputFile(`${directory}/${imageName}`, file.buffer);
await this.resizeImageToAVIF(file.buffer,150 * 1024,imageName,directory); await this.resizeImageToAVIF(file.buffer, 150 * 1024, imageName, directory);
return `${imageName}.avif` return `${imageName}.avif`;
} }
async getNextImageName(directory) { async getNextImageName(directory) {
try { try {
@ -103,37 +102,51 @@ export class FileService {
return null; return null;
} }
} }
async resizeImageToAVIF(buffer: Buffer, maxSize: number,imageName:string,directory:string) { async resizeImageToAVIF(buffer: Buffer, maxSize: number, imageName: string, directory: string) {
let quality = 50; // AVIF kann mit niedrigeren Qualitätsstufen gute Ergebnisse erzielen let quality = 50; // AVIF kann mit niedrigeren Qualitätsstufen gute Ergebnisse erzielen
let output; let output;
let start = Date.now(); let start = Date.now();
output = await sharp(buffer) output = await sharp(buffer)
.resize({ width: 1500 }) .resize({ width: 1500 })
.avif({ quality }) // Verwende AVIF .avif({ quality }) // Verwende AVIF
//.webp({ quality }) // Verwende Webp //.webp({ quality }) // Verwende Webp
.toBuffer(); .toBuffer();
await sharp(output).toFile(`${directory}/${imageName}.avif`); // Ersetze Dateierweiterung await sharp(output).toFile(`${directory}/${imageName}.avif`); // Ersetze Dateierweiterung
let timeTaken = Date.now() - start; let timeTaken = Date.now() - start;
this.logger.info(`Quality: ${quality} - Time: ${timeTaken} milliseconds`) this.logger.info(`Quality: ${quality} - Time: ${timeTaken} milliseconds`);
} }
getProfileImagesForUsers(userids:string){ getProfileImagesForUsers(userids: string) {
const ids = userids.split(','); const ids = userids.split(',');
let result = {}; let result = {};
for (const id of ids){ for (const id of ids) {
result = {...result,[id]:fs.existsSync(`./pictures/profile/${id}.avif`)} result = { ...result, [id]: fs.existsSync(`./pictures/profile/${id}.avif`) };
} }
return result; return result;
} }
getCompanyLogosForUsers(userids:string){ getCompanyLogosForUsers(userids: string) {
const ids = userids.split(','); const ids = userids.split(',');
let result = {}; let result = {};
for (const id of ids){ for (const id of ids) {
result = {...result,[id]:fs.existsSync(`./pictures/logo/${id}.avif`)} result = { ...result, [id]: fs.existsSync(`./pictures/logo/${id}.avif`) };
} }
return result; return result;
} }
deleteImage(path:string){ deleteImage(path: string) {
fs.unlinkSync(path); fs.unlinkSync(path);
} }
deleteDirectoryIfExists(imagePath) {
const dirPath = `pictures/property/${imagePath}`;
try {
const exists = fs.pathExistsSync();
if (exists) {
fs.removeSync(dirPath);
console.log(`Directory ${dirPath} was deleted.`);
} else {
console.log(`Directory ${dirPath} does not exist.`);
}
} catch (error) {
console.error(`Error while deleting ${dirPath}:`, error);
}
}
} }

View File

@ -40,9 +40,10 @@ export class CommercialPropertyListingsController {
this.logger.info(`Save Listing`); this.logger.info(`Save Listing`);
return await this.listingsService.updateListing(listing.id, listing, commercials); return await this.listingsService.updateListing(listing.id, listing, commercials);
} }
@Delete(':id') @Delete(':id/:imagePath')
deleteById(@Param('id') id: string) { deleteById(@Param('id') id: string, @Param('imagePath') imagePath: string) {
this.listingsService.deleteListing(id, commercials); this.listingsService.deleteListing(id, commercials);
this.fileService.deleteDirectoryIfExists(imagePath);
} }
@Put('imageOrder/:id') @Put('imageOrder/:id')

View File

@ -60,7 +60,7 @@
<div class="text-900 w-full md:w-10">{{ listing.brokerLicencing }}</div> <div class="text-900 w-full md:w-10">{{ listing.brokerLicencing }}</div>
</li> </li>
</ul> </ul>
@if(listing && listingUser && (listingUser.id===listing?.userId || isAdmin())){ @if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
<button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/editBusinessListing', listing.id]"></button> <button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/editBusinessListing', listing.id]"></button>
} }
</div> </div>

View File

@ -43,7 +43,7 @@
</li> </li>
</ul> </ul>
@if(listing && listingUser && (listingUser.id===listing?.userId || isAdmin())){ @if(listing && listingUser && (listingUser?.email===user?.email || isAdmin())){
<button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/editCommercialPropertyListing', listing.id]"></button> <button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/editCommercialPropertyListing', listing.id]"></button>
} }
</div> </div>

View File

@ -138,7 +138,7 @@
</ul> </ul>
</div> </div>
</div> </div>
@if( user?.id===(user$| async)?.id || isAdmin()){ @if( user?.email===(user$| async)?.email || isAdmin()){
<button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/account', user.id]"></button> <button pButton pRipple label="Edit" icon="pi pi-file-edit" class="w-auto" [routerLink]="['/account', user.id]"></button>
} }
</div> </div>

View File

@ -48,7 +48,7 @@ export class DetailsUserComponent {
async ngOnInit() { async ngOnInit() {
this.user = await this.userService.getById(this.id); this.user = await this.userService.getById(this.id);
this.user.email;
const results = await Promise.all([await this.listingsService.getListingByUserId(this.id, 'business'), await this.listingsService.getListingByUserId(this.id, 'commercialProperty')]); const results = await Promise.all([await this.listingsService.getListingByUserId(this.id, 'business'), await this.listingsService.getListingByUserId(this.id, 'commercialProperty')]);
// Zuweisen der Ergebnisse zu den Member-Variablen der Klasse // Zuweisen der Ergebnisse zu den Member-Variablen der Klasse
this.businessListings = results[0]; this.businessListings = results[0];

View File

@ -1,6 +1,6 @@
import { ChangeDetectorRef, Component } from '@angular/core'; import { ChangeDetectorRef, Component } from '@angular/core';
import { ConfirmationService, MessageService } from 'primeng/api'; import { ConfirmationService, MessageService } from 'primeng/api';
import { User } from '../../../../../../bizmatch-server/src/models/db.model'; import { CommercialPropertyListing, User } from '../../../../../../bizmatch-server/src/models/db.model';
import { ListingType } from '../../../../../../bizmatch-server/src/models/main.model'; import { ListingType } from '../../../../../../bizmatch-server/src/models/main.model';
import { ListingsService } from '../../../services/listings.service'; import { ListingsService } from '../../../services/listings.service';
import { SelectOptionsService } from '../../../services/select-options.service'; import { SelectOptionsService } from '../../../services/select-options.service';
@ -36,7 +36,11 @@ export class MyListingComponent {
} }
async deleteListing(listing: ListingType) { async deleteListing(listing: ListingType) {
await this.listingsService.deleteListing(listing.id, listing.listingsCategory); if (listing.listingsCategory === 'business') {
await this.listingsService.deleteBusinessListing(listing.id);
} else {
await this.listingsService.deleteCommercialPropertyListing(listing.id, (<CommercialPropertyListing>listing).imagePath);
}
const result = await Promise.all([await this.listingsService.getListingByUserId(this.user.id, 'business'), await this.listingsService.getListingByUserId(this.user.id, 'commercialProperty')]); const result = await Promise.all([await this.listingsService.getListingByUserId(this.user.id, 'business'), await this.listingsService.getListingByUserId(this.user.id, 'commercialProperty')]);
this.myListings = [...result[0], ...result[1]]; this.myListings = [...result[0], ...result[1]];
} }

View File

@ -22,7 +22,7 @@ export class HistoryService {
} }
get canGoBack(): boolean { get canGoBack(): boolean {
return !!this.previousUrl; return !!this.previousUrl || window.history.length > 2;
} }
goBack(): void { goBack(): void {

View File

@ -31,12 +31,16 @@ export class ListingsService {
} }
} }
async getAllStates(listingsCategory?: 'business' | 'commercialProperty'): Promise<StatesResult[]> { async getAllStates(listingsCategory?: 'business' | 'commercialProperty'): Promise<StatesResult[]> {
const result = lastValueFrom(this.http.get<StatesResult[]>(`${this.apiBaseUrl}/bizmatch/listings/${listingsCategory}/states/all`)); const result = lastValueFrom(this.http.get<StatesResult[]>(`${this.apiBaseUrl}/bizmatch/listings/business/states/all`));
return result; return result;
} }
async deleteListing(id: string, listingsCategory: 'business' | 'professionals_brokers' | 'commercialProperty') { async deleteBusinessListing(id: string) {
await lastValueFrom(this.http.delete<ListingType>(`${this.apiBaseUrl}/bizmatch/listings/${listingsCategory}/${id}`)); await lastValueFrom(this.http.delete<ListingType>(`${this.apiBaseUrl}/bizmatch/listings/business/${id}`));
} }
async deleteCommercialPropertyListing(id: string, imagePath: string) {
await lastValueFrom(this.http.delete<ListingType>(`${this.apiBaseUrl}/bizmatch/listings/commercialProperty/${id}/${imagePath}`));
}
async getPropertyImages(id: string): Promise<string[]> { async getPropertyImages(id: string): Promise<string[]> {
return await lastValueFrom(this.http.get<string[]>(`${this.apiBaseUrl}/bizmatch/image/${id}`)); return await lastValueFrom(this.http.get<string[]>(`${this.apiBaseUrl}/bizmatch/image/${id}`));
} }

View File

@ -1,6 +1,6 @@
// Build information, automatically generated by `the_build_script` :zwinkern: // Build information, automatically generated by `the_build_script` :zwinkern:
const build = { const build = {
timestamp: 'NA', timestamp: "GER: 16.05.2024 22:55 | TX: 05/16/2024 3:55 PM"
}; };
export default build; export default build;

View File

@ -1,29 +1,29 @@
@import "primeng/resources/primeng.css"; @import 'primeng/resources/primeng.css';
@import 'primeicons/primeicons.css'; @import 'primeicons/primeicons.css';
// @import 'primeflex/primeflex.scss'; // @import 'primeflex/primeflex.scss';
@import "primeflex/primeflex.css"; @import 'primeflex/primeflex.css';
@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap'); @import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap');
@import "primeng/resources/themes/lara-light-blue/theme.css"; @import 'primeng/resources/themes/lara-light-blue/theme.css';
@import "@fortawesome/fontawesome-free/css/all.min.css"; @import '@fortawesome/fontawesome-free/css/all.min.css';
:root { :root {
--text-color-secondary:rgba(255, 255, 255); --text-color-secondary: rgba(255, 255, 255);
--wrapper-width:1491px; --wrapper-width: 1491px;
// --secondary-color: #ffffff; /* Setzt die secondary Farbe auf weiß */ // --secondary-color: #ffffff; /* Setzt die secondary Farbe auf weiß */
} }
.p-button.p-button-secondary.p-button-outlined{ .p-button.p-button-secondary.p-button-outlined {
color: #ffffff;; color: #ffffff;
} }
html, html,
body, body,
app-root { app-root {
margin: 0; margin: 0;
height: 100%; height: 100%;
} }
app-root { app-root {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
h1, h1,
@ -32,47 +32,54 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
margin: 0; margin: 0;
} }
body, input, button, select, textarea { body,
// font-family: 'Open Sans', sans-serif; input,
font-family: var(--font-family); button,
-webkit-font-smoothing: antialiased; select,
-moz-osx-font-smoothing: grayscale; textarea {
// font-family: 'Open Sans', sans-serif;
font-family: var(--font-family);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
*:focus, *:focus,
.p-focus { .p-focus {
box-shadow: none !important; box-shadow: none !important;
} }
p-menubarsub ul { p-menubarsub ul {
gap: 4px; gap: 4px;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 3px; width: 3px;
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: transparent; background: transparent;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: rgba(155, 155, 155, 0.5); background-color: rgba(155, 155, 155, 0.5);
border-radius: 20px; border-radius: 20px;
border: transparent; border: transparent;
} }
.wrapper { .wrapper {
width: var(--wrapper-width); width: var(--wrapper-width);
max-width: 100%; max-width: 100%;
height: 100%; height: 100%;
margin: auto; margin: auto;
}
.p-editor-container .ql-toolbar {
background: #f9fafb;
border-top-right-radius: 6px;
border-top-left-radius: 6px;
}
.p-dropdown-panel .p-dropdown-header .p-dropdown-filter {
margin-right: 0 !important;
} }
.p-editor-container .ql-toolbar{
background: #f9fafb;
border-top-right-radius: 6px;
border-top-left-radius: 6px;
}

View File

@ -3,9 +3,11 @@ const fs = require('fs');
const dayjs = require('dayjs'); const dayjs = require('dayjs');
const timezone = require('dayjs/plugin/timezone'); const timezone = require('dayjs/plugin/timezone');
const utc = require('dayjs/plugin/utc'); const utc = require('dayjs/plugin/utc');
var localizedFormat = require('dayjs/plugin/localizedFormat');
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
dayjs.extend(localizedFormat);
const write = (content, path) => { const write = (content, path) => {
const writePath = path || `${process.cwd()}/src/build.ts`; const writePath = path || `${process.cwd()}/src/build.ts`;
@ -23,7 +25,10 @@ const package = require(`${process.cwd()}/package.json`);
console.log('start build.js script ...'); console.log('start build.js script ...');
// Generate `build` object // Generate `build` object
const build = {}; const build = {};
build.timestamp = dayjs(new Date()).utc().format('DD.MM.YYYY HH:mm') + ' UTC'; const acDate = new Date();
const german = dayjs(acDate).tz('Europe/Berlin').format('DD.MM.YYYY HH:mm');
const texan = dayjs(acDate).tz('America/Chicago').format('L LT');
build.timestamp = `GER: ${german} | TX: ${texan}`;
// Write Build information to file // Write Build information to file
write(build); write(build);
console.log('build.js script finished ...'); console.log('build.js script finished ...');