From 4975240eec0b9dca7bb1852b61d8ebcdecbaf732 Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Thu, 9 Jan 2020 19:33:56 +0100
Subject: [PATCH] [enh] add `search [pattern]` command

---
 app/modules/dump.ts | 114 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 111 insertions(+), 3 deletions(-)

diff --git a/app/modules/dump.ts b/app/modules/dump.ts
index 95148fd22..7e15e7d5c 100644
--- a/app/modules/dump.ts
+++ b/app/modules/dump.ts
@@ -11,11 +11,12 @@
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU Affero General Public License for more details.
 
+import {exec} from "child_process"
 import {ConfDTO} from "../lib/dto/ConfDTO"
 import {Server} from "../../server"
 import {moment} from "../lib/common-libs/moment"
 import {DBBlock} from "../lib/db/DBBlock"
-import {SindexEntry} from "../lib/indexer"
+import {FullIindexEntry, SindexEntry} from "../lib/indexer"
 import {BlockDTO} from "../lib/dto/BlockDTO"
 import {Underscore} from "../lib/common-libs/underscore"
 import {dumpWotWizard} from "./dump/wotwizard/wotwizard.dump"
@@ -23,6 +24,11 @@ import {OtherConstants} from "../lib/other_constants"
 import {Querable, querablep} from "../lib/common-libs/querable"
 import {dumpBlocks, dumpForks} from "./dump/blocks/dump.blocks"
 import {newResolveTimeoutPromise} from "../lib/common-libs/timeout-promise"
+import {readFileSync} from "fs"
+import {IdentityDTO} from "../lib/dto/IdentityDTO"
+import {CertificationDTO, ShortCertificationDTO} from "../lib/dto/CertificationDTO"
+import {MembershipDTO} from "../lib/dto/MembershipDTO"
+import {RevocationDTO, ShortRevocation} from "../lib/dto/RevocationDTO"
 
 const Table = require('cli-table')
 
@@ -111,6 +117,57 @@ module.exports = {
         // Save DB
         await server.disconnect();
       }
+    }, {
+      name: 'search [pattern]',
+      desc: 'Dumps data of the blockchain matching given pattern.',
+      logs: false,
+      preventIfRunning: true,
+
+      onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => {
+        const pattern: string = params[0] || ''
+
+        try {
+
+          const files: string[] = await new Promise((res, rej) => exec(`grep -r ${pattern} ${server.home}/${server.conf.currency} -l`, (err, stdout) => {
+            if (err) return rej(err)
+            console.log(stdout)
+            res(stdout.split('\n').filter(l => l))
+          }))
+
+          const blocks = Underscore.sortBy(await findBlocksMatching(pattern, files), b => b.number)
+
+          const events: { b: BlockDTO, event: (IdentityDTO|ShortCertificationDTO|MembershipDTO|ShortRevocation) }[] = []
+          for (const b of blocks) {
+            b.identities.filter(i => i.includes(pattern)).forEach(i => {
+              events.push({ b, event: IdentityDTO.fromInline(i) })
+            })
+            b.certifications.filter(c => c.includes(pattern)).forEach(c => {
+              events.push({ b, event: CertificationDTO.fromInline(c) })
+            })
+            b.joiners.concat(b.actives).concat(b.leavers).filter(m => m.includes(pattern)).forEach(m => {
+              events.push({ b, event: MembershipDTO.fromInline(m) })
+            })
+            b.revoked.filter(m => m.includes(pattern)).forEach(r => {
+              events.push({ b, event: RevocationDTO.fromInline(r) })
+            })
+          }
+
+          for (const e of events) {
+            if ((e.event as IdentityDTO).uid) {
+              const date = await getDateForBlock(e.b)
+              const idty = e.event as IdentityDTO
+              console.log('%s: new identity %s (created on %s)', date, idty.uid, await getDateFor(server, idty.buid as string))
+            }
+          }
+
+          console.log(events.map(e => e.event))
+
+        } catch (e) {
+          console.error(e)
+        }
+        // Save DB
+        await server.disconnect();
+      }
     }, {
       name: 'dump-ww',
       desc: 'Dumps WotWizard export.',
@@ -121,6 +178,21 @@ module.exports = {
   }
 }
 
