Browse Source

Add knob to control user signup feature

Add knob "Disable User Signup" in Admin overview page
Add new permission to handle this knob, only admin has access
Add new admin property to store this knob config
Validate user signup against this config.
pull/1512/head
gobdevel 3 years ago
parent
commit
f5eee4b4dc
  1. 13
      apps/api/src/app/info/info.service.ts
  2. 18
      apps/api/src/app/user/user.controller.ts
  3. 6
      apps/api/src/app/user/user.service.ts
  4. 1
      apps/api/src/services/configuration.service.ts
  5. 1
      apps/api/src/services/interfaces/environment.interface.ts
  6. 16
      apps/client/src/app/components/admin-overview/admin-overview.component.ts
  7. 11
      apps/client/src/app/components/admin-overview/admin-overview.html
  8. 1
      libs/common/src/lib/config.ts
  9. 3
      libs/common/src/lib/permissions.ts

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

@ -11,6 +11,7 @@ import {
PROPERTY_SLACK_COMMUNITY_USERS, PROPERTY_SLACK_COMMUNITY_USERS,
PROPERTY_STRIPE_CONFIG, PROPERTY_STRIPE_CONFIG,
PROPERTY_SYSTEM_MESSAGE, PROPERTY_SYSTEM_MESSAGE,
PROPERTY_DISABLE_USER_SIGNUP,
ghostfolioFearAndGreedIndexDataSource ghostfolioFearAndGreedIndexDataSource
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { import {
@ -103,6 +104,18 @@ export class InfoService {
)) as string; )) as string;
} }
if (this.configurationService.get('ENABLE_FEATURE_USER_SIGNUP_CONTROL')) {
const isUserSignupDisabled = (await this.propertyService.getByKey(
PROPERTY_DISABLE_USER_SIGNUP
)) as boolean;
if (!isUserSignupDisabled) {
globalPermissions.push(permissions.createUserAccount);
}
} else { // By default enabled
globalPermissions.push(permissions.createUserAccount);
}
return { return {
...info, ...info,
globalPermissions, globalPermissions,

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

@ -1,6 +1,9 @@
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_READ_ONLY_MODE,
PROPERTY_DISABLE_USER_SIGNUP
} 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';
@ -82,6 +85,19 @@ export class UserController {
} }
} }
if (this.configurationService.get('ENABLE_FEATURE_USER_SIGNUP_CONTROL')) {
const isUserSignupDisabled = (await this.propertyService.getByKey(
PROPERTY_DISABLE_USER_SIGNUP
)) as boolean;
if (isUserSignupDisabled) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
}
const hasAdmin = await this.userService.hasAdmin(); const hasAdmin = await this.userService.hasAdmin();
const { accessToken, id, role } = await this.userService.createUser({ const { accessToken, id, role } = await this.userService.createUser({

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

@ -185,6 +185,12 @@ export class UserService {
} }
} }
if (this.configurationService.get('ENABLE_FEATURE_USER_SIGNUP_CONTROL')) {
if (hasRole(user, Role.ADMIN)) {
currentPermissions.push(permissions.toggleUserSignupMode);
}
}
user.Account = sortBy(user.Account, (account) => { user.Account = sortBy(user.Account, (account) => {
return account.name; return account.name;
}); });

1
apps/api/src/services/configuration.service.ts

@ -30,6 +30,7 @@ export class ConfigurationService {
ENABLE_FEATURE_STATISTICS: bool({ default: false }), ENABLE_FEATURE_STATISTICS: bool({ default: false }),
ENABLE_FEATURE_SUBSCRIPTION: bool({ default: false }), ENABLE_FEATURE_SUBSCRIPTION: bool({ default: false }),
ENABLE_FEATURE_SYSTEM_MESSAGE: bool({ default: false }), ENABLE_FEATURE_SYSTEM_MESSAGE: bool({ default: false }),
ENABLE_FEATURE_USER_SIGNUP_CONTROL: bool({ default: false }),
EOD_HISTORICAL_DATA_API_KEY: str({ default: '' }), EOD_HISTORICAL_DATA_API_KEY: str({ default: '' }),
GOOGLE_CLIENT_ID: str({ default: 'dummyClientId' }), GOOGLE_CLIENT_ID: str({ default: 'dummyClientId' }),
GOOGLE_SECRET: str({ default: 'dummySecret' }), GOOGLE_SECRET: str({ default: 'dummySecret' }),

1
apps/api/src/services/interfaces/environment.interface.ts

@ -16,6 +16,7 @@ export interface Environment extends CleanedEnvAccessors {
ENABLE_FEATURE_STATISTICS: boolean; ENABLE_FEATURE_STATISTICS: boolean;
ENABLE_FEATURE_SUBSCRIPTION: boolean; ENABLE_FEATURE_SUBSCRIPTION: boolean;
ENABLE_FEATURE_SYSTEM_MESSAGE: boolean; ENABLE_FEATURE_SYSTEM_MESSAGE: boolean;
ENABLE_FEATURE_USER_SIGNUP_CONTROL: boolean;
EOD_HISTORICAL_DATA_API_KEY: string; EOD_HISTORICAL_DATA_API_KEY: string;
GOOGLE_CLIENT_ID: string; GOOGLE_CLIENT_ID: string;
GOOGLE_SECRET: string; GOOGLE_SECRET: string;

16
apps/client/src/app/components/admin-overview/admin-overview.component.ts

@ -7,7 +7,8 @@ import {
PROPERTY_COUPONS, PROPERTY_COUPONS,
PROPERTY_CURRENCIES, PROPERTY_CURRENCIES,
PROPERTY_IS_READ_ONLY_MODE, PROPERTY_IS_READ_ONLY_MODE,
PROPERTY_SYSTEM_MESSAGE PROPERTY_SYSTEM_MESSAGE,
PROPERTY_DISABLE_USER_SIGNUP
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { Coupon, InfoItem, User } from '@ghostfolio/common/interfaces'; import { Coupon, InfoItem, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -34,6 +35,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
public hasPermissionForSubscription: boolean; public hasPermissionForSubscription: boolean;
public hasPermissionForSystemMessage: boolean; public hasPermissionForSystemMessage: boolean;
public hasPermissionToToggleReadOnlyMode: boolean; public hasPermissionToToggleReadOnlyMode: boolean;
public hasPermissionToToggleUserSignupMode: boolean;
public info: InfoItem; public info: InfoItem;
public transactionCount: number; public transactionCount: number;
public userCount: number; public userCount: number;
@ -69,6 +71,11 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
this.user.permissions, this.user.permissions,
permissions.toggleReadOnlyMode permissions.toggleReadOnlyMode
); );
this.hasPermissionToToggleUserSignupMode = hasPermission(
this.user.permissions,
permissions.toggleUserSignupMode
);
} }
}); });
} }
@ -167,6 +174,13 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
}); });
} }
public onEnableUserSignupModeChange(aEvent: MatSlideToggleChange) {
this.putAdminSetting({
key: PROPERTY_DISABLE_USER_SIGNUP,
value: aEvent.checked ? true : undefined
});
}
public onSetSystemMessage() { public onSetSystemMessage() {
const systemMessage = prompt($localize`Please set your system message:`); const systemMessage = prompt($localize`Please set your system message:`);

11
apps/client/src/app/components/admin-overview/admin-overview.html

@ -119,6 +119,17 @@
></mat-slide-toggle> ></mat-slide-toggle>
</div> </div>
</div> </div>
<div class="d-flex my-3">
<div class="w-50" i18n> Disable User Signup </div>
<div class="w-50">
<mat-slide-toggle
color="primary"
[disabled]="!hasPermissionToToggleUserSignupMode"
[checked]="!info.globalPermissions.includes('createUserAccount')"
(change)="onEnableUserSignupModeChange($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
libs/common/src/lib/config.ts

@ -77,6 +77,7 @@ export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE';
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';
export const PROPERTY_DISABLE_USER_SIGNUP = 'PROPERTY_DISABLE_USER_SIGNUP';
export const QUEUE_JOB_STATUS_LIST = <JobStatus[]>[ export const QUEUE_JOB_STATUS_LIST = <JobStatus[]>[
'active', 'active',

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

@ -26,7 +26,8 @@ export const permissions = {
updateAuthDevice: 'updateAuthDevice', updateAuthDevice: 'updateAuthDevice',
updateOrder: 'updateOrder', updateOrder: 'updateOrder',
updateUserSettings: 'updateUserSettings', updateUserSettings: 'updateUserSettings',
updateViewMode: 'updateViewMode' updateViewMode: 'updateViewMode',
toggleUserSignupMode: 'toggleUserSignupMode'
}; };
export function getPermissions(aRole: Role): string[] { export function getPermissions(aRole: Role): string[] {

Loading…
Cancel
Save