-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add sourceAccountNormalizer service
This service will normalize the cozyMetadata.sourceAccountIdentifier attribute in io.cozy.identities,io.cozy.bills,io.cozy.accounts doctypes. This attribute is needed for debugging purpose for identities and bills and having this directly specified in accounts without needing any algorithm is easier to use. This service must be run manually at the moment since we don't want tu run it multiple times for every konnector which updates all these doctypes at one and I did not find a way to specify a unique @event trigger for multiple doctypes.
- Loading branch information
1 parent
294e8f3
commit 10e2a51
Showing
3 changed files
with
496 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
185 changes: 185 additions & 0 deletions
185
src/targets/services/sourceAccountIdentifierNormalizer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/* | ||
* This service updates identity, bills and accounts with proper sourceAccountIdentifier in | ||
* cozyMetadata.sourceAccountIdentifier when possible | ||
* | ||
*/ | ||
import CozyClient, { Q, models } from 'cozy-client' | ||
import logger from 'cozy-logger' | ||
import polyfillFetch from './polyfillFetch' | ||
|
||
const log = logger.namespace('sourceAccountIdentifierNormalizer') | ||
|
||
polyfillFetch() | ||
|
||
const main = async () => { | ||
const client = CozyClient.fromEnv() | ||
|
||
await Promise.all([ | ||
normalizeIdentities(client), | ||
normalizeBills(client), | ||
normalizeAccounts(client) | ||
]) | ||
} | ||
;(async () => { | ||
try { | ||
await main() | ||
} catch (error) { | ||
log('critical', error.message) | ||
} | ||
})() | ||
|
||
async function createBillsFilesMap({ client, bills }) { | ||
const billsInvoicesIds = bills.map(bill => { | ||
return bill.invoice?.split(':').pop() | ||
}) | ||
const files = await client.queryAll( | ||
Q('io.cozy.files').getByIds(billsInvoicesIds) | ||
) | ||
return files.reduce((map, file) => { | ||
map.set(file._id, file) | ||
return map | ||
}, new Map()) | ||
} | ||
|
||
async function createBillsAndFilesAccountsMap({ | ||
client, | ||
bills, | ||
billsFilesMap | ||
}) { | ||
const billsAndFilesAccountIds = [ | ||
...bills.map(bill => bill?.cozyMetadata?.sourceAccount).filter(Boolean), | ||
...Array.from(billsFilesMap.values()) | ||
.map(file => file?.cozyMetadata?.sourceAccount) | ||
.filter(Boolean) | ||
] | ||
const billsAndFilesAccounts = await client.queryAll( | ||
Q('io.cozy.accounts').getByIds(billsAndFilesAccountIds) | ||
) | ||
return billsAndFilesAccounts.reduce((map, account) => { | ||
map.set(account._id, account) | ||
return map | ||
}, new Map()) | ||
} | ||
|
||
export async function normalizeIdentities(client) { | ||
const identities = await client.queryAll( | ||
Q('io.cozy.identities').partialIndex({ | ||
'cozyMetadata.sourceAccountIdentifier': { $exists: false }, | ||
identifier: { $exists: true } | ||
}) | ||
) | ||
|
||
const normalizedIdentities = identities | ||
.map(identity => ({ | ||
...identity, | ||
cozyMetadata: { | ||
...identity.cozyMetadata, | ||
sourceAccountIdentifier: identity.identifier | ||
} | ||
})) | ||
.filter(Boolean) | ||
|
||
if (normalizedIdentities.length > 0) { | ||
await client.saveAll(normalizedIdentities) | ||
} | ||
log('info', `Normalized ${normalizedIdentities.length}/${identities.length}`) | ||
} | ||
|
||
export async function normalizeBills(client) { | ||
const bills = await client.queryAll( | ||
Q('io.cozy.bills').partialIndex({ | ||
'cozyMetadata.sourceAccountIdentifier': { $exists: false } | ||
}) | ||
) | ||
|
||
const billsFilesMap = await createBillsFilesMap({ client, bills }) | ||
const billsAndFilesAccountsMap = await createBillsAndFilesAccountsMap({ | ||
client, | ||
bills, | ||
billsFilesMap | ||
}) | ||
|
||
const normalizedBills = bills | ||
.map(bill => { | ||
let sourceAccountIdentifier = null | ||
if (bill.sourceAccountIdentifier) { | ||
sourceAccountIdentifier = bill.sourceAccountIdentifier | ||
} else if (bill.cozyMetadata?.sourceAccount) { | ||
const account = billsAndFilesAccountsMap.get( | ||
bill.cozyMetadata.sourceAccount | ||
) | ||
if (account) { | ||
if (account.cozyMetadata?.sourceAccountIdentifier) { | ||
sourceAccountIdentifier = | ||
account.cozyMetadata.sourceAccountIdentifier | ||
} else { | ||
const accountName = models.account.getAccountName(account) | ||
sourceAccountIdentifier = | ||
accountName !== account._id ? accountName : null | ||
} | ||
} | ||
} else if (!sourceAccountIdentifier && bill.invoice) { | ||
const fileId = bill.invoice?.split(':').pop() | ||
const file = billsFilesMap.get(fileId) | ||
if (file?.cozyMetadata?.sourceAccountIdentifier) { | ||
sourceAccountIdentifier = file.cozyMetadata.sourceAccountIdentifier | ||
} else if (file.cozyMetadata?.sourceAccount) { | ||
const account = billsAndFilesAccountsMap.get( | ||
file.cozyMetadata.sourceAccount | ||
) | ||
if (account) { | ||
if (account.cozyMetadata?.sourceAccountIdentifier) { | ||
sourceAccountIdentifier = | ||
account.cozyMetadata.sourceAccountIdentifier | ||
} else { | ||
const accountName = models.account.getAccountName(account) | ||
sourceAccountIdentifier = | ||
accountName !== account._id ? accountName : null | ||
} | ||
} | ||
} | ||
} | ||
if (!sourceAccountIdentifier) { | ||
return false | ||
} | ||
return { | ||
...bill, | ||
cozyMetadata: { ...bill.cozyMetadata, sourceAccountIdentifier } | ||
} | ||
}) | ||
.filter(Boolean) | ||
|
||
log('info', `Normalized ${normalizedBills.length}/${bills.length}`) | ||
if (normalizedBills.length > 0) { | ||
await client.saveAll(normalizedBills) | ||
} | ||
} | ||
|
||
export async function normalizeAccounts(client) { | ||
const accounts = await client.queryAll( | ||
Q('io.cozy.accounts').partialIndex({ | ||
'cozyMetadata.sourceAccountIdentifier': { $exists: false } | ||
}) | ||
) | ||
|
||
const normalizedAccounts = accounts | ||
.map(account => { | ||
const accountName = models.account.getAccountName(account) | ||
const sourceAccountIdentifier = | ||
accountName !== account._id ? accountName : null | ||
if (!sourceAccountIdentifier) { | ||
return false | ||
} | ||
|
||
return { | ||
...account, | ||
cozyMetadata: { ...account.cozyMetadata, sourceAccountIdentifier } | ||
} | ||
}) | ||
.filter(Boolean) | ||
|
||
log('info', `Normalized ${normalizedAccounts.length}/${accounts.length}`) | ||
if (normalizedAccounts.length > 0) { | ||
await client.saveAll(normalizedAccounts) | ||
} | ||
} |
Oops, something went wrong.