hard delete tiems in the database

This commit is contained in:
Simon Larsen 2023-06-08 17:14:05 +01:00
parent b0f4083297
commit d7c8edd598
No known key found for this signature in database
GPG Key ID: AB45983AA9C81CDE
9 changed files with 148 additions and 69 deletions

View File

@ -79,6 +79,26 @@ class DatabaseService<TBaseModel extends BaseModel> {
private model!: TBaseModel;
private modelName!: string;
private _hardDeleteItemByColumnName : string = '';
public get hardDeleteItemByColumnName() : string {
return this._hardDeleteItemByColumnName;
}
public set hardDeleteItemByColumnName(v : string) {
this._hardDeleteItemByColumnName = v;
}
private _hardDeleteItemsOlderThanDays : number = 0;
public get hardDeleteItemsOlderThanDays() : number {
return this._hardDeleteItemsOlderThanDays;
}
public set hardDeleteItemsOlderThanDays(v : number) {
this._hardDeleteItemsOlderThanDays = v;
}
public constructor(
modelType: { new (): TBaseModel },
postgresDatabase?: PostgresDatabase
@ -92,6 +112,11 @@ class DatabaseService<TBaseModel extends BaseModel> {
}
}
public hardDeleteItemsOlderThanInDays(columnName: string, olderThan: number) {
this.hardDeleteItemByColumnName = columnName;
this.hardDeleteItemsOlderThanDays = olderThan;
}
public getModel(): TBaseModel {
return this.model;
}

View File

@ -68,6 +68,9 @@ import WorkflowService from './WorkflowService';
import WorkflowVariablesService from './WorkflowVariableService';
import WorkflowLogService from './WorkflowLogService';
// SMS Log Servce
import SmsLogService from './SmsLogService';
export default [
UserService,
ProbeService,
@ -118,4 +121,6 @@ export default [
WorkflowService,
WorkflowVariablesService,
WorkflowLogService,
SmsLogService
];

View File

@ -5,6 +5,7 @@ import DatabaseService from './DatabaseService';
export class Service extends DatabaseService<Model> {
public constructor(postgresDatabase?: PostgresDatabase) {
super(Model, postgresDatabase);
this.hardDeleteItemsOlderThanInDays("createdAt", 30);
}
}

View File

@ -74,7 +74,7 @@ const Detail: Function = (props: ComponentProps): ReactElement => {
};
const getUSDCentsField: Function = (usdCents: number): ReactElement => {
return <div>{usdCents / 100} USD</div>;
return <div className='text-gray-900'>{usdCents / 100} USD</div>;
};
const getField: Function = (field: Field, index: number): ReactElement => {

View File

@ -11,6 +11,7 @@ import PageComponentProps from '../PageComponentProps';
import DashboardSideMenu from './SideMenu';
import FieldType from 'CommonUI/src/Components/Types/FieldType';
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
import { BILLING_ENABLED } from 'CommonUI/src/Config';
const Settings: FunctionComponent<PageComponentProps> = (
_props: PageComponentProps
@ -41,7 +42,7 @@ const Settings: FunctionComponent<PageComponentProps> = (
sideMenu={<DashboardSideMenu />}
>
{/* API Key View */}
<CardModelDetail
{BILLING_ENABLED ? <CardModelDetail
name="Current Balance"
cardProps={{
title: 'Current Balance',
@ -56,9 +57,9 @@ const Settings: FunctionComponent<PageComponentProps> = (
fields: [
{
field: {
smsOrCallCurrentBalanceInUSD: true,
smsOrCallCurrentBalanceInUSDCents: true,
},
fieldType: FieldType.Number,
fieldType: FieldType.USDCents,
title: 'SMS or Call Current Balance',
description:
'This is your current balance for SMS or Call. It is in USD. ',
@ -67,7 +68,7 @@ const Settings: FunctionComponent<PageComponentProps> = (
],
modelId: DashboardNavigation.getProjectId()?.toString(),
}}
/>
/> : <></>}
<CardModelDetail
name="Enable Notifications"
@ -130,7 +131,7 @@ const Settings: FunctionComponent<PageComponentProps> = (
}}
/>
<CardModelDetail
{BILLING_ENABLED ? <CardModelDetail
name="Auto Recharge"
cardProps={{
title: 'Auto Recharge',
@ -291,7 +292,7 @@ const Settings: FunctionComponent<PageComponentProps> = (
],
modelId: DashboardNavigation.getProjectId()?.toString(),
}}
/>
/> : <></>}
</Page>
);
};

View File

@ -155,12 +155,12 @@ const DashboardSideMenu: FunctionComponent = (): ReactElement => {
/>
<SideMenuItem
link={{
title: 'Call and SMS',
title: 'Notification Settings',
to: RouteUtil.populateRouteParams(
RouteMap[PageMap.SETTINGS_CALL_SMS] as Route
),
}}
icon={IconProp.Call}
icon={IconProp.Settings}
/>
<SideMenuItem
link={{

View File

@ -16,6 +16,9 @@ import Page from 'CommonUI/src/Components/Page/Page';
import Pill from 'CommonUI/src/Components/Pill/Pill';
import SmsStatus from 'Common/Types/SmsStatus';
import { Green, Red } from 'Common/Types/BrandColors';
import { BILLING_ENABLED } from 'CommonUI/src/Config';
import Column from 'CommonUI/src/Components/ModelTable/Column';
import Columns from 'CommonUI/src/Components/ModelTable/Columns';
const SMSLogs: FunctionComponent<PageComponentProps> = (
_props: PageComponentProps
@ -26,6 +29,70 @@ const SMSLogs: FunctionComponent<PageComponentProps> = (
const [smsModelTitle, setSmsModalTitle] = useState<string>('');
const [smsModelDescription, setSmsModalDescription] = useState<string>('');
const modelTableColumns: Columns<SmsLog> = [{
field: {
_id: true,
},
title: 'Log ID',
type: FieldType.Text,
isFilterable: true,
},
{
field: {
toNumber: true,
},
isFilterable: true,
title: 'To Number',
type: FieldType.Phone,
},
{
field: {
createdAt: true,
},
title: 'Sent at',
type: FieldType.DateTime,
isFilterable: true,
},
{
field: {
status: true,
},
title: 'Status',
type: FieldType.Text,
getElement: (item: JSONObject): ReactElement => {
if (item['status']) {
return (
<Pill
isMinimal={false}
color={
item['status'] ===
SmsStatus.Success
? Green
: Red
}
text={item['status'] as string}
/>
);
}
return <></>;
},
isFilterable: true,
}];
if(BILLING_ENABLED){
modelTableColumns.push({
field: {
smsCostInUSDCents: true,
},
title: 'SMS Cost',
type: FieldType.USDCents,
} as Column<SmsLog>);
}
return (
<Page
title={'Project Settings'}
@ -117,66 +184,7 @@ const SMSLogs: FunctionComponent<PageComponentProps> = (
}
showRefreshButton={true}
showFilterButton={true}
columns={[
{
field: {
_id: true,
},
title: 'Log ID',
type: FieldType.Text,
isFilterable: true,
},
{
field: {
toNumber: true,
},
isFilterable: true,
title: 'To Number',
type: FieldType.Phone,
},
{
field: {
createdAt: true,
},
title: 'Sent at',
type: FieldType.DateTime,
isFilterable: true,
},
{
field: {
smsCostInUSDCents: true,
},
title: 'SMS Cost',
type: FieldType.USDCents,
},
{
field: {
status: true,
},
title: 'Status',
type: FieldType.Text,
getElement: (item: JSONObject): ReactElement => {
if (item['status']) {
return (
<Pill
isMinimal={false}
color={
item['status'] ===
SmsStatus.Success
? Green
: Red
}
text={item['status'] as string}
/>
);
}
return <></>;
},
isFilterable: true,
},
]}
columns={modelTableColumns}
/>
{showViewSmsTextModal && (

View File

@ -155,6 +155,7 @@ export default class SmsService {
});
}
} catch (e: any) {
smsLog.smsCostInUSDCents = 0;
smsLog.status = SmsStatus.Error;
smsLog.statusMessage =
e && e.message ? e.message.toString() : e.toString();

View File

@ -35,3 +35,41 @@ RunCron(
}
}
);
RunCron(
'HardDelete:HardDeleteOlderItemsInDatabase',
{ schedule: IsDevelopment ? EVERY_MINUTE : EVERY_DAY, runOnStartup: false },
async () => {
for (const service of Services) {
if (service instanceof DatabaseService) {
if(!service.hardDeleteItemByColumnName || !service.hardDeleteItemsOlderThanDays) {
continue;
}
try {
// Retain data for 30 days for accidental deletion, and then hard delete.
await service.hardDeleteBy({
query: {
[service.hardDeleteItemByColumnName]: QueryHelper.lessThan(
OneUptimeDate.getSomeDaysAgo(service.hardDeleteItemsOlderThanDays)
),
},
props: {
isRoot: true,
},
limit: LIMIT_MAX,
skip: 0,
});
} catch (err) {
logger.error(err);
}
}
}
}
);