Browse Source

Update permissions and add discount

pull/178/head
Thomas 4 years ago
parent
commit
2ae2470a33
  1. 7
      apps/api/src/app/subscription/subscription.controller.ts
  2. 18
      apps/api/src/app/subscription/subscription.service.ts
  3. 7
      apps/api/src/app/user/interfaces/user-settings-params.interface.ts
  4. 19
      apps/api/src/app/user/user.controller.ts
  5. 35
      apps/api/src/app/user/user.service.ts
  6. 18
      apps/client/src/app/pages/account/account-page.component.ts
  7. 11
      apps/client/src/app/pages/account/account-page.html
  8. 2
      apps/client/src/app/pages/pricing/pricing-page.component.ts
  9. 10
      apps/client/src/app/pages/pricing/pricing-page.html
  10. 11
      apps/client/src/app/services/data.service.ts
  11. 2
      libs/common/src/lib/interfaces/subscription.interface.ts
  12. 4
      libs/common/src/lib/interfaces/user-settings.interface.ts
  13. 1
      libs/common/src/lib/interfaces/user-with-settings.ts
  14. 9
      libs/common/src/lib/permissions.ts

7
apps/api/src/app/subscription/subscription.controller.ts

@ -34,11 +34,14 @@ export class SubscriptionController {
res.redirect(`${this.configurationService.get('ROOT_URL')}/account`);
}
@Post('stripe/checkout-session/create')
@Post('stripe/checkout-session')
@UseGuards(AuthGuard('jwt'))
public async createCheckoutSession(@Body() { priceId }: { priceId: string }) {
public async createCheckoutSession(
@Body() { couponId, priceId }: { couponId: string; priceId: string }
) {
try {
return await this.subscriptionService.createCheckoutSession({
couponId,
priceId,
userId: this.request.user.id
});

18
apps/api/src/app/subscription/subscription.service.ts

@ -21,13 +21,15 @@ export class SubscriptionService {
}
public async createCheckoutSession({
couponId,
priceId,
userId
}: {
couponId?: string;
priceId: string;
userId: string;
}) {
const session = await this.stripe.checkout.sessions.create({
const checkoutSessionCreateParams: Stripe.Checkout.SessionCreateParams = {
cancel_url: `${this.configurationService.get('ROOT_URL')}/account`,
client_reference_id: userId,
line_items: [
@ -44,7 +46,19 @@ export class SubscriptionService {
success_url: `${this.configurationService.get(
'ROOT_URL'
)}/api/subscription/stripe/callback?checkoutSessionId={CHECKOUT_SESSION_ID}`
});
};
if (couponId) {
checkoutSessionCreateParams.discounts = [
{
coupon: couponId
}
];
}
const session = await this.stripe.checkout.sessions.create(
checkoutSessionCreateParams
);
return {
sessionId: session.id

7
apps/api/src/app/user/interfaces/user-settings-params.interface.ts

@ -0,0 +1,7 @@
import { Currency, ViewMode } from '@prisma/client';
export interface UserSettingsParams {
currency?: Currency;
userId: string;
viewMode?: ViewMode;
}

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

@ -25,6 +25,7 @@ import { User as UserModel } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { UserItem } from './interfaces/user-item.interface';
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
import { UpdateUserSettingsDto } from './update-user-settings.dto';
import { UserService } from './user.service';
@ -92,10 +93,20 @@ export class UserController {
);
}
return await this.userService.updateUserSettings({
const userSettings: UserSettingsParams = {
currency: data.baseCurrency,
userId: this.request.user.id,
viewMode: data.viewMode
});
userId: this.request.user.id
};
if (
hasPermission(
getPermissions(this.request.user.role),
permissions.updateViewMode
)
) {
userSettings.viewMode = data.viewMode;
}
return await this.userService.updateUserSettings(userSettings);
}
}

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

@ -1,13 +1,13 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { locale } from '@ghostfolio/common/config';
import { resetHours } from '@ghostfolio/common/helper';
import { User as IUser, UserWithSettings } from '@ghostfolio/common/interfaces';
import { getPermissions, permissions } from '@ghostfolio/common/permissions';
import { SubscriptionType } from '@ghostfolio/common/types/subscription.type';
import { Injectable } from '@nestjs/common';
import { Currency, Prisma, Provider, User, ViewMode } from '@prisma/client';
import { add, isBefore } from 'date-fns';
import { isBefore } from 'date-fns';
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
const crypto = require('crypto');
@ -24,7 +24,7 @@ export class UserService {
Account,
alias,
id,
role,
permissions,
Settings,
subscription
}: UserWithSettings): Promise<IUser> {
@ -36,15 +36,10 @@ export class UserService {
where: { GranteeUser: { id } }
});
const currentPermissions = getPermissions(role);
if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
currentPermissions.push(permissions.accessFearAndGreedIndex);
}
return {
alias,
id,
permissions,
subscription,
access: access.map((accessItem) => {
return {
@ -53,7 +48,6 @@ export class UserService {
};
}),
accounts: Account,
permissions: currentPermissions,
settings: {
locale,
baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY,
@ -72,6 +66,14 @@ export class UserService {
const user: UserWithSettings = userFromDatabase;
const currentPermissions = getPermissions(userFromDatabase.role);
if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
currentPermissions.push(permissions.accessFearAndGreedIndex);
}
user.permissions = currentPermissions;
if (userFromDatabase?.Settings) {
if (!userFromDatabase.Settings.currency) {
// Set default currency if needed
@ -106,6 +108,13 @@ export class UserService {
type: SubscriptionType.Basic
};
}
if (user.subscription.type === SubscriptionType.Basic) {
user.permissions = user.permissions.filter((permission) => {
return permission !== permissions.updateViewMode;
});
user.Settings.viewMode = ViewMode.ZEN;
}
}
return user;
@ -213,11 +222,7 @@ export class UserService {
currency,
userId,
viewMode
}: {
currency?: Currency;
userId: string;
viewMode?: ViewMode;
}) {
}: UserSettingsParams) {
await this.prisma.settings.upsert({
create: {
currency,

18
apps/client/src/app/pages/account/account-page.component.ts

@ -31,8 +31,11 @@ export class AccountPageComponent implements OnDestroy, OnInit {
public accesses: Access[];
public baseCurrency: Currency;
public coupon: number;
public couponId: string;
public currencies: Currency[] = [];
public defaultDateFormat = DEFAULT_DATE_FORMAT;
public hasPermissionToUpdateViewMode: boolean;
public hasPermissionToUpdateUserSettings: boolean;
public price: number;
public priceId: string;
@ -54,9 +57,11 @@ export class AccountPageComponent implements OnDestroy, OnInit {
.fetchInfo()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ currencies, subscriptions }) => {
this.coupon = subscriptions?.[0]?.coupon;
this.couponId = subscriptions?.[0]?.couponId;
this.currencies = currencies;
this.price = subscriptions?.[0].price;
this.priceId = subscriptions?.[0].priceId;
this.price = subscriptions?.[0]?.price;
this.priceId = subscriptions?.[0]?.priceId;
this.changeDetectorRef.markForCheck();
});
@ -72,6 +77,11 @@ export class AccountPageComponent implements OnDestroy, OnInit {
permissions.updateUserSettings
);
this.hasPermissionToUpdateViewMode = hasPermission(
this.user.permissions,
permissions.updateViewMode
);
this.changeDetectorRef.markForCheck();
}
});
@ -107,9 +117,9 @@ export class AccountPageComponent implements OnDestroy, OnInit {
});
}
public onCheckout(priceId: string) {
public onCheckout() {
this.dataService
.createCheckoutSession(priceId)
.createCheckoutSession({ couponId: this.couponId, priceId: this.priceId })
.pipe(
switchMap(({ sessionId }: { sessionId: string }) => {
return this.stripeService.redirectToCheckout({

11
apps/client/src/app/pages/account/account-page.html

@ -32,8 +32,13 @@
Upgrade
</button>
<div *ngIf="price" class="mt-1">
{{ user.settings.baseCurrency }} {{ price }}
<span i18n>per year</span>
{{ user.settings.baseCurrency }}
<ng-container *ngIf="coupon"
>{{ price - coupon }}
<del>{{ user.settings.baseCurrency }} {{ price }}</del>
</ng-container>
<ng-container *ngIf="!coupon">{{ price }}</ng-container>
<span i18n> per year</span>
</div>
</div>
</div>
@ -61,7 +66,7 @@
<mat-label i18n>View Mode</mat-label>
<mat-select
name="viewMode"
[disabled]="!hasPermissionToUpdateUserSettings"
[disabled]="!hasPermissionToUpdateViewMode"
[value]="user.settings.viewMode"
(selectionChange)="onChangeUserSettings('viewMode', $event.value)"
>

2
apps/client/src/app/pages/pricing/pricing-page.component.ts

@ -13,6 +13,7 @@ import { takeUntil } from 'rxjs/operators';
})
export class PricingPageComponent implements OnInit {
public baseCurrency = baseCurrency;
public coupon: number;
public isLoggedIn: boolean;
public price: number;
public user: User;
@ -31,6 +32,7 @@ export class PricingPageComponent implements OnInit {
.fetchInfo()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ subscriptions }) => {
this.coupon = this.price = subscriptions?.[0]?.coupon;
this.price = subscriptions?.[0]?.price;
this.changeDetectorRef.markForCheck();

10
apps/client/src/app/pages/pricing/pricing-page.html

@ -179,8 +179,14 @@
<p class="h5 text-right" [hidden]="!price">
<span class="font-weight-normal"
>{{ user?.settings.baseCurrency || baseCurrency }}
<strong>{{ price }}</strong>
per year</span
<ng-container *ngIf="coupon"
><strong>{{ price - coupon }} </strong>
<del>{{ user.settings.baseCurrency }} {{ price }}</del>
</ng-container>
<ng-container *ngIf="!coupon"
><strong>{{ price }}</strong></ng-container
>
<span i18n> per year</span></span
>
</p>
</mat-card>

11
apps/client/src/app/services/data.service.ts

@ -43,8 +43,15 @@ export class DataService {
private settingsStorageService: SettingsStorageService
) {}
public createCheckoutSession(priceId) {
return this.http.post('/api/subscription/stripe/checkout-session/create', {
public createCheckoutSession({
couponId,
priceId
}: {
couponId?: string;
priceId: string;
}) {
return this.http.post('/api/subscription/stripe/checkout-session', {
couponId,
priceId
});
}

2
libs/common/src/lib/interfaces/subscription.interface.ts

@ -1,4 +1,6 @@
export interface Subscription {
coupon?: number;
couponId?: string;
price: number;
priceId: string;
}

4
libs/common/src/lib/interfaces/user-settings.interface.ts

@ -1,7 +1,7 @@
import { Currency, ViewMode } from '@prisma/client';
export interface UserSettings {
baseCurrency: Currency;
baseCurrency?: Currency;
locale: string;
viewMode: ViewMode;
viewMode?: ViewMode;
}

1
libs/common/src/lib/interfaces/user-with-settings.ts

@ -3,6 +3,7 @@ import { Account, Settings, User } from '@prisma/client';
export type UserWithSettings = User & {
Account: Account[];
permissions?: string[];
Settings: Settings;
subscription?: {
expiresAt?: Date;

9
libs/common/src/lib/permissions.ts

@ -21,7 +21,8 @@ export const permissions = {
updateAccount: 'updateAccount',
updateAuthDevice: 'updateAuthDevice',
updateOrder: 'updateOrder',
updateUserSettings: 'updateUserSettings'
updateUserSettings: 'updateUserSettings',
updateViewMode: 'updateViewMode'
};
export function hasPermission(
@ -46,7 +47,8 @@ export function getPermissions(aRole: Role): string[] {
permissions.updateAccount,
permissions.updateAuthDevice,
permissions.updateOrder,
permissions.updateUserSettings
permissions.updateUserSettings,
permissions.updateViewMode
];
case 'DEMO':
@ -62,7 +64,8 @@ export function getPermissions(aRole: Role): string[] {
permissions.updateAccount,
permissions.updateAuthDevice,
permissions.updateOrder,
permissions.updateUserSettings
permissions.updateUserSettings,
permissions.updateViewMode
];
default:

Loading…
Cancel
Save