From 68d2615f0fcc4ecedba222107869e77429762d9e Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Thu, 12 Sep 2024 15:13:56 +0200 Subject: [PATCH] export DB, Event creation, broker with city/state --- bizmatch-server/.gitignore | 1 + bizmatch-server/src/app.module.ts | 2 + bizmatch-server/src/drizzle/export.ts | 35 ++++++++++ bizmatch-server/src/drizzle/schema.ts | 6 +- bizmatch-server/src/event/event.controller.ts | 20 ++++++ bizmatch-server/src/event/event.module.ts | 11 ++++ bizmatch-server/src/event/event.service.ts | 17 +++++ bizmatch-server/src/geo/geo.controller.ts | 6 +- bizmatch-server/src/geo/geo.service.ts | 12 +++- bizmatch-server/src/mail/mail.service.ts | 6 +- bizmatch-server/src/models/db.model.ts | 17 +++++ bizmatch/proxy.conf.json | 20 +++++- bizmatch/src/app/app.component.ts | 9 +++ .../details-business-listing.component.ts | 7 +- ...s-commercial-property-listing.component.ts | 6 +- .../broker-listings.component.html | 14 ++-- .../app/pages/success/success.component.ts | 6 +- bizmatch/src/app/services/audit.service.ts | 66 +++++++++++++++++++ bizmatch/src/app/services/geo.service.ts | 3 + bizmatch/src/app/services/log.service.ts | 17 ----- bizmatch/src/environments/environment.base.ts | 1 + 21 files changed, 242 insertions(+), 40 deletions(-) create mode 100644 bizmatch-server/src/drizzle/export.ts create mode 100644 bizmatch-server/src/event/event.controller.ts create mode 100644 bizmatch-server/src/event/event.module.ts create mode 100644 bizmatch-server/src/event/event.service.ts create mode 100644 bizmatch/src/app/services/audit.service.ts delete mode 100644 bizmatch/src/app/services/log.service.ts diff --git a/bizmatch-server/.gitignore b/bizmatch-server/.gitignore index 8bc5360..68cb476 100644 --- a/bizmatch-server/.gitignore +++ b/bizmatch-server/.gitignore @@ -2,6 +2,7 @@ /dist /node_modules /build +/data # Logs logs diff --git a/bizmatch-server/src/app.module.ts b/bizmatch-server/src/app.module.ts index 9a5292c..ecadae0 100644 --- a/bizmatch-server/src/app.module.ts +++ b/bizmatch-server/src/app.module.ts @@ -22,6 +22,7 @@ import { PaymentModule } from './payment/payment.module'; import { RequestDurationMiddleware } from './request-duration/request-duration.middleware'; import { SelectOptionsModule } from './select-options/select-options.module'; import { UserModule } from './user/user.module'; +import { EventModule } from './event/event.module'; // const __filename = fileURLToPath(import.meta.url); // const __dirname = path.dirname(__filename); @@ -85,6 +86,7 @@ loadEnvFiles(); AiModule, LogModule, PaymentModule, + EventModule, ], controllers: [AppController, LogController], providers: [AppService, FileService, JwtStrategy], diff --git a/bizmatch-server/src/drizzle/export.ts b/bizmatch-server/src/drizzle/export.ts new file mode 100644 index 0000000..4a3a589 --- /dev/null +++ b/bizmatch-server/src/drizzle/export.ts @@ -0,0 +1,35 @@ +import 'dotenv/config'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import { promises as fs } from 'fs'; +import { Pool } from 'pg'; +import * as schema from './schema'; + +// Drizzle-Tabellen-Definitionen (hier hast du bereits die Tabellen definiert, wir nehmen an, sie werden hier importiert) +import { businesses, commercials, users } from './schema'; // Anpassen je nach tatsächlicher Struktur + +const connectionString = process.env.DATABASE_URL; +console.log(connectionString); +const client = new Pool({ connectionString }); +const db = drizzle(client, { schema, logger: true }); +(async () => { + try { + // Abfrage der Daten für jede Tabelle + const usersData = await db.select().from(users).execute(); + const businessesData = await db.select().from(businesses).execute(); + const commercialsData = await db.select().from(commercials).execute(); + + // Speichern der Daten in JSON-Dateien + await fs.writeFile('./data/users_export.json', JSON.stringify(usersData, null, 2)); + console.log('Users exportiert in users.json'); + + await fs.writeFile('./data/businesses_export.json', JSON.stringify(businessesData, null, 2)); + console.log('Businesses exportiert in businesses.json'); + + await fs.writeFile('./data/commercials_export.json', JSON.stringify(commercialsData, null, 2)); + console.log('Commercials exportiert in commercials.json'); + } catch (error) { + console.error('Fehler beim Exportieren der Tabellen:', error); + } finally { + await client.end(); + } +})(); diff --git a/bizmatch-server/src/drizzle/schema.ts b/bizmatch-server/src/drizzle/schema.ts index d5b63ff..1322ff3 100644 --- a/bizmatch-server/src/drizzle/schema.ts +++ b/bizmatch-server/src/drizzle/schema.ts @@ -134,10 +134,10 @@ export const commercials = pgTable( // }); export const listingEvents = pgTable('listing_events', { id: uuid('id').primaryKey().defaultRandom().notNull(), - listingId: uuid('listing_id').notNull(), // Assuming listings are referenced by UUID, adjust as necessary + listingId: uuid('listing_id'), // Assuming listings are referenced by UUID, adjust as necessary userId: uuid('user_id'), // Nullable, if user is logged in, otherwise null - eventType: varchar('event_type', { length: 50 }).notNull(), // 'view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact' - eventTimestamp: timestamp('event_timestamp').defaultNow().notNull(), + eventType: varchar('event_type', { length: 50 }), // 'view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact' + eventTimestamp: timestamp('event_timestamp').defaultNow(), userIp: varchar('user_ip', { length: 45 }), // Optional if you choose to track IP in frontend or backend userAgent: varchar('user_agent', { length: 255 }), // Store User-Agent as string locationCountry: varchar('location_country', { length: 100 }), // Country from IP diff --git a/bizmatch-server/src/event/event.controller.ts b/bizmatch-server/src/event/event.controller.ts new file mode 100644 index 0000000..5e062e6 --- /dev/null +++ b/bizmatch-server/src/event/event.controller.ts @@ -0,0 +1,20 @@ +import { Body, Controller, Headers, Ip, Post } from '@nestjs/common'; +import { ListingEvent } from 'src/models/db.model'; +import { EventService } from './event.service'; + +@Controller('event') +export class EventController { + constructor(private eventService: EventService) {} + @Post() + async createEvent( + @Body() event: ListingEvent, // Struktur des Body-Objekts entsprechend anpassen + @Ip() userIp: string, // IP Adresse des Clients + @Headers('user-agent') userAgent: string, // User-Agent des Clients + ) { + //const { listingId, userId, eventType, locationCountry, locationCity, locationLat, locationLng, referrer, additionalData } = body; + event.userIp = userIp; + event.userAgent = userAgent; + this.eventService.createEvent(event); + return { message: 'Event gespeichert' }; + } +} diff --git a/bizmatch-server/src/event/event.module.ts b/bizmatch-server/src/event/event.module.ts new file mode 100644 index 0000000..c4ca997 --- /dev/null +++ b/bizmatch-server/src/event/event.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { DrizzleModule } from 'src/drizzle/drizzle.module'; +import { EventController } from './event.controller'; +import { EventService } from './event.service'; + +@Module({ + imports: [DrizzleModule], + controllers: [EventController], + providers: [EventService], +}) +export class EventModule {} diff --git a/bizmatch-server/src/event/event.service.ts b/bizmatch-server/src/event/event.service.ts new file mode 100644 index 0000000..331d98e --- /dev/null +++ b/bizmatch-server/src/event/event.service.ts @@ -0,0 +1,17 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { NodePgDatabase } from 'drizzle-orm/node-postgres'; +import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; +import { ListingEvent } from 'src/models/db.model'; +import * as schema from '../drizzle/schema'; +import { listingEvents, PG_CONNECTION } from '../drizzle/schema'; +@Injectable() +export class EventService { + constructor( + @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, + @Inject(PG_CONNECTION) private conn: NodePgDatabase, + ) {} + async createEvent(event: ListingEvent) { + // Speichere das Event in der Datenbank + await this.conn.insert(listingEvents).values(event).execute(); + } +} diff --git a/bizmatch-server/src/geo/geo.controller.ts b/bizmatch-server/src/geo/geo.controller.ts index b97bab9..ded4075 100644 --- a/bizmatch-server/src/geo/geo.controller.ts +++ b/bizmatch-server/src/geo/geo.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Param, Post } from '@nestjs/common'; +import { Body, Controller, Get, Ip, Param, Post } from '@nestjs/common'; import { CountyRequest } from 'src/models/server.model'; import { GeoService } from './geo.service'; @@ -24,4 +24,8 @@ export class GeoController { findByPrefixAndStates(@Body() countyRequest: CountyRequest): any { return this.geoService.findCountiesStartingWith(countyRequest.prefix, countyRequest.states); } + @Get('ipinfo/georesult/wysiwyg') + fetchIpAndGeoLocation(@Ip() userIp: string): any { + return this.geoService.fetchIpAndGeoLocation(userIp); + } } diff --git a/bizmatch-server/src/geo/geo.service.ts b/bizmatch-server/src/geo/geo.service.ts index 7140c53..eb5385b 100644 --- a/bizmatch-server/src/geo/geo.service.ts +++ b/bizmatch-server/src/geo/geo.service.ts @@ -62,7 +62,7 @@ export class GeoService { }); return state ? result.filter(e => e.state.toLowerCase() === state.toLowerCase()) : result; } - findCitiesAndStatesStartingWith(prefix: string, state?: string): Array { + findCitiesAndStatesStartingWith(prefix: string): Array { const results: Array = []; const lowercasePrefix = prefix.toLowerCase(); @@ -100,4 +100,14 @@ export class GeoService { getCityWithCoords(state: string, city: string): City { return this.geo.states.find(s => s.state_code === state).cities.find(c => c.name === city); } + async fetchIpAndGeoLocation(ip: string): Promise { + const response = await fetch(`${process.env.IP_INFO_URL}/${ip}/geo?token=${process.env.IP_INFO_TOKEN}`, { + method: 'GET', + }); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + return data; + } } diff --git a/bizmatch-server/src/mail/mail.service.ts b/bizmatch-server/src/mail/mail.service.ts index 7a147af..2903515 100644 --- a/bizmatch-server/src/mail/mail.service.ts +++ b/bizmatch-server/src/mail/mail.service.ts @@ -17,7 +17,7 @@ export class MailService { async sendInquiry(mailInfo: MailInfo): Promise { try { - const validatedSender = SenderSchema.parse(mailInfo.sender); + SenderSchema.parse(mailInfo.sender); } catch (error) { if (error instanceof ZodError) { const formattedErrors = error.errors.map(err => ({ @@ -54,7 +54,7 @@ export class MailService { } async sendRequest(mailInfo: MailInfo): Promise { try { - const validatedSender = SenderSchema.parse(mailInfo.sender); + SenderSchema.parse(mailInfo.sender); } catch (error) { if (error instanceof ZodError) { const formattedErrors = error.errors.map(err => ({ @@ -97,7 +97,7 @@ export class MailService { } async send2Friend(shareByEMail: ShareByEMail): Promise { try { - const validatedSender = ShareByEMailSchema.parse(shareByEMail); + ShareByEMailSchema.parse(shareByEMail); } catch (error) { if (error instanceof ZodError) { const formattedErrors = error.errors.map(err => ({ diff --git a/bizmatch-server/src/models/db.model.ts b/bizmatch-server/src/models/db.model.ts index f6741b7..a4ce090 100644 --- a/bizmatch-server/src/models/db.model.ts +++ b/bizmatch-server/src/models/db.model.ts @@ -316,3 +316,20 @@ export const ShareByEMailSchema = z.object({ type: ListingsCategoryEnum, }); export type ShareByEMail = z.infer; + +export const ListingEventSchema = z.object({ + id: z.string().uuid(), // UUID für das Event + listingId: z.string().uuid(), // UUID für das Listing + userId: z.string().uuid().optional().nullable(), // UUID für den Benutzer, optional, wenn kein Benutzer eingeloggt ist + eventType: z.enum(['view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact']), // Die Event-Typen + eventTimestamp: z.string().datetime().or(z.date()), // Der Zeitstempel des Events, kann ein String im ISO-Format oder ein Date-Objekt sein + userIp: z.string().max(45).optional().nullable(), // IP-Adresse des Benutzers, optional + userAgent: z.string().max(255).optional().nullable(), // User-Agent des Benutzers, optional + locationCountry: z.string().max(100).optional().nullable(), // Land, optional + locationCity: z.string().max(100).optional().nullable(), // Stadt, optional + locationLat: z.string().max(20).optional().nullable(), // Latitude, als String + locationLng: z.string().max(20).optional().nullable(), // Longitude, als String + referrer: z.string().max(255).optional().nullable(), // Referrer URL, optional + additionalData: z.record(z.any()).optional().nullable(), // JSON für zusätzliche Daten, z.B. soziale Medien, optional +}); +export type ListingEvent = z.infer; diff --git a/bizmatch/proxy.conf.json b/bizmatch/proxy.conf.json index ac67e3b..cdc833d 100644 --- a/bizmatch/proxy.conf.json +++ b/bizmatch/proxy.conf.json @@ -1,10 +1,28 @@ { "/api": { "target": "http://localhost:3000", - "secure": false + "secure": false, + "changeOrigin": true, + "logLevel": "debug" }, "/pictures": { "target": "http://localhost:8080", "secure": false + }, + "/ipify": { + "target": "https://api.ipify.org", + "secure": true, + "changeOrigin": true, + "pathRewrite": { + "^/ipify": "" + } + }, + "/ipinfo": { + "target": "https://ipinfo.io", + "secure": true, + "changeOrigin": true, + "pathRewrite": { + "^/ipinfo": "" + } } } \ No newline at end of file diff --git a/bizmatch/src/app/app.component.ts b/bizmatch/src/app/app.component.ts index bf0fb53..2f8a83c 100644 --- a/bizmatch/src/app/app.component.ts +++ b/bizmatch/src/app/app.component.ts @@ -12,6 +12,8 @@ import { FooterComponent } from './components/footer/footer.component'; import { HeaderComponent } from './components/header/header.component'; import { MessageContainerComponent } from './components/message/message-container.component'; import { SearchModalComponent } from './components/search-modal/search-modal.component'; +import { AuditService } from './services/audit.service'; +import { GeoService } from './services/geo.service'; import { LoadingService } from './services/loading.service'; import { UserService } from './services/user.service'; @@ -35,6 +37,8 @@ export class AppComponent { private keycloakService: KeycloakService, private userService: UserService, private confirmationService: ConfirmationService, + private auditService: AuditService, + private geoService: GeoService, ) { this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => { let currentRoute = this.activatedRoute.root; @@ -55,6 +59,11 @@ export class AppComponent { } }, }); + // Ensure the service fetches the IP and Geolocation only once + // this.auditService.fetchIpAndGeoLocation(); + this.geoService.fetchIpAndGeoLocation().subscribe(data => { + console.log(JSON.stringify(data)); + }); } private async handleTokenExpiration(): Promise { try { diff --git a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts index d448d0e..0dcaf14 100644 --- a/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts +++ b/bizmatch/src/app/pages/details/details-business-listing/details-business-listing.component.ts @@ -13,9 +13,9 @@ import { ValidatedInputComponent } from '../../../components/validated-input/val import { ValidatedNgSelectComponent } from '../../../components/validated-ng-select/validated-ng-select.component'; import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component'; import { ValidationMessagesService } from '../../../components/validation-messages.service'; +import { AuditService } from '../../../services/audit.service'; import { HistoryService } from '../../../services/history.service'; import { ListingsService } from '../../../services/listings.service'; -import { LogService } from '../../../services/log.service'; import { MailService } from '../../../services/mail.service'; import { SelectOptionsService } from '../../../services/select-options.service'; import { UserService } from '../../../services/user.service'; @@ -71,7 +71,7 @@ export class DetailsBusinessListingComponent { public keycloakService: KeycloakService, private validationMessagesService: ValidationMessagesService, private messageService: MessageService, - private logService: LogService, + private auditService: AuditService, public emailService: EMailService, ) { this.router.events.subscribe(event => { @@ -89,12 +89,13 @@ export class DetailsBusinessListingComponent { this.user = await this.userService.getByMail(this.keycloakUser.email); this.mailinfo = createMailInfo(this.user); } + this.auditService.createEvent({ listingId: this.listing.id, eventType: 'view', eventTimestamp: new Date(), userAgent: navigator.userAgent, userId: this.user?.email }); try { this.listing = await lastValueFrom(this.listingsService.getListingById(this.id, 'business')); this.listingUser = await this.userService.getByMail(this.listing.email); this.description = this.sanitizer.bypassSecurityTrustHtml(this.listing.description); } catch (error) { - this.logService.log({ severity: 'error', text: error.error.message }); + this.auditService.log({ severity: 'error', text: error.error.message }); this.router.navigate(['notfound']); } } diff --git a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts index 1d684bf..043a16a 100644 --- a/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts +++ b/bizmatch/src/app/pages/details/details-commercial-property-listing/details-commercial-property-listing.component.ts @@ -15,10 +15,10 @@ import { ValidatedInputComponent } from '../../../components/validated-input/val import { ValidatedNgSelectComponent } from '../../../components/validated-ng-select/validated-ng-select.component'; import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component'; import { ValidationMessagesService } from '../../../components/validation-messages.service'; +import { AuditService } from '../../../services/audit.service'; import { HistoryService } from '../../../services/history.service'; import { ImageService } from '../../../services/image.service'; import { ListingsService } from '../../../services/listings.service'; -import { LogService } from '../../../services/log.service'; import { MailService } from '../../../services/mail.service'; import { SelectOptionsService } from '../../../services/select-options.service'; import { UserService } from '../../../services/user.service'; @@ -80,7 +80,7 @@ export class DetailsCommercialPropertyListingComponent { private ngZone: NgZone, private validationMessagesService: ValidationMessagesService, private messageService: MessageService, - private logService: LogService, + private auditService: AuditService, private emailService: EMailService, ) { this.mailinfo = { sender: {}, email: '', url: environment.mailinfoUrl }; @@ -116,7 +116,7 @@ export class DetailsCommercialPropertyListingComponent { this.images.push(new ImageItem({ src: imageURL, thumb: imageURL })); }); } catch (error) { - this.logService.log({ severity: 'error', text: error.error.message }); + this.auditService.log({ severity: 'error', text: error.error.message }); this.router.navigate(['notfound']); } diff --git a/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html b/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html index d1a1881..34ab667 100644 --- a/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html +++ b/bizmatch/src/app/pages/listings/broker-listings/broker-listings.component.html @@ -4,7 +4,6 @@ @for (user of users; track user) {
- @if(user.hasProfile){ } @else { @@ -12,13 +11,17 @@ }

{{ user.description }}

-

{{ user.firstname }} {{ user.lastname }}

- -

{{ user.companyName }}

+

+ {{ user.firstname }} {{ user.lastname }}{{ user.location?.name }} - {{ user.location?.state }} +

+
+ +

{{ user.companyName }}

+
+
- @if(user.hasCompanyLogo){ } @else { @@ -30,6 +33,7 @@
+ } diff --git a/bizmatch/src/app/pages/success/success.component.ts b/bizmatch/src/app/pages/success/success.component.ts index 2646f3c..17e02c8 100644 --- a/bizmatch/src/app/pages/success/success.component.ts +++ b/bizmatch/src/app/pages/success/success.component.ts @@ -3,7 +3,7 @@ import { Component } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; import { KeycloakService } from 'keycloak-angular'; import { User } from '../../../../../bizmatch-server/src/models/db.model'; -import { LogService } from '../../services/log.service'; +import { AuditService } from '../../services/audit.service'; import { UserService } from '../../services/user.service'; import { map2User } from '../../utils/utils'; @@ -18,7 +18,7 @@ export class SuccessComponent { user: User; maxAttemptsReached: boolean = false; // Neue Variable hinzufügen - constructor(private keycloakService: KeycloakService, private userService: UserService, private logService: LogService, private router: Router) {} + constructor(private keycloakService: KeycloakService, private userService: UserService, private auditService: AuditService, private router: Router) {} async ngOnInit() { let email = null; @@ -35,7 +35,7 @@ export class SuccessComponent { async checkSubscriptionPlan(email: string, error?: string) { if (!email) { - this.logService.log({ severity: 'error', text: `Unauthorized Access to Success Page ${error}` }); + this.auditService.log({ severity: 'error', text: `Unauthorized Access to Success Page ${error}` }); this.router.navigate(['home']); return; } diff --git a/bizmatch/src/app/services/audit.service.ts b/bizmatch/src/app/services/audit.service.ts new file mode 100644 index 0000000..f3dc8cc --- /dev/null +++ b/bizmatch/src/app/services/audit.service.ts @@ -0,0 +1,66 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { BehaviorSubject, lastValueFrom, Observable } from 'rxjs'; +import { ListingEvent } from '../../../../bizmatch-server/src/models/db.model'; +import { LogMessage } from '../../../../bizmatch-server/src/models/main.model'; +import { environment } from '../../environments/environment'; + +@Injectable({ + providedIn: 'root', +}) +export class AuditService { + private apiBaseUrl = environment.apiBaseUrl; + private apiKey = environment.ipinfo_token; + // private ipifyUrl = 'https://api.ipify.org?format=json'; + // private ipInfoUrl = 'https://ipinfo.io'; + private ipifyUrl = 'https://api.ipify.org?format=json'; + private ipInfoUrl = 'https://ipinfo.io'; + + // BehaviorSubject to store the geolocation data + private geoLocationSubject = new BehaviorSubject(null); + public geoLocation$: Observable = this.geoLocationSubject.asObservable(); + + constructor(private http: HttpClient) {} + + async log(message: LogMessage): Promise { + lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/log`, message)); + } + async createEvent(event: ListingEvent): Promise { + lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/event`, event)); + } + // Function to get the IP address + private getIpAddress(): Observable<{ ip: string }> { + return this.http.get<{ ip: string }>(`/ipinfo?format=json`); + } + + // Function to get geolocation using IP address + private getGeolocation(ip: string): Observable { + return this.http.get(`/ipinfo/${ip}?token=${this.apiKey}`); + } + + // Fetch IP and Geolocation only once, if not already fetched + fetchIpAndGeoLocation(): void { + if (!this.geoLocationSubject.getValue()) { + this.getIpAddress().subscribe({ + next: response => { + this.getGeolocation(response.ip).subscribe({ + next: geoData => { + this.geoLocationSubject.next(geoData); // Store the geolocation data + }, + error: geoError => { + console.error('Error fetching geolocation:', geoError); + }, + }); + }, + error: ipError => { + console.error('Error fetching IP address:', ipError); + }, + }); + } + } + + // Method to provide the stored geolocation data + getGeoLocationData(): Observable { + return this.geoLocation$; // Returns the observable for other components to subscribe + } +} diff --git a/bizmatch/src/app/services/geo.service.ts b/bizmatch/src/app/services/geo.service.ts index e8c97ac..3cf5d6a 100644 --- a/bizmatch/src/app/services/geo.service.ts +++ b/bizmatch/src/app/services/geo.service.ts @@ -27,4 +27,7 @@ export class GeoService { let headers = new HttpHeaders().set('X-Hide-Loading', 'true').set('Accept-Language', 'en-US'); return this.http.get(`${this.baseUrl}?q=${prefix},US&format=json&addressdetails=1&limit=5`, { headers }) as Observable; } + fetchIpAndGeoLocation(): Observable { + return this.http.get(`${this.apiBaseUrl}/bizmatch/geo/ipinfo/georesult/wysiwyg`); + } } diff --git a/bizmatch/src/app/services/log.service.ts b/bizmatch/src/app/services/log.service.ts deleted file mode 100644 index 287b272..0000000 --- a/bizmatch/src/app/services/log.service.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { lastValueFrom } from 'rxjs'; -import { LogMessage } from '../../../../bizmatch-server/src/models/main.model'; -import { environment } from '../../environments/environment'; - -@Injectable({ - providedIn: 'root', -}) -export class LogService { - private apiBaseUrl = environment.apiBaseUrl; - constructor(private http: HttpClient) {} - - async log(message: LogMessage): Promise { - lastValueFrom(this.http.post(`${this.apiBaseUrl}/bizmatch/log`, message)); - } -} diff --git a/bizmatch/src/environments/environment.base.ts b/bizmatch/src/environments/environment.base.ts index 8b912c9..1408694 100644 --- a/bizmatch/src/environments/environment.base.ts +++ b/bizmatch/src/environments/environment.base.ts @@ -11,4 +11,5 @@ export const environment_base = { clientId: 'bizmatch-dev', redirectUri: 'https://dev.bizmatch.net', }, + ipinfo_token: '7029590fb91214', };