+async function findBlocksMatching(pattern: string, files: string[]) {
+  const matchingBlocks: BlockDTO[] = []
+  for (const f of files) {
+    const blocks: any[] = JSON.parse(await readFileSync(f, 'utf8')).blocks
+    for (const jsonBlock of blocks) {
+      const b = BlockDTO.fromJSONObject(jsonBlock)
+      const raw = b.getRawSigned()
+      if (raw.includes(pattern)) {
+        matchingBlocks.push(b)
+      }
+    }
+  }
+  return matchingBlocks
+}
+
 async function dumpCurrent(server: Server) {
   const current = await server.dal.getCurrentBlockOrNull()
   if (!current) {
@@ -229,8 +301,9 @@ function dump(rows: any[], columns: string[]) {
 }
 
 async function dumpHistory(server: Server, pub: string) {
-  const irows = await server.dal.iindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])
-  const mrows = await server.dal.mindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])
+  const irows = (await server.dal.iindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])).filter(r => pub ? r.pub === pub : true)
+  const mrows = (await server.dal.mindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])).filter(r => pub ? r.pub === pub : true)
+  const crows = (await server.dal.cindexDAL.findRawWithOrder({ pub }, [['writtenOn', false]])).filter(r => pub ? r.issuer === pub || r.receiver === pub: true)
   console.log('----- IDENTITY -----')
   for (const e of irows) {
     const date = await getDateFor(server, e.written_on)
@@ -259,6 +332,28 @@ async function dumpHistory(server: Server, pub: string) {
       console.log('Non displayable MINDEX entry')
     }
   }
+  console.log('----- CERTIFICATION -----')
+  crows.forEach(crow => {
+    console.log(JSON.stringify(crow))
+  })
+  for (const e of crows) {
+    const dateW = await getDateFor(server, e.written_on)
+    const dateC = await getDateForBlockNumber(server, e.created_on)
+    if (e.receiver === pub) {
+      const issuer = await server.dal.getWrittenIdtyByPubkey(e.issuer) as FullIindexEntry
+      if (e.op === 'UPDATE') {
+        console.log('%s : %s: from %s (update)', dateC, dateW, issuer.uid)
+      }
+      else {
+        console.log('%s : %s: from %s', dateC, dateW, issuer.uid)
+      }
+    // } else if (e.issuer === pub) {
+    //   const receiver = await server.dal.getWrittenIdtyByPubkey(e.receiver) as FullIindexEntry
+    //   console.log('%s: to ', date, receiver.uid)
+    } else {
+      // console.log('Non displayable CINDEX entry')
+    }
+  }
 }
 
 async function dumpWot(server: Server) {
@@ -274,6 +369,19 @@ async function getDateFor(server: Server, blockstamp: string) {
   return formatTimestamp(b.medianTime) + ' (#' + bnumberPadded + ')'
 }
 
+async function getDateForBlockNumber(server: Server, number: number) {
+  const b = (await server.dal.getBlock(number)) as DBBlock
+  const s = "         " + b.number
+  const bnumberPadded = s.substr(s.length - 6)
+  return formatTimestamp(b.medianTime) + ' (#' + bnumberPadded + ')'
+}
+
+async function getDateForBlock(b: BlockDTO) {
+  const s = "         " + b.number
+  const bnumberPadded = s.substr(s.length - 6)
+  return formatTimestamp(b.medianTime) + ' (#' + bnumberPadded + ')'
+}
+
 function formatTimestamp(ts: number) {
   return moment(ts * 1000).format('YYYY-MM-DD hh:mm:ss')
 }
-- 
GitLab