keep plan selection during keycloak hop
This commit is contained in:
parent
c00c2caccc
commit
eaa8a5064f
|
|
@ -1,4 +1,6 @@
|
||||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
import { Body, Controller, Get, Param, Put, UseGuards } from '@nestjs/common';
|
||||||
|
import { JwtAuthGuard } from 'src/jwt-auth/jwt-auth.guard';
|
||||||
|
import { KeycloakUser } from 'src/models/main.model';
|
||||||
import { AdminAuthGuard } from '../jwt-auth/admin-auth.guard';
|
import { AdminAuthGuard } from '../jwt-auth/admin-auth.guard';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
|
|
@ -18,12 +20,16 @@ export class AuthController {
|
||||||
return this.authService.getUsers();
|
return this.authService.getUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @UseGuards(AdminAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
// @Get('user/:userid')
|
@Get('users/:userid')
|
||||||
// getUser(@Param('userid') userId: string): any {
|
getUser(@Param('userid') userId: string): any {
|
||||||
// return this.authService.getUser(userId);
|
return this.authService.getUser(userId);
|
||||||
// }
|
}
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Put('users/:userid')
|
||||||
|
updateKeycloakUser(@Body() keycloakUser: KeycloakUser): any {
|
||||||
|
return this.authService.updateKeycloakUser(keycloakUser);
|
||||||
|
}
|
||||||
// @UseGuards(AdminAuthGuard)
|
// @UseGuards(AdminAuthGuard)
|
||||||
// @Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
|
// @Get('user/:userid/lastlogin') //e0811669-c7eb-4e5e-a699-e8334d5c5b01 -> aknuth
|
||||||
// getLastLogin(@Param('userid') userId: string): any {
|
// getLastLogin(@Param('userid') userId: string): any {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { KeycloakUser } from 'src/models/main.model';
|
import { KeycloakUser } from 'src/models/main.model';
|
||||||
|
import urlcat from 'urlcat';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
public async getAccessToken() {
|
public async getAccessToken() {
|
||||||
|
|
@ -50,21 +50,40 @@ export class AuthService {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data as KeycloakUser[];
|
return data as KeycloakUser[];
|
||||||
}
|
}
|
||||||
// public async getUser(userid: string) {
|
public async getUser(userid: string): Promise<KeycloakUser> {
|
||||||
// const token = await this.getAccessToken();
|
const token = await this.getAccessToken();
|
||||||
// const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_USER_URL}`;
|
const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_USER_URL}`;
|
||||||
// const URL = urlcat(process.env.KEYCLOAK_HOST, URLPATH, { userid });
|
const URL = urlcat(process.env.KEYCLOAK_HOST, URLPATH, { userid });
|
||||||
// const response = await ky
|
const response = await fetch(URL, {
|
||||||
// .get(URL, {
|
method: 'GET',
|
||||||
// headers: {
|
headers: {
|
||||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
// Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
// },
|
},
|
||||||
// })
|
});
|
||||||
// .json();
|
if (!response.ok) {
|
||||||
// return response;
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
// }
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
return data as KeycloakUser;
|
||||||
|
}
|
||||||
|
public async updateKeycloakUser(keycloakUser: KeycloakUser): Promise<void> {
|
||||||
|
const token = await this.getAccessToken();
|
||||||
|
const userid = keycloakUser.id;
|
||||||
|
const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_USER_URL}`;
|
||||||
|
const URL = urlcat(process.env.KEYCLOAK_HOST, URLPATH, { userid });
|
||||||
|
const response = await fetch(URL, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(keycloakUser),
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
// public async getLastLogin(userid: string) {
|
// public async getLastLogin(userid: string) {
|
||||||
// const token = await this.getAccessToken();
|
// const token = await this.getAccessToken();
|
||||||
// const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_LASTLOGIN_URL}`;
|
// const URLPATH = `${process.env.KEYCLOAK_ADMIN_REALM}${process.env.REALM}${process.env.KEYCLOAK_LASTLOGIN_URL}`;
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,8 @@ export const commercials = pgTable(
|
||||||
// });
|
// });
|
||||||
export const listingEvents = pgTable('listing_events', {
|
export const listingEvents = pgTable('listing_events', {
|
||||||
id: uuid('id').primaryKey().defaultRandom().notNull(),
|
id: uuid('id').primaryKey().defaultRandom().notNull(),
|
||||||
listingId: uuid('listing_id'), // Assuming listings are referenced by UUID, adjust as necessary
|
listingId: varchar('listing_id', { length: 255 }), // Assuming listings are referenced by UUID, adjust as necessary
|
||||||
email: varchar('email', { length: 255 }).references(() => users.email),
|
email: varchar('email', { length: 255 }),
|
||||||
eventType: varchar('event_type', { length: 50 }), // 'view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact'
|
eventType: varchar('event_type', { length: 50 }), // 'view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact'
|
||||||
eventTimestamp: timestamp('event_timestamp').defaultNow(),
|
eventTimestamp: timestamp('event_timestamp').defaultNow(),
|
||||||
userIp: varchar('user_ip', { length: 45 }), // Optional if you choose to track IP in frontend or backend
|
userIp: varchar('user_ip', { length: 45 }), // Optional if you choose to track IP in frontend or backend
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export const CustomerTypeEnum = z.enum(['buyer', 'seller', 'professional']);
|
||||||
export const SubscriptionTypeEnum = z.enum(['free', 'professional', 'broker']);
|
export const SubscriptionTypeEnum = z.enum(['free', 'professional', 'broker']);
|
||||||
export const CustomerSubTypeEnum = z.enum(['broker', 'cpa', 'attorney', 'titleCompany', 'surveyor', 'appraiser']);
|
export const CustomerSubTypeEnum = z.enum(['broker', 'cpa', 'attorney', 'titleCompany', 'surveyor', 'appraiser']);
|
||||||
export const ListingsCategoryEnum = z.enum(['commercialProperty', 'business']);
|
export const ListingsCategoryEnum = z.enum(['commercialProperty', 'business']);
|
||||||
export const ZodEventTypeEnum = z.enum(['view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact', 'favorite']);
|
export const ZodEventTypeEnum = z.enum(['view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact', 'favorite', 'emailus', 'pricing']);
|
||||||
export type EventTypeEnum = z.infer<typeof ZodEventTypeEnum>;
|
export type EventTypeEnum = z.infer<typeof ZodEventTypeEnum>;
|
||||||
const PropertyTypeEnum = z.enum(['retail', 'land', 'industrial', 'office', 'mixedUse', 'multifamily', 'uncategorized']);
|
const PropertyTypeEnum = z.enum(['retail', 'land', 'industrial', 'office', 'mixedUse', 'multifamily', 'uncategorized']);
|
||||||
const TypeEnum = z.enum([
|
const TypeEnum = z.enum([
|
||||||
|
|
@ -331,7 +331,7 @@ export type ShareByEMail = z.infer<typeof ShareByEMailSchema>;
|
||||||
|
|
||||||
export const ListingEventSchema = z.object({
|
export const ListingEventSchema = z.object({
|
||||||
id: z.string().uuid(), // UUID für das Event
|
id: z.string().uuid(), // UUID für das Event
|
||||||
listingId: z.string().uuid(), // UUID für das Listing
|
listingId: z.string().uuid().optional().nullable(), // UUID für das Listing
|
||||||
email: z.string().email().optional().nullable(), // EMail des den Benutzer, optional, wenn kein Benutzer eingeloggt ist
|
email: z.string().email().optional().nullable(), // EMail des den Benutzer, optional, wenn kein Benutzer eingeloggt ist
|
||||||
eventType: ZodEventTypeEnum, // Die Event-Typen
|
eventType: ZodEventTypeEnum, // 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
|
eventTimestamp: z.string().datetime().or(z.date()), // Der Zeitstempel des Events, kann ein String im ISO-Format oder ein Date-Objekt sein
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ export interface KeycloakUser {
|
||||||
requiredActions?: any[];
|
requiredActions?: any[];
|
||||||
notBefore?: number;
|
notBefore?: number;
|
||||||
access?: Access;
|
access?: Access;
|
||||||
|
attributes?: Attributes;
|
||||||
}
|
}
|
||||||
export interface JwtUser {
|
export interface JwtUser {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
@ -128,6 +129,10 @@ export interface JwtUser {
|
||||||
lastname: string;
|
lastname: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
}
|
}
|
||||||
|
interface Attributes {
|
||||||
|
[key: string]: any;
|
||||||
|
priceID: any;
|
||||||
|
}
|
||||||
export interface Access {
|
export interface Access {
|
||||||
manageGroupMembership: boolean;
|
manageGroupMembership: boolean;
|
||||||
view: boolean;
|
view: boolean;
|
||||||
|
|
@ -174,6 +179,7 @@ export interface JwtToken {
|
||||||
family_name: string;
|
family_name: string;
|
||||||
email: string;
|
email: string;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
price_id: string;
|
||||||
}
|
}
|
||||||
export interface JwtPayload {
|
export interface JwtPayload {
|
||||||
sub: string;
|
sub: string;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { switchMap } from 'rxjs';
|
||||||
import { User } from '../../../../../bizmatch-server/src/models/db.model';
|
import { User } from '../../../../../bizmatch-server/src/models/db.model';
|
||||||
import { Checkout, KeycloakUser } from '../../../../../bizmatch-server/src/models/main.model';
|
import { Checkout, KeycloakUser } from '../../../../../bizmatch-server/src/models/main.model';
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../environments/environment';
|
||||||
|
import { AuditService } from '../../services/audit.service';
|
||||||
import { UserService } from '../../services/user.service';
|
import { UserService } from '../../services/user.service';
|
||||||
import { SharedModule } from '../../shared/shared/shared.module';
|
import { SharedModule } from '../../shared/shared/shared.module';
|
||||||
import { map2User } from '../../utils/utils';
|
import { map2User } from '../../utils/utils';
|
||||||
|
|
@ -24,25 +25,50 @@ export class PricingComponent {
|
||||||
pricingOverview: boolean | undefined = this.activatedRoute.snapshot.data['pricingOverview'] as boolean | undefined;
|
pricingOverview: boolean | undefined = this.activatedRoute.snapshot.data['pricingOverview'] as boolean | undefined;
|
||||||
keycloakUser: KeycloakUser;
|
keycloakUser: KeycloakUser;
|
||||||
user: User;
|
user: User;
|
||||||
constructor(public keycloakService: KeycloakService, private http: HttpClient, private stripeService: StripeService, private activatedRoute: ActivatedRoute, private userService: UserService, private router: Router) {}
|
constructor(
|
||||||
|
public keycloakService: KeycloakService,
|
||||||
|
private http: HttpClient,
|
||||||
|
private stripeService: StripeService,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private userService: UserService,
|
||||||
|
private router: Router,
|
||||||
|
private auditService: AuditService,
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const token = await this.keycloakService.getToken();
|
const token = await this.keycloakService.getToken();
|
||||||
this.keycloakUser = map2User(token);
|
this.keycloakUser = map2User(token);
|
||||||
if (this.keycloakUser) {
|
if (this.keycloakUser) {
|
||||||
if (this.id === 'free') {
|
|
||||||
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
||||||
|
const originalKeycloakUser = await this.userService.getKeycloakUser(this.keycloakUser.id);
|
||||||
|
const priceId = originalKeycloakUser.attributes && originalKeycloakUser.attributes['priceID'] ? originalKeycloakUser.attributes['priceID'][0] : null;
|
||||||
|
if (priceId) {
|
||||||
|
originalKeycloakUser.attributes['priceID'] = null;
|
||||||
|
await this.userService.updateKeycloakUser(originalKeycloakUser);
|
||||||
|
}
|
||||||
|
if (!this.user.subscriptionPlan) {
|
||||||
|
if (this.id === 'free' || priceId === 'free') {
|
||||||
this.user.subscriptionPlan = 'free';
|
this.user.subscriptionPlan = 'free';
|
||||||
await this.userService.saveGuaranteed(this.user);
|
await this.userService.saveGuaranteed(this.user);
|
||||||
this.router.navigate([`/account`]);
|
this.router.navigate([`/account`]);
|
||||||
} else if (this.id) {
|
} else if (this.id || priceId) {
|
||||||
this.checkout({ priceId: atob(this.id), email: this.keycloakUser.email, name: `${this.keycloakUser.firstName} ${this.keycloakUser.lastName}` });
|
const base64PriceId = this.id ? this.id : priceId;
|
||||||
} else if (!this.id && !this.pricingOverview) {
|
this.checkout({ priceId: atob(base64PriceId), email: this.keycloakUser.email, name: `${this.keycloakUser.firstName} ${this.keycloakUser.lastName}` });
|
||||||
this.user = await this.userService.getByMail(this.keycloakUser.email);
|
|
||||||
if (this.user.subscriptionId) {
|
|
||||||
this.router.navigate([`/account`]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if (this.id === 'free' || this.keycloakUser.priceId === 'free') {
|
||||||
|
// this.user.subscriptionPlan = 'free';
|
||||||
|
// await this.userService.saveGuaranteed(this.user);
|
||||||
|
// this.router.navigate([`/account`]);
|
||||||
|
// } else if (this.id || this.keycloakUser.priceId) {
|
||||||
|
// const priceId = this.id ? this.id : this.keycloakUser.priceId;
|
||||||
|
// this.checkout({ priceId: atob(priceId), email: this.keycloakUser.email, name: `${this.keycloakUser.firstName} ${this.keycloakUser.lastName}` });
|
||||||
|
// } else if (!this.id && !this.pricingOverview) {
|
||||||
|
// this.user = await this.userService.getByMail(this.keycloakUser.email);
|
||||||
|
// if (this.user.subscriptionId) {
|
||||||
|
// this.router.navigate([`/account`]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
this.pricingOverview = false;
|
this.pricingOverview = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ import { KeycloakService } from 'keycloak-angular';
|
||||||
|
|
||||||
import { User } from '../../../../../../bizmatch-server/src/models/db.model';
|
import { User } from '../../../../../../bizmatch-server/src/models/db.model';
|
||||||
import { ErrorResponse, KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
import { ErrorResponse, KeycloakUser, MailInfo } from '../../../../../../bizmatch-server/src/models/main.model';
|
||||||
import { environment } from '../../../../environments/environment';
|
|
||||||
import { MessageService } from '../../../components/message/message.service';
|
import { MessageService } from '../../../components/message/message.service';
|
||||||
import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component';
|
import { ValidatedInputComponent } from '../../../components/validated-input/validated-input.component';
|
||||||
import { ValidatedNgSelectComponent } from '../../../components/validated-ng-select/validated-ng-select.component';
|
import { ValidatedNgSelectComponent } from '../../../components/validated-ng-select/validated-ng-select.component';
|
||||||
import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
import { ValidatedTextareaComponent } from '../../../components/validated-textarea/validated-textarea.component';
|
||||||
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
import { ValidationMessagesService } from '../../../components/validation-messages.service';
|
||||||
|
import { AuditService } from '../../../services/audit.service';
|
||||||
import { MailService } from '../../../services/mail.service';
|
import { MailService } from '../../../services/mail.service';
|
||||||
import { SelectOptionsService } from '../../../services/select-options.service';
|
import { SelectOptionsService } from '../../../services/select-options.service';
|
||||||
import { UserService } from '../../../services/user.service';
|
import { UserService } from '../../../services/user.service';
|
||||||
|
|
@ -34,8 +34,9 @@ export class EmailUsComponent {
|
||||||
private validationMessagesService: ValidationMessagesService,
|
private validationMessagesService: ValidationMessagesService,
|
||||||
private messageService: MessageService,
|
private messageService: MessageService,
|
||||||
public selectOptions: SelectOptionsService,
|
public selectOptions: SelectOptionsService,
|
||||||
|
private auditService: AuditService,
|
||||||
) {
|
) {
|
||||||
this.mailinfo = { sender: {}, email: '', url: environment.mailinfoUrl };
|
this.mailinfo = createMailInfo();
|
||||||
}
|
}
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const token = await this.keycloakService.getToken();
|
const token = await this.keycloakService.getToken();
|
||||||
|
|
@ -50,9 +51,11 @@ export class EmailUsComponent {
|
||||||
}
|
}
|
||||||
async mail() {
|
async mail() {
|
||||||
try {
|
try {
|
||||||
|
this.validationMessagesService.updateMessages([]);
|
||||||
this.mailinfo.email = 'support@bizmatch.net';
|
this.mailinfo.email = 'support@bizmatch.net';
|
||||||
await this.mailService.mail(this.mailinfo);
|
await this.mailService.mail(this.mailinfo);
|
||||||
this.messageService.addMessage({ severity: 'success', text: 'Your request has been forwarded to the support team of bizmatch.', duration: 3000 });
|
this.messageService.addMessage({ severity: 'success', text: 'Your request has been forwarded to the support team of bizmatch.', duration: 3000 });
|
||||||
|
this.auditService.createEvent(null, 'emailus', this.mailinfo.email, this.mailinfo);
|
||||||
this.mailinfo = createMailInfo(this.user);
|
this.mailinfo = createMailInfo(this.user);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.messageService.addMessage({
|
this.messageService.addMessage({
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ export class UserService {
|
||||||
getNumberOfBroker(criteria?: UserListingCriteria): Observable<number> {
|
getNumberOfBroker(criteria?: UserListingCriteria): Observable<number> {
|
||||||
return this.http.post<number>(`${this.apiBaseUrl}/bizmatch/user/findTotal`, criteria);
|
return this.http.post<number>(`${this.apiBaseUrl}/bizmatch/user/findTotal`, criteria);
|
||||||
}
|
}
|
||||||
|
getKeycloakUser(id: string): Promise<KeycloakUser> {
|
||||||
|
return lastValueFrom(this.http.get<KeycloakUser>(`${this.apiBaseUrl}/bizmatch/auth/users/${id}`));
|
||||||
|
}
|
||||||
|
async updateKeycloakUser(keycloakUser: KeycloakUser): Promise<void> {
|
||||||
|
await lastValueFrom(this.http.put<void>(`${this.apiBaseUrl}/bizmatch/auth/users/${keycloakUser.id}`, keycloakUser));
|
||||||
|
}
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
// ADMIN SERVICES
|
// ADMIN SERVICES
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|
|
||||||
|
|
@ -137,9 +137,9 @@ export function resetUserListingCriteria(criteria: UserListingCriteria) {
|
||||||
criteria.radius = null;
|
criteria.radius = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createMailInfo(user: User): MailInfo {
|
export function createMailInfo(user?: User): MailInfo {
|
||||||
return {
|
return {
|
||||||
sender: { name: `${user.firstname} ${user.lastname}`, email: user.email, phoneNumber: user.phoneNumber, state: user.location?.state, comments: null },
|
sender: user ? { name: `${user.firstname} ${user.lastname}`, email: user.email, phoneNumber: user.phoneNumber, state: user.location?.state, comments: null } : {},
|
||||||
email: null,
|
email: null,
|
||||||
url: environment.mailinfoUrl,
|
url: environment.mailinfoUrl,
|
||||||
listing: null,
|
listing: null,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue