Browse Source

Refactor JwtStrategy

pull/1764/head
Thomas 3 years ago
parent
commit
94da578e10
  1. 36
      apps/api/src/app/admin/admin.service.ts
  2. 21
      apps/api/src/app/auth/jwt.strategy.ts
  3. 4
      apps/api/src/app/info/info.service.ts
  4. 6
      apps/api/src/app/user/user.controller.ts
  5. 6
      apps/api/src/app/user/user.service.ts
  6. 2
      apps/api/src/interceptors/transform-data-source-in-request.interceptor.ts
  7. 4
      apps/api/src/interceptors/transform-data-source-in-response.interceptor.ts
  8. 13
      apps/client/src/app/components/admin-users/admin-users.html

36
apps/api/src/app/admin/admin.service.ts

@ -231,12 +231,27 @@ export class AdminService {
}
private async getUsersWithAnalytics(): Promise<AdminData['users']> {
const usersWithAnalytics = await this.prismaService.user.findMany({
orderBy: {
let orderBy: any = {
createdAt: 'desc'
};
let where;
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
orderBy = {
Analytics: {
updatedAt: 'desc'
}
},
};
where = {
NOT: {
Analytics: null
}
};
}
const usersWithAnalytics = await this.prismaService.user.findMany({
orderBy,
where,
select: {
_count: {
select: { Account: true, Order: true }
@ -252,19 +267,16 @@ export class AdminService {
id: true,
Subscription: true
},
take: 30,
where: {
NOT: {
Analytics: null
}
}
take: 30
});
return usersWithAnalytics.map(
({ _count, Analytics, createdAt, id, Subscription }) => {
const daysSinceRegistration =
differenceInDays(new Date(), createdAt) + 1;
const engagement = Analytics.activityCount / daysSinceRegistration;
const engagement = Analytics
? Analytics.activityCount / daysSinceRegistration
: undefined;
const subscription = this.configurationService.get(
'ENABLE_FEATURE_SUBSCRIPTION'
@ -278,8 +290,8 @@ export class AdminService {
id,
subscription,
accountCount: _count.Account || 0,
country: Analytics.country,
lastActivity: Analytics.updatedAt,
country: Analytics?.country,
lastActivity: Analytics?.updatedAt,
transactionCount: _count.Order || 0
};
}

21
apps/api/src/app/auth/jwt.strategy.ts

@ -1,33 +1,46 @@
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { HEADER_KEY_TIMEZONE } from '@ghostfolio/common/config';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import * as countriesAndTimezones from 'countries-and-timezones';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
public constructor(
readonly configurationService: ConfigurationService,
private readonly configurationService: ConfigurationService,
private readonly prismaService: PrismaService,
private readonly userService: UserService
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
passReqToCallback: true,
secretOrKey: configurationService.get('JWT_SECRET_KEY')
});
}
public async validate({ id }: { id: string }) {
public async validate(request: Request, { id }: { id: string }) {
try {
const timezone = request.headers[HEADER_KEY_TIMEZONE.toLowerCase()];
const user = await this.userService.user({ id });
if (user) {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
const country =
countriesAndTimezones.getCountryForTimezone(timezone)?.id;
await this.prismaService.analytics.upsert({
create: { User: { connect: { id: user.id } } },
update: { activityCount: { increment: 1 }, updatedAt: new Date() },
create: { country, User: { connect: { id: user.id } } },
update: {
country,
activityCount: { increment: 1 },
updatedAt: new Date()
},
where: { userId: user.id }
});
}
return user;
} else {

4
apps/api/src/app/info/info.service.ts

@ -59,9 +59,7 @@ export class InfoService {
}
if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') === true
) {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
info.fearAndGreedDataSource = encodeDataSource(
ghostfolioFearAndGreedIndexDataSource
);

6
apps/api/src/app/user/user.controller.ts

@ -1,5 +1,4 @@
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { HEADER_KEY_TIMEZONE } from '@ghostfolio/common/config';
import { User, UserSettings } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
@ -66,9 +65,7 @@ export class UserController {
}
@Post()
public async signupUser(
@Headers(HEADER_KEY_TIMEZONE.toLowerCase()) timezone
): Promise<UserItem> {
public async signupUser(): Promise<UserItem> {
const isUserSignupEnabled =
await this.propertyService.isUserSignupEnabled();
@ -82,7 +79,6 @@ export class UserController {
const hasAdmin = await this.userService.hasAdmin();
const { accessToken, id, role } = await this.userService.createUser({
timezone,
data: { role: hasAdmin ? 'USER' : 'ADMIN' }
});

6
apps/api/src/app/user/user.service.ts

@ -16,7 +16,6 @@ import {
} from '@ghostfolio/common/permissions';
import { Injectable } from '@nestjs/common';
import { Prisma, Role, User } from '@prisma/client';
import * as countriesAndTimezones from 'countries-and-timezones';
import { sortBy } from 'lodash';
const crypto = require('crypto');
@ -233,11 +232,9 @@ export class UserService {
}
public async createUser({
data,
timezone
data
}: {
data: Prisma.UserCreateInput;
timezone?: string;
}): Promise<User> {
if (!data?.provider) {
data.provider = 'ANONYMOUS';
@ -266,7 +263,6 @@ export class UserService {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
await this.prismaService.analytics.create({
data: {
country: countriesAndTimezones.getCountryForTimezone(timezone)?.id,
User: { connect: { id: user.id } }
}
});

2
apps/api/src/interceptors/transform-data-source-in-request.interceptor.ts

@ -24,7 +24,7 @@ export class TransformDataSourceInRequestInterceptor<T>
const http = context.switchToHttp();
const request = http.getRequest();
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') === true) {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
if (request.body.dataSource) {
request.body.dataSource = decodeDataSource(request.body.dataSource);
}

4
apps/api/src/interceptors/transform-data-source-in-response.interceptor.ts

@ -26,9 +26,7 @@ export class TransformDataSourceInResponseInterceptor<T>
): Observable<any> {
return next.handle().pipe(
map((data: any) => {
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') === true
) {
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
data = redactAttributes({
options: [
{

13
apps/client/src/app/components/admin-users/admin-users.html

@ -28,7 +28,13 @@
>
<ng-container i18n>Engagement per Day</ng-container>
</th>
<th class="mat-header-cell px-1 py-2" i18n>Last Request</th>
<th
*ngIf="hasPermissionForSubscription"
class="mat-header-cell px-1 py-2"
i18n
>
Last Request
</th>
<th class="mat-header-cell px-1 py-2"></th>
</tr>
</thead>
@ -86,7 +92,10 @@
[value]="userItem.engagement"
></gf-value>
</td>
<td class="mat-cell px-1 py-2">
<td
*ngIf="hasPermissionForSubscription"
class="mat-cell px-1 py-2"
>
{{ formatDistanceToNow(userItem.lastActivity) }}
</td>
<td class="mat-cell px-1 py-2">

Loading…
Cancel
Save