@@ -3,11 +3,13 @@ import { UserService } from "../services/UserService";
33import { GroupService } from "../services/GroupService" ;
44import { VoteService } from "../services/VoteService" ;
55import { PollService } from "../services/PollService" ;
6- import { JobQueueService } from "../services/JobQueueService" ;
6+ import { VotingReputationService } from "../services/VotingReputationService" ;
7+ import { MessageService } from "../services/MessageService" ;
78import { adapter } from "../web3adapter/watchers/subscriber" ;
89import { User } from "../database/entities/User" ;
910import { Group } from "../database/entities/Group" ;
1011import { Poll } from "../database/entities/Poll" ;
12+ import { VoteReputationResult } from "../database/entities/VoteReputationResult" ;
1113import { AppDataSource } from "../database/data-source" ;
1214import axios from "axios" ;
1315
@@ -16,15 +18,17 @@ export class WebhookController {
1618 groupService : GroupService ;
1719 voteService : VoteService ;
1820 pollService : PollService ;
19- jobQueueService : JobQueueService ;
21+ votingReputationService : VotingReputationService ;
22+ messageService : MessageService ;
2023 adapter : typeof adapter ;
2124
22- constructor ( jobQueueService : JobQueueService ) {
25+ constructor ( ) {
2326 this . userService = new UserService ( ) ;
2427 this . groupService = new GroupService ( ) ;
2528 this . voteService = new VoteService ( ) ;
2629 this . pollService = new PollService ( ) ;
27- this . jobQueueService = jobQueueService ;
30+ this . votingReputationService = new VotingReputationService ( ) ;
31+ this . messageService = new MessageService ( ) ;
2832 this . adapter = adapter ;
2933 }
3034
@@ -261,17 +265,11 @@ export class WebhookController {
261265 await pollRepository . save ( poll ) ;
262266 finalLocalId = poll . id ;
263267
264- // Enqueue reputation calculation job if needed
268+ // Process eReputation calculation if needed
265269 if ( this . voteService . isEReputationWeighted ( poll ) && poll . groupId ) {
266- try {
267- await this . jobQueueService . enqueuePollReputationJob (
268- poll . id ,
269- poll . groupId ,
270- globalId // Use globalId as eventId for idempotency
271- ) ;
272- } catch ( error ) {
273- console . error ( `Failed to enqueue reputation job for poll ${ poll . id } :` , error ) ;
274- }
270+ this . processEReputationWeightedPoll ( poll ) . catch ( ( error ) => {
271+ console . error ( `Error processing eReputation for poll ${ poll . id } :` , error ) ;
272+ } ) ;
275273 }
276274 }
277275 } else {
@@ -297,17 +295,11 @@ export class WebhookController {
297295 } ) ;
298296 finalLocalId = savedPoll . id ;
299297
300- // Enqueue reputation calculation job if needed
298+ // Process eReputation calculation if needed
301299 if ( this . voteService . isEReputationWeighted ( savedPoll ) && savedPoll . groupId ) {
302- try {
303- await this . jobQueueService . enqueuePollReputationJob (
304- savedPoll . id ,
305- savedPoll . groupId ,
306- globalId // Use globalId as eventId for idempotency
307- ) ;
308- } catch ( error ) {
309- console . error ( `Failed to enqueue reputation job for poll ${ savedPoll . id } :` , error ) ;
310- }
300+ this . processEReputationWeightedPoll ( savedPoll ) . catch ( ( error ) => {
301+ console . error ( `Error processing eReputation for poll ${ savedPoll . id } :` , error ) ;
302+ } ) ;
311303 }
312304 }
313305 }
@@ -319,4 +311,115 @@ export class WebhookController {
319311 }
320312 } ;
321313
314+ private async processEReputationWeightedPoll ( poll : Poll ) : Promise < void > {
315+ if ( ! poll . groupId ) return ;
316+
317+ const group = await this . groupService . getGroupById ( poll . groupId ) ;
318+ if ( ! group || ! group . charter ) return ;
319+
320+ const reputationResults = await this . votingReputationService . calculateGroupMemberReputations (
321+ poll . groupId ,
322+ group . charter
323+ ) ;
324+
325+ const voteReputationResult = await this . votingReputationService . saveReputationResults (
326+ poll . id ,
327+ poll . groupId ,
328+ reputationResults
329+ ) ;
330+
331+ await this . transmitReputationResults ( voteReputationResult , poll , group ) ;
332+ await this . createReputationMessage ( poll , reputationResults ) ;
333+ }
334+
335+ private async transmitReputationResults (
336+ result : VoteReputationResult ,
337+ poll : Poll ,
338+ group : Group
339+ ) : Promise < void > {
340+ const voteReputationResultRepository = AppDataSource . getRepository ( VoteReputationResult ) ;
341+ const pollRepository = AppDataSource . getRepository ( Poll ) ;
342+ const groupRepository = AppDataSource . getRepository ( Group ) ;
343+
344+ const reloadedResult = await voteReputationResultRepository . findOne ( {
345+ where : { id : result . id } ,
346+ relations : [ "poll" , "group" ]
347+ } ) ;
348+
349+ if ( ! reloadedResult ) throw new Error ( `Result not found: ${ result . id } ` ) ;
350+
351+ let pollEntity : Poll | null = reloadedResult . poll || null ;
352+ let groupEntity : Group | null = reloadedResult . group || null ;
353+
354+ if ( ! pollEntity && reloadedResult . pollId ) {
355+ pollEntity = await pollRepository . findOne ( { where : { id : reloadedResult . pollId } } ) ;
356+ }
357+
358+ if ( ! groupEntity && reloadedResult . groupId ) {
359+ groupEntity = await groupRepository . findOne ( {
360+ where : { id : reloadedResult . groupId } ,
361+ select : [ "id" , "ename" , "name" ]
362+ } ) ;
363+ }
364+
365+ if ( ! pollEntity || ! groupEntity || ! groupEntity . ename ) {
366+ throw new Error ( "Missing required data for transmission" ) ;
367+ }
368+
369+ const data : any = {
370+ id : reloadedResult . id ,
371+ pollId : reloadedResult . pollId ,
372+ groupId : reloadedResult . groupId ,
373+ results : JSON . stringify ( reloadedResult . results ) ,
374+ createdAt : reloadedResult . createdAt ,
375+ updatedAt : reloadedResult . updatedAt ,
376+ poll : {
377+ id : pollEntity . id ,
378+ groupId : pollEntity . groupId ,
379+ group : {
380+ id : groupEntity . id ,
381+ ename : groupEntity . ename ,
382+ name : groupEntity . name
383+ }
384+ }
385+ } ;
386+
387+ if ( ! data . groupId ) {
388+ data . groupId = groupEntity . id ;
389+ }
390+
391+ await this . adapter . handleChange ( {
392+ data,
393+ tableName : "vote_reputation_results"
394+ } ) ;
395+ }
396+
397+ private async createReputationMessage (
398+ poll : Poll ,
399+ reputationResults : Array < { ename : string ; score : number ; justification : string } >
400+ ) : Promise < void > {
401+ if ( ! poll . groupId ) return ;
402+
403+ try {
404+ const messageLines : string [ ] = [ ] ;
405+ messageLines . push ( `eReputation scores calculated for poll: "${ poll . title } "` ) ;
406+ messageLines . push ( `` ) ;
407+
408+ for ( const result of reputationResults ) {
409+ const user = await this . userService . getUserByEname ( result . ename ) ;
410+ const userName = user ?. name || "Unknown" ;
411+ messageLines . push ( `${ userName } (@${ result . ename } ): ${ result . score } /5` ) ;
412+ messageLines . push ( ` ${ result . justification } ` ) ;
413+ messageLines . push ( `` ) ;
414+ }
415+
416+ await this . messageService . createSystemMessage ( {
417+ text : messageLines . join ( '\n' ) ,
418+ groupId : poll . groupId ,
419+ voteId : poll . id
420+ } ) ;
421+ } catch ( error ) {
422+ console . error ( `Failed to create system message for poll ${ poll . id } :` , error ) ;
423+ }
424+ }
322425}
0 commit comments