From 539955720a0da745a2da5a1233cb1f53e1f146bd Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Tue, 21 May 2019 18:29:20 +0200 Subject: [PATCH] [enh] Data > History of member view --- back/webmin/graphql/resolvers/BigResolver.ts | 7 ++ .../graphql/types/HistoryOfMemberType.ts | 9 +++ back/webmin/queries/gql-data.ts | 70 +++++++++++++++++++ src/lib/services/webmin.service.ts | 19 +++++ src/views/Home.vue | 4 +- src/views/home/Data.vue | 47 +++++++++++++ src/views/home/data/HistoryOfMember.vue | 43 ++++++++++++ src/vue-modules/register-router.ts | 17 ++++- 8 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 back/webmin/graphql/types/HistoryOfMemberType.ts create mode 100644 back/webmin/queries/gql-data.ts create mode 100644 src/views/home/Data.vue create mode 100644 src/views/home/data/HistoryOfMember.vue diff --git a/back/webmin/graphql/resolvers/BigResolver.ts b/back/webmin/graphql/resolvers/BigResolver.ts index 1ccc04b..8ae3685 100644 --- a/back/webmin/graphql/resolvers/BigResolver.ts +++ b/back/webmin/graphql/resolvers/BigResolver.ts @@ -14,6 +14,8 @@ import {getConf, testAndSaveConf} from '../../queries/gql-conf' import {Arg} from 'type-graphql/dist/decorators/Arg' import {getForks, getMainChain} from '../../queries/gql-forks' import {ChainType} from '../types/ChainType' +import {HistoryOfMemberType} from '../types/HistoryOfMemberType' +import {getHistoryOfMember} from '../../queries/gql-data' @Resolver() export class BigResolver { @@ -83,6 +85,11 @@ export class BigResolver { return getMainChain(ApplicationContext.server, start, end) } + @Query(type => HistoryOfMemberType) + historyOfMember(@Arg("pub", type => String) pub: string): Promise<HistoryOfMemberType> { + return getHistoryOfMember(ApplicationContext.server, pub) + } + @Query(type => ChainType) getForks(@Arg("start", type => Int) start: number, @Arg("end", type => Int) end: number): Promise<ChainType> { return getForks(ApplicationContext.server, start, end) diff --git a/back/webmin/graphql/types/HistoryOfMemberType.ts b/back/webmin/graphql/types/HistoryOfMemberType.ts new file mode 100644 index 0000000..5c6a14d --- /dev/null +++ b/back/webmin/graphql/types/HistoryOfMemberType.ts @@ -0,0 +1,9 @@ +import {Field, Int, ObjectType} from 'type-graphql' +import {BlockTransactionType} from './BlockTransactionType' +import {BlockType} from './BlockType' + +@ObjectType() +export class HistoryOfMemberType { + + @Field(type => [String]) stories: string[] +} diff --git a/back/webmin/queries/gql-data.ts b/back/webmin/queries/gql-data.ts new file mode 100644 index 0000000..7b5c3eb --- /dev/null +++ b/back/webmin/queries/gql-data.ts @@ -0,0 +1,70 @@ +import {Server} from 'duniter/server' +import {HistoryOfMemberType} from '../graphql/types/HistoryOfMemberType' +import {CertificationDTO} from 'duniter/app/lib/dto/CertificationDTO' +import {DBBlock} from 'duniter/app/lib/db/DBBlock' + +export async function getHistoryOfMember(server: Server, pub: string): Promise<HistoryOfMemberType> { + const stories = [] + const start = Date.now() + const pubRegexp = new RegExp(pub) + const blocks = await Promise.all((await server.dal.blockDAL.findWithIdentities()) + .concat(await server.dal.blockDAL.findWithCertifications()) + .concat(await server.dal.blockDAL.findWithJoiners()) + .concat(await server.dal.blockDAL.findWithActives()) + .concat(await server.dal.blockDAL.findWithLeavers()) + .concat(await server.dal.blockDAL.findWithExcluded()) + .concat(await server.dal.blockDAL.findWithRevoked()) + .map(async bNumber => (await server.dal.blockDAL.getBlock(bNumber)) as DBBlock)) + + blocks.forEach(b => { + + const fNumber = String(b.number).padStart(6, '0') + + b.identities + .filter(i => i.match(pubRegexp)) + .forEach(i => stories.push(`b#${fNumber}: IDENTITY`)) + + const certifies = b.certifications + .map(CertificationDTO.fromInline) + .filter(c => c.from === pub) + + if (certifies.length) { + stories.push(`b#${fNumber}: CERTIFIES ${certifies.length} member(s)`) + } + + const certified = b.certifications + .map(CertificationDTO.fromInline) + .filter(c => c.to === pub) + + if (certified.length) { + stories.push(`b#${fNumber}: CERTIFIED BY ${certified.length} member(s)`) + } + + b.joiners + .filter(i => i.match(pubRegexp)) + .forEach(i => stories.push( + `b#${fNumber}: JOIN`) + ) + + b.actives + .filter(i => i.match(pubRegexp)) + .forEach(i => stories.push( + `b#${fNumber}: RENEW`) + ) + + b.leavers + .filter(i => i.match(pubRegexp)) + .forEach(i => stories.push( + `b#${fNumber}: LEAVE`) + ) + + b.revoked + .filter(i => i.match(pubRegexp)) + .forEach(i => stories.push( + `b#${fNumber}: REVOKED`) + ) + + }) + stories.push(`scanned all the blocs in ${Date.now() - start}ms`) + return { stories } +} \ No newline at end of file diff --git a/src/lib/services/webmin.service.ts b/src/lib/services/webmin.service.ts index 149fb98..66f301f 100644 --- a/src/lib/services/webmin.service.ts +++ b/src/lib/services/webmin.service.ts @@ -1,6 +1,7 @@ import gql from 'graphql-tag' import ApolloClient from 'apollo-client'; import {DBBlock, NodeState, WS2PConnectionInfos, WS2PHead} from '../../../common/types' +import {HistoryOfMemberType} from '../../../back/webmin/graphql/types/HistoryOfMemberType' import {ChainType} from '../../../back/webmin/graphql/types/ChainType' export class WebminService { @@ -350,6 +351,24 @@ export class WebminService { return res.data.getMainChain } + async historyOfMember(pub: string) { + const res = await this.getApollo() + .watchQuery<{ historyOfMember: HistoryOfMemberType }>({ + query: gql` + query ($pub: String!){ + historyOfMember(pub: $pub) { + stories + } + } + `, + variables: { + pub + }, + }) + .result() + return res.data.historyOfMember + } + async getForks(start: number, end: number): Promise<ChainType> { const res = await this.getApollo() .watchQuery<{ getForks: ChainType }>({ diff --git a/src/views/Home.vue b/src/views/Home.vue index 571ed50..5b96ad1 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -22,8 +22,8 @@ <b-navbar-nav class="mr-auto"> <b-nav-item> - <router-link to="home/forkview"> - <button class="btn"><font-awesome-icon icon="cube"/></button> + <router-link to="/home/data"> + <button class="btn"><font-awesome-icon icon="search"/></button> </router-link> </b-nav-item> </b-navbar-nav> diff --git a/src/views/home/Data.vue b/src/views/home/Data.vue new file mode 100644 index 0000000..b0ec967 --- /dev/null +++ b/src/views/home/Data.vue @@ -0,0 +1,47 @@ +<style lang="css" scoped> +</style> + +<template> + + <div class="container-fluid m-0 p-0"> + + <div class="row mt-2"> + <div class="col-2"> + <div class="nav flex-column nav-pills"> + + <router-link :to="menu.route" v-for="menu in menus" :key="menu.route"> + <span class="nav-link" :class="{ 'active': currentRoute === menu.route }">{{ $t(menu.name )}}</span> + </router-link> + </div> + </div> + + <div class="col-10"> + + <router-view></router-view> + + </div> + + </div> + + </div> + +</template> + +<script lang="ts"> + import {Component, Vue} from 'vue-property-decorator'; + + @Component({ + components: {}, + }) + export default class extends Vue { + + menus = [ + { route: '/home/data', name: 'data.menu.forks' }, + { route: '/home/data/history-of-member', name: 'data.menu.history.of.member' }, + ] + + get currentRoute() { + return this.$route.path + } + } +</script> diff --git a/src/views/home/data/HistoryOfMember.vue b/src/views/home/data/HistoryOfMember.vue new file mode 100644 index 0000000..7a25310 --- /dev/null +++ b/src/views/home/data/HistoryOfMember.vue @@ -0,0 +1,43 @@ +<style lang="css" scoped> + + .col-12.graph { + overflow: auto !important; + } + + ul { + font-family: Consolas, "Courier New", Courier, monospace; + } +</style> + +<template> + + <div class="container-fluid"> + <div class="row"> + <div class="col-12"> + <h3>History</h3> + <ul> + <li v-for="(s) in stories">{{ s }}</li> + </ul> + </div> + </div> + </div> + +</template> + +<script lang="ts"> + import {Component, Vue} from 'vue-property-decorator'; + import ForkGraph from '@/components/ForkGraph.vue'; + + @Component({ + components: {ForkGraph}, + }) + export default class extends Vue { + + stories: string[] = [] + + async beforeMount() { + this.stories = (await this.$webmin.historyOfMember('2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ')).stories + } + + } +</script> diff --git a/src/vue-modules/register-router.ts b/src/vue-modules/register-router.ts index cb13b31..abca5b0 100644 --- a/src/vue-modules/register-router.ts +++ b/src/vue-modules/register-router.ts @@ -10,6 +10,8 @@ import Conf from '@/views/home/parameters/Conf.vue' import Network from '@/views/home/parameters/Network.vue' import Forkview from '@/views/home/Forkview.vue' import Language from '@/views/home/parameters/Language.vue' +import Data from '@/views/home/Data.vue' +import HistoryOfMember from '@/views/home/data/HistoryOfMember.vue' Vue.use(Router) @@ -36,9 +38,18 @@ export default new Router({ name: 'overview', component: Overview },{ - path: 'forkview', - name: 'forkview', - component: Forkview + path: 'data', + name: 'data', + component: Data, + children: [{ + path: '', + name: 'forkview', + component: Forkview, + },{ + path: 'history-of-member', + name: 'history', + component: HistoryOfMember, + }] },{ path: 'parameters', name: 'parameters', -- GitLab