diff --git a/back/webmin/graphql/resolvers/BigResolver.ts b/back/webmin/graphql/resolvers/BigResolver.ts index 1ccc04b85bab54d12531f7542b9a30b9980c5120..8ae3685de0c20019bb5903ebf01411084af4f850 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 0000000000000000000000000000000000000000..5c6a14d7a461e645fb21b991f0397649104e6f96 --- /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 0000000000000000000000000000000000000000..7b5c3ebb34bb2de6e0c32eb3c9c1bb1171868dd4 --- /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 149fb98dc7570c74ef72beb4c060e17b66f22b24..66f301fd8478d589263a5355714d55818e99f0cb 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 571ed50f1daa307fcfceb8f0f9cb333ca8e76faa..5b96ad1cdeb33df37adf7f8606c3b5ae3164b6c2 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 0000000000000000000000000000000000000000..b0ec967bd8c46b1f9afc59a506f26dcc10344c9b --- /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 0000000000000000000000000000000000000000..7a253104c2a04649ff65ec14cfacca45822e56a9 --- /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 cb13b316575ba92891ea039fb25efa86d13c1baf..abca5b0f04dfab6f4d3ab1ad48b67e776c53e434 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',