Skip to content

Commit

Permalink
feat: ability to enable/disable the bank connect feature (#423)
Browse files Browse the repository at this point in the history
  • Loading branch information
abouolia authored Apr 24, 2024
1 parent 1372a1f commit 7abfa6a
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 43 deletions.
10 changes: 10 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ services:
- GOTENBERG_URL=${GOTENBERG_URL}
- GOTENBERG_DOCS_URL=${GOTENBERG_DOCS_URL}

# Bank Sync
- BANKING_CONNECT=${BANKING_CONNECT}

# Plaid
- PLAID_ENV=${PLAID_ENV}
- PLAID_CLIENT_ID=${PLAID_CLIENT_ID}
- PLAID_SECRET_DEVELOPMENT=${PLAID_SECRET_DEVELOPMENT}
- PLAID_SECRET_SANDBOX=${b8cf42b441e110451e2f69ad7e1e9f}
- PLAID_LINK_WEBHOOK=${PLAID_LINK_WEBHOOK}

# Lemon Squeez
- LEMONSQUEEZY_API_KEY=${LEMONSQUEEZY_API_KEY}
- LEMONSQUEEZY_STORE_ID=${LEMONSQUEEZY_STORE_ID}
Expand Down
6 changes: 3 additions & 3 deletions packages/server/src/api/controllers/Dashboard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export default class DashboardMetaController {
dashboardService: DashboardService;

/**
*
* Constructor router.
* @returns
*/
router() {
public router() {
const router = Router();

router.get('/boot', this.getDashboardBoot);
Expand All @@ -25,7 +25,7 @@ export default class DashboardMetaController {
* @param {Response} res -
* @param {NextFunction} next -
*/
getDashboardBoot = async (
private getDashboardBoot = async (
req: Request,
res: Response,
next: NextFunction
Expand Down
8 changes: 8 additions & 0 deletions packages/server/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ module.exports = {
},
},

/**
* Bank Synchronization.
*/
bankSync: {
enabled: parseBoolean(defaultTo(process.env.BANKING_CONNECT, false), false),
provider: 'plaid',
},

/**
* Plaid.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/server/src/interfaces/Features.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export enum Features {
WAREHOUSES = 'warehouses',
BRANCHES = 'branches',
BankSyncing = 'BankSyncing'
}

export interface IFeatureAllItem {
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/lib/Metable/MetableStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ export default class MetableStore implements IMetableStore {
* @param {String} key -
* @param {Mixied} defaultValue -
*/
get(query: string | IMetaQuery, defaultValue: any): any | false {
get(query: string | IMetaQuery, defaultValue: any): any | null {
const metadata = this.find(query);
return metadata
? metadata.value
: typeof defaultValue !== 'undefined'
? defaultValue
: false;
: null;
}

/**
Expand Down
32 changes: 3 additions & 29 deletions packages/server/src/services/Features/FeaturesManager.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import { defaultTo } from 'lodash';
import { Inject, Service } from 'typedi';
import { omit } from 'lodash';
import { FeaturesSettingsDriver } from './FeaturesSettingsDriver';
import { FeaturesConfigureManager } from './FeaturesConfigureManager';
import { IFeatureAllItem } from '@/interfaces';

@Service()
export class FeaturesManager {
@Inject()
private drive: FeaturesSettingsDriver;

@Inject()
private configure: FeaturesConfigureManager;

/**
* Turns-on the given feature name.
* @param {number} tenantId
Expand Down Expand Up @@ -40,35 +34,15 @@ export class FeaturesManager {
* @returns {Promise<void>}
*/
public async accessible(tenantId: number, feature: string) {
// Retrieves the feature default accessible value.
const defaultValue = this.configure.getFeatureConfigure(
feature,
'defaultValue'
);
const isAccessible = await this.drive.accessible(tenantId, feature);

return defaultTo(isAccessible, defaultValue);
return this.drive.accessible(tenantId, feature);
}

/**
* Retrieves the all features and their accessible value and default value.
* @param {number} tenantId
* @returns
* @returns {Promise<IFeatureAllItem[]>}
*/
public async all(tenantId: number): Promise<IFeatureAllItem[]> {
const all = await this.drive.all(tenantId);

return all.map((feature: IFeatureAllItem) => {
const defaultAccessible = this.configure.getFeatureConfigure(
feature.name,
'defaultValue'
);
const isAccessible = feature.isAccessible;

return {
...feature,
isAccessible: defaultTo(isAccessible, defaultAccessible),
};
});
return this.drive.all(tenantId);
}
}
16 changes: 14 additions & 2 deletions packages/server/src/services/Features/FeaturesSettingsDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import { Service, Inject } from 'typedi';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { FeaturesConfigure } from './constants';
import { IFeatureAllItem } from '@/interfaces';
import { FeaturesConfigureManager } from './FeaturesConfigureManager';

@Service()
export class FeaturesSettingsDriver {
@Inject()
tenancy: HasTenancyService;
private tenancy: HasTenancyService;

@Inject()
private configure: FeaturesConfigureManager;

/**
* Turns-on the given feature name.
Expand Down Expand Up @@ -41,7 +45,15 @@ export class FeaturesSettingsDriver {
async accessible(tenantId: number, feature: string) {
const settings = this.tenancy.settings(tenantId);

return !!settings.get({ group: 'features', key: feature });
const defaultValue = this.configure.getFeatureConfigure(
feature,
'defaultValue'
);
const settingValue = settings.get(
{ group: 'features', key: feature },
defaultValue
);
return settingValue;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions packages/server/src/services/Features/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Features, IFeatureConfiugration } from '@/interfaces';
import config from '@/config';
import { defaultTo } from 'lodash';

export const FeaturesConfigure: IFeatureConfiugration[] = [
{
Expand All @@ -9,4 +11,8 @@ export const FeaturesConfigure: IFeatureConfiugration[] = [
name: Features.WAREHOUSES,
defaultValue: false,
},
{
name: Features.BankSyncing,
defaultValue: defaultTo(config.bankSync.enabled, false),
}
];
3 changes: 2 additions & 1 deletion packages/webapp/src/constants/features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export const Features = {
Warehouses: 'warehouses',
Branches: 'branches',
ManualJournal: 'manualJournal',
Projects:'Projects'
Projects:'Projects',
BankSyncing: 'BankSyncing',
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Can,
Icon,
FormattedMessage as T,
FeatureCan,
} from '@/components';
import { useRefreshCashflowAccounts } from '@/hooks/query';
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
Expand All @@ -21,7 +22,7 @@ import withCashflowAccountsTableActions from '../AccountTransactions/withCashflo

import { AccountDialogAction } from '@/containers/Dialogs/AccountDialog/utils';

import { ACCOUNT_TYPE } from '@/constants';
import { ACCOUNT_TYPE, Features } from '@/constants';
import { DialogsName } from '@/constants/dialogs';

import { compose } from '@/utils';
Expand Down Expand Up @@ -110,12 +111,14 @@ function CashFlowAccountsActionsBar({
</NavbarGroup>

<NavbarGroup align={Alignment.RIGHT}>
<Button
className={Classes.MINIMAL}
text={'Connect to Bank / Credit Card'}
onClick={handleConnectToBank}
/>
<FeatureCan feature={Features.BankSyncing}>
<Button
className={Classes.MINIMAL}
text={'Connect to Bank / Credit Card'}
onClick={handleConnectToBank}
/>
<NavbarDivider />
</FeatureCan>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="refresh-16" iconSize={14} />}
Expand Down

0 comments on commit 7abfa6a

Please sign in to comment.