From 420e928a1525ddfa7f1f5c3080cbdb15b9157e5e Mon Sep 17 00:00:00 2001 From: hzmangel Date: Mon, 23 Dec 2024 00:11:07 +0800 Subject: [PATCH 1/7] New state for proposal deleted from metaforo. Added a new logic to set proposal state but haven't tested yet --- internal/model/proposal.go | 30 +++++++++++--------- internal_inject/proposal/proposal.service.go | 16 +++++++++-- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/internal/model/proposal.go b/internal/model/proposal.go index 1d474cda..a6e18d10 100644 --- a/internal/model/proposal.go +++ b/internal/model/proposal.go @@ -38,6 +38,9 @@ const ( // ProposalStateVetoed indicates the proposal has been voted by city hall proposal. // TODO: In this case, there should be some field to reflect this relationship ProposalStateVetoed + + // ProposalStateDeletedFromMetaforo indicates the proposal has been deleted from metaforo + ProposalStateDeletedFromMetaforo ) const ( @@ -49,18 +52,19 @@ const ( ) var ProposalStateIdNameMapping = map[string]ProposalState{ - "pending_submit": ProposalStatePendingSubmit, - "draft": ProposalStateDraft, - "withdrawn": ProposalStateWithdrawn, - "rejected": ProposalStateRejected, - "approved": ProposalStateApproved, - "voting": ProposalStateVoting, - "vote_passed": ProposalStateVotePassed, - "vote_failed": ProposalStateVoteFailed, - "pending_execution": ProposalStatePendingExecution, - "executed": ProposalStateExecuted, - "execution_failed": ProposalStateExecutionFailed, - "vetoed": ProposalStateVetoed, + "pending_submit": ProposalStatePendingSubmit, + "draft": ProposalStateDraft, + "withdrawn": ProposalStateWithdrawn, + "rejected": ProposalStateRejected, + "approved": ProposalStateApproved, + "voting": ProposalStateVoting, + "vote_passed": ProposalStateVotePassed, + "vote_failed": ProposalStateVoteFailed, + "pending_execution": ProposalStatePendingExecution, + "executed": ProposalStateExecuted, + "execution_failed": ProposalStateExecutionFailed, + "vetoed": ProposalStateVetoed, + "deleted_from_metaforo": ProposalStateDeletedFromMetaforo, } var ProposalStateName = []string{ @@ -197,7 +201,7 @@ func (p *Proposal) TaskStartDelay() time.Duration { // which means the no more actions should be performed to the proposal // VoteFailed may require additional actions, so it is not in here func (p *Proposal) IsInFinState() bool { - return p.State == int(ProposalStateExecuted) || p.State == int(ProposalStateVetoed) + return p.State == int(ProposalStateExecuted) || p.State == int(ProposalStateVetoed) || p.State == int(ProposalStateDeletedFromMetaforo) } // StateIsUpdatable returns bool value indicates whether this proposal can be updated. diff --git a/internal_inject/proposal/proposal.service.go b/internal_inject/proposal/proposal.service.go index e8759e8f..a8bf4e9d 100644 --- a/internal_inject/proposal/proposal.service.go +++ b/internal_inject/proposal/proposal.service.go @@ -686,8 +686,15 @@ func (s *ProposalService) SaveProposalToMetaforo(db *gorm.DB, dbProposalId uint, // Get metaforo proposal detail metaforoProposalResponse, err = metaforo.GetProposal(metaforoThreadId, metaforoGroupName, metaforoAccessToken, 0) if err != nil { - log.Error().Msgf("get metaforoProposal %d error: %+v", metaforoThreadId, err) - return err + if strings.Contains(err.Error(), "not found") { + // Metaforo proposal not found, update proposal to deletedFromMetaforo + // Code branch for updating proposal to deletedFromMetaforo state doesn't require user and cfg data + _, err = s.UpdateProposalStateAndLaunchStateChangeActions(db, nil, strconv.Itoa(int(dbProposalId)), model.ProposalStateDeletedFromMetaforo, nil) + return err + } else { + log.Error().Msgf("get metaforoProposal %d error: %+v", metaforoThreadId, err) + return err + } } err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse) @@ -2613,6 +2620,11 @@ func (s *ProposalService) UpdateProposalStateAndLaunchStateChangeActions(db *gor log.Error().Msgf("change proposal to executed error") return 0, err } + case model.ProposalStateDeletedFromMetaforo: + if err = db.Model(&proposalRecord).Where("id = ?", proposalRecord.ID).Update("state", model.ProposalStateDeletedFromMetaforo).Error; err != nil { + log.Error().Msgf("update proposal %d state to deleted_by_metaforo error", proposalRecord.ID) + return 0, err + } default: return 0, fmt.Errorf("changing proposal from state %s to %s is not approved", proposalRecord.StateName(), model.ProposalStateName[newState]) } From 825f55281244fae6e8e227d01cc823ee081a9564 Mon Sep 17 00:00:00 2001 From: hzmangel Date: Mon, 23 Dec 2024 10:01:08 +0800 Subject: [PATCH 2/7] Save mf proposal state in UpdateDbRecordsFromMetaforoProposalResponse function --- internal/api/proposal/helper.go | 21 +++++++++++++++++++-- internal/api/proposal/req_n_resp.go | 10 ++++++---- internal/api/proposal/utils.go | 3 ++- internal/model/proposal.go | 3 +++ internal/task_manager/metaforo_task.go | 4 +++- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/internal/api/proposal/helper.go b/internal/api/proposal/helper.go index 431e8195..7511dc9e 100644 --- a/internal/api/proposal/helper.go +++ b/internal/api/proposal/helper.go @@ -764,10 +764,11 @@ func SaveProposalToMetaforo(db *gorm.DB, dbProposalId uint, voteType int, metafo metaforoProposalResponse, err = metaforo.GetProposal(metaforoThreadId, metaforoGroupName, metaforoAccessToken, 0) if err != nil { log.Error().Msgf("get metaforoProposal %d error: %+v", metaforoThreadId, err) + _ = UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse, err) return err } - err = UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse) + err = UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse, nil) if err != nil { log.Error().Msgf("update db records from metaforoProposalResponse error: %+v", err) } @@ -977,7 +978,23 @@ func IsUserMetVoteGate(userSeepassData *sdk.SeepassResponse, proposalVoteGate *m } } -func UpdateDbRecordsFromMetaforoProposalResponse(db *gorm.DB, dbProposalRcdId uint, metaforoProposal *metaforo.ProposalResponse) error { +func UpdateDbRecordsFromMetaforoProposalResponse(db *gorm.DB, dbProposalRcdId uint, metaforoProposal *metaforo.ProposalResponse, mfError error) error { + // Check whether update form metaforo contains error, if yes, update state to metaforo error and return + if mfError != nil { + log.Error().Msgf("get metaforo proposal error: %+v", mfError) + proposalStateForMetaforoError := model.ProposalStateUncategorizedMetaforoError + if strings.Contains(mfError.Error(), "not found") { + proposalStateForMetaforoError = model.ProposalStateDeletedFromMetaforo + } + + if err = db.Model(&model.Proposal{}).Where("id = ?", dbProposalRcdId).Update("state", proposalStateForMetaforoError).Error; err != nil { + log.Error().Msgf("update proposal %d state to deleted_by_metaforo error", dbProposalRcdId) + return err + } + + return nil + } + // Save all version proposals' arweave hash if err = UpdateArweaveHashFromMetaforoProposalResponse(db, dbProposalRcdId, metaforoProposal); err != nil { log.Error().Msgf("update arweave hash error: %+v", err) diff --git a/internal/api/proposal/req_n_resp.go b/internal/api/proposal/req_n_resp.go index 9be5decf..10342a0d 100644 --- a/internal/api/proposal/req_n_resp.go +++ b/internal/api/proposal/req_n_resp.go @@ -371,18 +371,20 @@ func ConvertProposalToFrontendDetailRecord(db *gorm.DB, proposalId uint, startPo if proposal.ProposalRecordId != "" { metaforoProposal, err := metaforo.GetProposal(proposal.GetMetaforoThreadId(), metaforoGroupName, accessToken, startPostId) if err != nil { + log.Error().Msgf("get metaforo proposal error: %+v", err) + _ = UpdateDbRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal, err) return nil, err } - commentCount = metaforoProposal.Thread.PostsCount - votes = metaforoProposal.Thread.Polls - - err = UpdateDbRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal) + err = UpdateDbRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal, nil) if err != nil { log.Error().Msgf("update proposal %d from metaforo error: %+v", proposalId, err) return nil, err } + commentCount = metaforoProposal.Thread.PostsCount + votes = metaforoProposal.Thread.Polls + pollStatusChanged, err := UpdateDbVoteOptionRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal) if err != nil { log.Error().Msgf("update propsal vote option records with metaforo response error: %+v", err) diff --git a/internal/api/proposal/utils.go b/internal/api/proposal/utils.go index a6bf60ba..ff82c7a6 100644 --- a/internal/api/proposal/utils.go +++ b/internal/api/proposal/utils.go @@ -100,10 +100,11 @@ func GetMetaforoProposalByInternalId(db *gorm.DB, proposalIdStr string, metaforo metaforoProposalResponse, err := metaforo.GetProposal(osProposalRcd.GetMetaforoThreadId(), metaforoGroupName, mfAccessToken, 0) if err != nil { log.Error().Msgf("get metaforo proposal error: %+v", err) + _ = UpdateDbRecordsFromMetaforoProposalResponse(db, osProposalRcd.ID, metaforoProposalResponse, err) return nil, nil, err } - err = UpdateDbRecordsFromMetaforoProposalResponse(db, osProposalRcd.ID, metaforoProposalResponse) + err = UpdateDbRecordsFromMetaforoProposalResponse(db, osProposalRcd.ID, metaforoProposalResponse, nil) if err != nil { log.Error().Msgf("update db records from metaforoProposalResponse error: %+v", err) } diff --git a/internal/model/proposal.go b/internal/model/proposal.go index a6e18d10..56e8b3ed 100644 --- a/internal/model/proposal.go +++ b/internal/model/proposal.go @@ -41,6 +41,9 @@ const ( // ProposalStateDeletedFromMetaforo indicates the proposal has been deleted from metaforo ProposalStateDeletedFromMetaforo + + // ProposalStateUncategorizedMetaforoError indicates other errors returned by metaforo + ProposalStateUncategorizedMetaforoError ) const ( diff --git a/internal/task_manager/metaforo_task.go b/internal/task_manager/metaforo_task.go index 1cd80d4a..24588851 100644 --- a/internal/task_manager/metaforo_task.go +++ b/internal/task_manager/metaforo_task.go @@ -67,14 +67,16 @@ func RefreshVotingProposalInfoJob(db *gorm.DB, job *model.CronJob, jobParams str for _, dbRcd := range proposals { metaforoThreadId := dbRcd.GetMetaforoThreadId() metaforoProposalData, err := metaforo.GetProposal(metaforoThreadId, params.GroupName, cfg.MetaforoData.AccessToken, 0) + if err != nil { + _ = proposal.UpdateDbRecordsFromMetaforoProposalResponse(db, dbRcd.ID, metaforoProposalData, err) log.Warn().Msgf("get metaforo proposal error: %+v", err) continue } // Start transaction to update db records if err = db.Transaction(func(tx *gorm.DB) error { - err = proposal.UpdateDbRecordsFromMetaforoProposalResponse(tx, dbRcd.ID, metaforoProposalData) + err = proposal.UpdateDbRecordsFromMetaforoProposalResponse(tx, dbRcd.ID, metaforoProposalData, nil) if err != nil { log.Warn().Msgf("update propsal with metaforo response error: %+v", err) return err From 1f6e4b6be7154a65dd7976831573bee6d63afc23 Mon Sep 17 00:00:00 2001 From: hzmangel Date: Mon, 23 Dec 2024 10:01:25 +0800 Subject: [PATCH 3/7] Save mf proposal state in UpdateDbRecordsFromMetaforoProposalResponse function The new proposal.service.go version --- internal_inject/proposal/proposal.service.go | 45 +++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/internal_inject/proposal/proposal.service.go b/internal_inject/proposal/proposal.service.go index a8bf4e9d..0b8f907f 100644 --- a/internal_inject/proposal/proposal.service.go +++ b/internal_inject/proposal/proposal.service.go @@ -686,18 +686,12 @@ func (s *ProposalService) SaveProposalToMetaforo(db *gorm.DB, dbProposalId uint, // Get metaforo proposal detail metaforoProposalResponse, err = metaforo.GetProposal(metaforoThreadId, metaforoGroupName, metaforoAccessToken, 0) if err != nil { - if strings.Contains(err.Error(), "not found") { - // Metaforo proposal not found, update proposal to deletedFromMetaforo - // Code branch for updating proposal to deletedFromMetaforo state doesn't require user and cfg data - _, err = s.UpdateProposalStateAndLaunchStateChangeActions(db, nil, strconv.Itoa(int(dbProposalId)), model.ProposalStateDeletedFromMetaforo, nil) - return err - } else { - log.Error().Msgf("get metaforoProposal %d error: %+v", metaforoThreadId, err) - return err - } + log.Error().Msgf("get metaforoProposal %d error: %+v", metaforoThreadId, err) + _ = s.UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse, err) + return err } - err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse) + err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, updatedProposalRecord.ID, metaforoProposalResponse, nil) if err != nil { log.Error().Msgf("update db records from metaforoProposalResponse error: %+v", err) } @@ -907,7 +901,23 @@ func (s *ProposalService) IsUserMetVoteGate(userSeepassData *sdk.SeepassResponse } } -func (s *ProposalService) UpdateDbRecordsFromMetaforoProposalResponse(db *gorm.DB, dbProposalRcdId uint, metaforoProposal *metaforo.ProposalResponse) error { +func (s *ProposalService) UpdateDbRecordsFromMetaforoProposalResponse(db *gorm.DB, dbProposalRcdId uint, metaforoProposal *metaforo.ProposalResponse, mfError error) error { + // Check whether update form metaforo contains error, if yes, update state to metaforo error and return + if mfError != nil { + log.Error().Msgf("get metaforo proposal error: %+v", mfError) + proposalStateForMetaforoError := model.ProposalStateUncategorizedMetaforoError + if strings.Contains(mfError.Error(), "not found") { + proposalStateForMetaforoError = model.ProposalStateDeletedFromMetaforo + } + + if err := db.Model(&model.Proposal{}).Where("id = ?", dbProposalRcdId).Update("state", proposalStateForMetaforoError).Error; err != nil { + log.Error().Msgf("update proposal %d state to deleted_by_metaforo error", dbProposalRcdId) + return err + } + + return nil + } + // Save all version proposals' arweave hash if err := s.UpdateArweaveHashFromMetaforoProposalResponse(db, dbProposalRcdId, metaforoProposal); err != nil { log.Error().Msgf("update arweave hash error: %+v", err) @@ -2018,18 +2028,20 @@ func (s *ProposalService) ConvertProposalToFrontendDetailRecord(db *gorm.DB, pro if proposal.ProposalRecordId != "" { metaforoProposal, err := metaforo.GetProposal(proposal.GetMetaforoThreadId(), metaforoGroupName, accessToken, startPostId) if err != nil { + log.Error().Msgf("get proposal %d from metaforo error: %+v", proposalId, err) + _ = s.UpdateDbRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal, err) return nil, err } - commentCount = metaforoProposal.Thread.PostsCount - votes = metaforoProposal.Thread.Polls - - err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal) + err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal, nil) if err != nil { log.Error().Msgf("update proposal %d from metaforo error: %+v", proposalId, err) return nil, err } + commentCount = metaforoProposal.Thread.PostsCount + votes = metaforoProposal.Thread.Polls + pollStatusChanged, err := s.UpdateDbVoteOptionRecordsFromMetaforoProposalResponse(db, proposalId, metaforoProposal) if err != nil { log.Error().Msgf("update propsal vote option records with metaforo response error: %+v", err) @@ -2218,10 +2230,11 @@ func (s *ProposalService) GetMetaforoProposalByInternalId(db *gorm.DB, proposalI metaforoProposalResponse, err := metaforo.GetProposal(osProposalRcd.GetMetaforoThreadId(), metaforoGroupName, mfAccessToken, 0) if err != nil { log.Error().Msgf("get metaforo proposal error: %+v", err) + _ = s.UpdateDbRecordsFromMetaforoProposalResponse(db, osProposalRcd.ID, metaforoProposalResponse, err) return nil, nil, err } - err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, osProposalRcd.ID, metaforoProposalResponse) + err = s.UpdateDbRecordsFromMetaforoProposalResponse(db, osProposalRcd.ID, metaforoProposalResponse, nil) if err != nil { log.Error().Msgf("update db records from metaforoProposalResponse error: %+v", err) } From 96da05cb7976e13c5fca2d7f836517961b14ed37 Mon Sep 17 00:00:00 2001 From: hzmangel Date: Mon, 23 Dec 2024 23:53:45 +0800 Subject: [PATCH 4/7] check proposal not found error in playground code --- cmd/metaforo_api_test/main.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmd/metaforo_api_test/main.go b/cmd/metaforo_api_test/main.go index e65e369a..199837a9 100644 --- a/cmd/metaforo_api_test/main.go +++ b/cmd/metaforo_api_test/main.go @@ -103,7 +103,14 @@ func main() { metaforo.UpdateVoteTime(*voteAccessToken, *voteGroup, *voteId, startTs.Unix(), endTs.Unix()) case "show": showCommand.Parse(os.Args[2:]) - proposal, _ := metaforo.GetProposal(*showThreadId, *showGroup, "", 0) + proposal, err := metaforo.GetProposal(*showThreadId, *showGroup, "", 0) + if err != nil { + if strings.Contains(err.Error(), "thread not found") { + log.Err(err).Msgf("thread not found, threadId: %d", *showThreadId) + } else { + panic(err) + } + } api.PrintStructAsJson(proposal, "") default: fmt.Println("Unknown subcommand:", os.Args[1]) From e07c9f0e1e027ca0cb8582f95fb21db71b4c6164 Mon Sep 17 00:00:00 2001 From: hzmangel Date: Sun, 8 Jun 2025 01:57:14 +0800 Subject: [PATCH 5/7] Add new field to save IsMultipleVote flag Which can solve saved proposal missing this flag error. --- internal/api/proposal/helper.go | 1 + internal/model/proposal.go | 4 ++++ internal_inject/proposal/proposal.service.go | 8 +++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/api/proposal/helper.go b/internal/api/proposal/helper.go index 431e8195..d41dbf3d 100644 --- a/internal/api/proposal/helper.go +++ b/internal/api/proposal/helper.go @@ -344,6 +344,7 @@ func SaveProposalRecordToDB(db *gorm.DB, reqData *CreateOrUpdateProposalData, us proposalRcd.VoteDurationSecond = dbProposalRcd.VoteDurationSecond proposalRcd.VoteDurationSecond = dbProposalRcd.VoteDurationSecond proposalRcd.AssociateProposalId = reqData.CreateProjectProposalId + proposalRcd.IsMultipleVote = reqData.IsMultipleVote // proposalRcd is a new record, use create function here. Also update other data related to proposal if err = db.Transaction(func(tx *gorm.DB) error { diff --git a/internal/model/proposal.go b/internal/model/proposal.go index 1d474cda..d044f505 100644 --- a/internal/model/proposal.go +++ b/internal/model/proposal.go @@ -175,6 +175,10 @@ type Proposal struct { // Whether user vote record has been saved for this proposal UserVoteRecordSaved bool `gorm:"default:false"` + + // IsMultiple saves the proposal is multiple vote or not, the flag will be used for draft proposal + // For proposals already created in Metaforo, the max_vote will be used as proporal multiple vote flag + IsMultipleVote bool `gorm:"default:false"` } func (p *Proposal) StateName() string { diff --git a/internal_inject/proposal/proposal.service.go b/internal_inject/proposal/proposal.service.go index 255e21d6..2de4b521 100644 --- a/internal_inject/proposal/proposal.service.go +++ b/internal_inject/proposal/proposal.service.go @@ -2160,6 +2160,12 @@ func (s *ProposalService) ConvertProposalToFrontendDetailRecord(db *gorm.DB, pro log.Error().Msgf("fetch proposal error: %+v", err) return nil, err, -1 } + + proposalMultipleVoteFlag := proposal.IsMultipleVote + if proposal.ProposalRecordId != "" { + proposalMultipleVoteFlag = len(votes) > 0 && votes[0].Max > 1 + } + return &FrontendProposalDetailRecord{ ID: proposalId, Title: proposal.Title, @@ -2185,7 +2191,7 @@ func (s *ProposalService) ConvertProposalToFrontendDetailRecord(db *gorm.DB, pro Votes: votes, OsVoteOptions: frontendVoteOptions, VoteType: proposal.VoteType, - IsMultipleVote: len(votes) > 0 && votes[0].Max > 1, + IsMultipleVote: proposalMultipleVoteFlag, CreateTs: proposal.CreateTs, IsBasedOnCustomTemplate: proposal.IsBasedOnCustomTemplate, TemplateName: templateName, From 3fdaeed30dc01f43c268c4bfd00e6007f17deb89 Mon Sep 17 00:00:00 2001 From: hzmangel Date: Sun, 8 Jun 2025 20:52:03 +0800 Subject: [PATCH 6/7] Set the IsMultipleVote for real logic --- internal_inject/proposal/proposal.service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal_inject/proposal/proposal.service.go b/internal_inject/proposal/proposal.service.go index 2de4b521..fc3fe811 100644 --- a/internal_inject/proposal/proposal.service.go +++ b/internal_inject/proposal/proposal.service.go @@ -267,6 +267,7 @@ func (s *ProposalService) SaveProposalRecordToDB(db *gorm.DB, reqData *CreateOrU proposalRcd.VoteDurationSecond = dbProposalRcd.VoteDurationSecond proposalRcd.VoteDurationSecond = dbProposalRcd.VoteDurationSecond proposalRcd.AssociateProposalId = reqData.CreateProjectProposalId + proposalRcd.IsMultipleVote = reqData.IsMultipleVote // proposalRcd is a new record, use create function here. Also update other data related to proposal if err = db.Transaction(func(tx *gorm.DB) error { From 92df00c16e65ee77ae4505036f02d60bb81ac586 Mon Sep 17 00:00:00 2001 From: hzmangel Date: Sun, 8 Jun 2025 20:57:49 +0800 Subject: [PATCH 7/7] Fix cases for creating new proposal --- internal_inject/proposal/proposal.service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal_inject/proposal/proposal.service.go b/internal_inject/proposal/proposal.service.go index fc3fe811..8fc3f4e2 100644 --- a/internal_inject/proposal/proposal.service.go +++ b/internal_inject/proposal/proposal.service.go @@ -334,6 +334,7 @@ func (s *ProposalService) SaveProposalRecordToDB(db *gorm.DB, reqData *CreateOrU AssociateProposalId: reqData.CreateProjectProposalId, ProposalTemplateID: &reqData.TemplateId, ExtraResultCheckRule: pTemplate.ExtraResultCheckRule, + IsMultipleVote: reqData.IsMultipleVote, } proposalRecord.PublicitySecond = voteTimeProps.PublicitySecond proposalRecord.PendingExecutionSecond = voteTimeProps.PendingExecutionSecond