Feature/add signup permission (#1512)
* Added support to disable user sign up in the admin control panel * Update changelog Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com>
This commit is contained in:
parent
b13e4425d3
commit
616d168a7c
@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added support to disable user sign up in the admin control panel
|
||||||
- Extended the glossary of the resources page by _Deflation_, _Inflation_ and _Stagflation_
|
- Extended the glossary of the resources page by _Deflation_, _Inflation_ and _Stagflation_
|
||||||
|
|
||||||
## 1.218.0 - 2022-12-12
|
## 1.218.0 - 2022-12-12
|
||||||
|
@ -8,6 +8,7 @@ import { TagService } from '@ghostfolio/api/services/tag/tag.service';
|
|||||||
import {
|
import {
|
||||||
DEMO_USER_ID,
|
DEMO_USER_ID,
|
||||||
PROPERTY_IS_READ_ONLY_MODE,
|
PROPERTY_IS_READ_ONLY_MODE,
|
||||||
|
PROPERTY_IS_USER_SIGNUP_ENABLED,
|
||||||
PROPERTY_SLACK_COMMUNITY_USERS,
|
PROPERTY_SLACK_COMMUNITY_USERS,
|
||||||
PROPERTY_STRIPE_CONFIG,
|
PROPERTY_STRIPE_CONFIG,
|
||||||
PROPERTY_SYSTEM_MESSAGE,
|
PROPERTY_SYSTEM_MESSAGE,
|
||||||
@ -103,6 +104,15 @@ export class InfoService {
|
|||||||
)) as string;
|
)) as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isUserSignupEnabled =
|
||||||
|
((await this.propertyService.getByKey(
|
||||||
|
PROPERTY_IS_USER_SIGNUP_ENABLED
|
||||||
|
)) as boolean) ?? true;
|
||||||
|
|
||||||
|
if (isUserSignupEnabled) {
|
||||||
|
globalPermissions.push(permissions.createUserAccount);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...info,
|
...info,
|
||||||
globalPermissions,
|
globalPermissions,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||||
import { PROPERTY_IS_READ_ONLY_MODE } from '@ghostfolio/common/config';
|
import { PROPERTY_IS_USER_SIGNUP_ENABLED } from '@ghostfolio/common/config';
|
||||||
import { User, UserSettings } from '@ghostfolio/common/interfaces';
|
import { User, UserSettings } from '@ghostfolio/common/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import type { RequestWithUser } from '@ghostfolio/common/types';
|
import type { RequestWithUser } from '@ghostfolio/common/types';
|
||||||
@ -69,17 +69,16 @@ export class UserController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
public async signupUser(): Promise<UserItem> {
|
public async signupUser(): Promise<UserItem> {
|
||||||
if (this.configurationService.get('ENABLE_FEATURE_READ_ONLY_MODE')) {
|
const isUserSignupEnabled =
|
||||||
const isReadOnlyMode = (await this.propertyService.getByKey(
|
((await this.propertyService.getByKey(
|
||||||
PROPERTY_IS_READ_ONLY_MODE
|
PROPERTY_IS_USER_SIGNUP_ENABLED
|
||||||
)) as boolean;
|
)) as boolean) ?? true;
|
||||||
|
|
||||||
if (isReadOnlyMode) {
|
if (!isUserSignupEnabled) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
getReasonPhrase(StatusCodes.FORBIDDEN),
|
getReasonPhrase(StatusCodes.FORBIDDEN),
|
||||||
StatusCodes.FORBIDDEN
|
StatusCodes.FORBIDDEN
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasAdmin = await this.userService.hasAdmin();
|
const hasAdmin = await this.userService.hasAdmin();
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
PROPERTY_COUPONS,
|
PROPERTY_COUPONS,
|
||||||
PROPERTY_CURRENCIES,
|
PROPERTY_CURRENCIES,
|
||||||
PROPERTY_IS_READ_ONLY_MODE,
|
PROPERTY_IS_READ_ONLY_MODE,
|
||||||
|
PROPERTY_IS_USER_SIGNUP_ENABLED,
|
||||||
PROPERTY_SYSTEM_MESSAGE
|
PROPERTY_SYSTEM_MESSAGE
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import { Coupon, InfoItem, User } from '@ghostfolio/common/interfaces';
|
import { Coupon, InfoItem, User } from '@ghostfolio/common/interfaces';
|
||||||
@ -35,6 +36,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
public hasPermissionForSystemMessage: boolean;
|
public hasPermissionForSystemMessage: boolean;
|
||||||
public hasPermissionToToggleReadOnlyMode: boolean;
|
public hasPermissionToToggleReadOnlyMode: boolean;
|
||||||
public info: InfoItem;
|
public info: InfoItem;
|
||||||
|
public permissions = permissions;
|
||||||
public transactionCount: number;
|
public transactionCount: number;
|
||||||
public userCount: number;
|
public userCount: number;
|
||||||
public user: User;
|
public user: User;
|
||||||
@ -167,6 +169,13 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onEnableUserSignupModeChange(aEvent: MatSlideToggleChange) {
|
||||||
|
this.putAdminSetting({
|
||||||
|
key: PROPERTY_IS_USER_SIGNUP_ENABLED,
|
||||||
|
value: aEvent.checked ? undefined : false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public onSetSystemMessage() {
|
public onSetSystemMessage() {
|
||||||
const systemMessage = prompt($localize`Please set your system message:`);
|
const systemMessage = prompt($localize`Please set your system message:`);
|
||||||
|
|
||||||
@ -214,7 +223,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
private putAdminSetting({ key, value }: { key: string; value: any }) {
|
private putAdminSetting({ key, value }: { key: string; value: any }) {
|
||||||
this.dataService
|
this.dataService
|
||||||
.putAdminSetting(key, {
|
.putAdminSetting(key, {
|
||||||
value: value ? JSON.stringify(value) : undefined
|
value: value || value === false ? JSON.stringify(value) : undefined
|
||||||
})
|
})
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
|
@ -82,6 +82,26 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="d-flex my-3">
|
||||||
|
<div class="w-50" i18n>User Signup</div>
|
||||||
|
<div class="w-50">
|
||||||
|
<mat-slide-toggle
|
||||||
|
color="primary"
|
||||||
|
[checked]="info.globalPermissions.includes(permissions.createUserAccount)"
|
||||||
|
(change)="onEnableUserSignupModeChange($event)"
|
||||||
|
></mat-slide-toggle>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="hasPermissionToToggleReadOnlyMode" class="d-flex my-3">
|
||||||
|
<div class="w-50" i18n>Read-only Mode</div>
|
||||||
|
<div class="w-50">
|
||||||
|
<mat-slide-toggle
|
||||||
|
color="primary"
|
||||||
|
[checked]="info?.isReadOnlyMode"
|
||||||
|
(change)="onReadOnlyModeChange($event)"
|
||||||
|
></mat-slide-toggle>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div *ngIf="hasPermissionForSystemMessage" class="d-flex my-3">
|
<div *ngIf="hasPermissionForSystemMessage" class="d-flex my-3">
|
||||||
<div class="w-50" i18n>System Message</div>
|
<div class="w-50" i18n>System Message</div>
|
||||||
<div class="w-50">
|
<div class="w-50">
|
||||||
@ -109,16 +129,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="hasPermissionToToggleReadOnlyMode" class="d-flex my-3">
|
|
||||||
<div class="w-50" i18n>Read-only Mode</div>
|
|
||||||
<div class="w-50">
|
|
||||||
<mat-slide-toggle
|
|
||||||
color="primary"
|
|
||||||
[checked]="info?.isReadOnlyMode"
|
|
||||||
(change)="onReadOnlyModeChange($event)"
|
|
||||||
></mat-slide-toggle>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
*ngIf="hasPermissionForSubscription"
|
*ngIf="hasPermissionForSubscription"
|
||||||
class="d-flex my-3 subscription"
|
class="d-flex my-3 subscription"
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<mat-toolbar class="px-2">
|
<mat-toolbar class="px-2">
|
||||||
<ng-container *ngIf="user">
|
<ng-container *ngIf="user">
|
||||||
<a
|
<a
|
||||||
[routerLink]="['/']"
|
|
||||||
class="align-items-center d-flex h-100 no-min-width px-2 rounded-0"
|
class="align-items-center d-flex h-100 no-min-width px-2 rounded-0"
|
||||||
mat-button
|
mat-button
|
||||||
|
[routerLink]="['/']"
|
||||||
>
|
>
|
||||||
<gf-logo></gf-logo>
|
<gf-logo></gf-logo>
|
||||||
</a>
|
</a>
|
||||||
@ -289,7 +289,7 @@
|
|||||||
<ng-container i18n>Sign in</ng-container>
|
<ng-container i18n>Sign in</ng-container>
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
*ngIf="currentRoute !== 'register' && !info?.isReadOnlyMode"
|
*ngIf="currentRoute !== 'register' && hasPermissionToCreateUser"
|
||||||
class="d-none d-sm-block"
|
class="d-none d-sm-block"
|
||||||
color="primary"
|
color="primary"
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
|
@ -38,6 +38,7 @@ export class HeaderComponent implements OnChanges {
|
|||||||
public hasPermissionForSubscription: boolean;
|
public hasPermissionForSubscription: boolean;
|
||||||
public hasPermissionToAccessAdminControl: boolean;
|
public hasPermissionToAccessAdminControl: boolean;
|
||||||
public hasPermissionToAccessFearAndGreedIndex: boolean;
|
public hasPermissionToAccessFearAndGreedIndex: boolean;
|
||||||
|
public hasPermissionToCreateUser: boolean;
|
||||||
public impersonationId: string;
|
public impersonationId: string;
|
||||||
public isMenuOpen: boolean;
|
public isMenuOpen: boolean;
|
||||||
|
|
||||||
@ -79,6 +80,11 @@ export class HeaderComponent implements OnChanges {
|
|||||||
this.info?.globalPermissions,
|
this.info?.globalPermissions,
|
||||||
permissions.enableFearAndGreedIndex
|
permissions.enableFearAndGreedIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.hasPermissionToCreateUser = hasPermission(
|
||||||
|
this.info?.globalPermissions,
|
||||||
|
permissions.createUserAccount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public impersonateAccount(aId: string) {
|
public impersonateAccount(aId: string) {
|
||||||
|
@ -17,6 +17,7 @@ export class LandingPageComponent implements OnDestroy, OnInit {
|
|||||||
public demoAuthToken: string;
|
public demoAuthToken: string;
|
||||||
public deviceType: string;
|
public deviceType: string;
|
||||||
public hasPermissionForStatistics: boolean;
|
public hasPermissionForStatistics: boolean;
|
||||||
|
public hasPermissionToCreateUser: boolean;
|
||||||
public statistics: Statistics;
|
public statistics: Statistics;
|
||||||
public testimonials = [
|
public testimonials = [
|
||||||
{
|
{
|
||||||
@ -54,6 +55,11 @@ export class LandingPageComponent implements OnDestroy, OnInit {
|
|||||||
permissions.enableStatistics
|
permissions.enableStatistics
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.hasPermissionToCreateUser = hasPermission(
|
||||||
|
globalPermissions,
|
||||||
|
permissions.createUserAccount
|
||||||
|
);
|
||||||
|
|
||||||
this.statistics = statistics;
|
this.statistics = statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,15 +31,18 @@
|
|||||||
<div class="button-container mb-5 row">
|
<div class="button-container mb-5 row">
|
||||||
<div class="align-items-center col d-flex justify-content-center">
|
<div class="align-items-center col d-flex justify-content-center">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a
|
<ng-container *ngIf="hasPermissionToCreateUser">
|
||||||
class="d-inline-block"
|
<a
|
||||||
color="primary"
|
class="d-inline-block"
|
||||||
mat-flat-button
|
color="primary"
|
||||||
[routerLink]="['/register']"
|
mat-flat-button
|
||||||
|
[routerLink]="['/register']"
|
||||||
|
>
|
||||||
|
Get Started
|
||||||
|
</a>
|
||||||
|
<div class="d-inline-block mx-3 text-muted">or</div></ng-container
|
||||||
>
|
>
|
||||||
Get Started
|
|
||||||
</a>
|
|
||||||
<div class="d-inline-block mx-3 text-muted">or</div>
|
|
||||||
<a class="d-inline-block" mat-stroked-button [routerLink]="['/demo']">
|
<a class="d-inline-block" mat-stroked-button [routerLink]="['/demo']">
|
||||||
Live Demo
|
Live Demo
|
||||||
</a>
|
</a>
|
||||||
@ -306,7 +309,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row my-5">
|
<div *ngIf="hasPermissionToCreateUser" class="row my-5">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h2 class="h4 mb-1 text-center">Are <strong>you</strong> ready?</h2>
|
<h2 class="h4 mb-1 text-center">Are <strong>you</strong> ready?</h2>
|
||||||
<p class="lead mb-3 text-center">
|
<p class="lead mb-3 text-center">
|
||||||
|
@ -25,6 +25,7 @@ export class RegisterPageComponent implements OnDestroy, OnInit {
|
|||||||
public demoAuthToken: string;
|
public demoAuthToken: string;
|
||||||
public deviceType: string;
|
public deviceType: string;
|
||||||
public hasPermissionForSocialLogin: boolean;
|
public hasPermissionForSocialLogin: boolean;
|
||||||
|
public hasPermissionToCreateUser: boolean;
|
||||||
public historicalDataItems: LineChartItem[];
|
public historicalDataItems: LineChartItem[];
|
||||||
public info: InfoItem;
|
public info: InfoItem;
|
||||||
|
|
||||||
@ -52,6 +53,10 @@ export class RegisterPageComponent implements OnDestroy, OnInit {
|
|||||||
globalPermissions,
|
globalPermissions,
|
||||||
permissions.enableSocialLogin
|
permissions.enableSocialLogin
|
||||||
);
|
);
|
||||||
|
this.hasPermissionToCreateUser = hasPermission(
|
||||||
|
globalPermissions,
|
||||||
|
permissions.createUserAccount
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createAccount() {
|
public async createAccount() {
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="button-container row">
|
<div *ngIf="hasPermissionToCreateUser" class="button-container row">
|
||||||
<div class="align-items-center col d-flex justify-content-center">
|
<div class="align-items-center col d-flex justify-content-center">
|
||||||
<div class="py-5 text-center">
|
<div class="py-5 text-center">
|
||||||
<button
|
<button
|
||||||
class="d-inline-block"
|
class="d-inline-block"
|
||||||
color="primary"
|
color="primary"
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
[disabled]="!demoAuthToken || info?.isReadOnlyMode"
|
[disabled]="!demoAuthToken"
|
||||||
(click)="createAccount()"
|
(click)="createAccount()"
|
||||||
>
|
>
|
||||||
<ng-container i18n>Create Account</ng-container>
|
<ng-container i18n>Create Account</ng-container>
|
||||||
|
@ -74,6 +74,7 @@ export const PROPERTY_BENCHMARKS = 'BENCHMARKS';
|
|||||||
export const PROPERTY_COUPONS = 'COUPONS';
|
export const PROPERTY_COUPONS = 'COUPONS';
|
||||||
export const PROPERTY_CURRENCIES = 'CURRENCIES';
|
export const PROPERTY_CURRENCIES = 'CURRENCIES';
|
||||||
export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE';
|
export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE';
|
||||||
|
export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED';
|
||||||
export const PROPERTY_SLACK_COMMUNITY_USERS = 'SLACK_COMMUNITY_USERS';
|
export const PROPERTY_SLACK_COMMUNITY_USERS = 'SLACK_COMMUNITY_USERS';
|
||||||
export const PROPERTY_STRIPE_CONFIG = 'STRIPE_CONFIG';
|
export const PROPERTY_STRIPE_CONFIG = 'STRIPE_CONFIG';
|
||||||
export const PROPERTY_SYSTEM_MESSAGE = 'SYSTEM_MESSAGE';
|
export const PROPERTY_SYSTEM_MESSAGE = 'SYSTEM_MESSAGE';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user