// moderatorRanking provides functions to calculate a moderator's rank, and to get a list of ranked moderators // A moderator's rank is determined by ranking all moderators by their identity scores. package moderatorRanking //TODO: Add a bool to both functions to exclude banned moderators // When a moderator is viewing another moderator's rank, they should be able to view both rankings: Banned excluded and banned included // This might actually be a bad idea, because it could encourage moderators to ban other moderators so they can surpass them in rank without having to burn more funds. import "seekia/internal/encoding" import "seekia/internal/helpers" import "seekia/internal/identity" import "seekia/internal/moderation/enabledModerators" import "seekia/internal/moderation/moderatorScores" import "slices" import "errors" // This function returns the rank of a particular moderator // This is faster than ranking all of the moderators, because we don't have to sort //Outputs: // -bool: Moderator ranking known // -int: Moderator rank // -int: Total number of moderators // -error func GetModeratorRanking(moderatorIdentityHash [16]byte, networkType byte)(bool, int, int, error){ isValid := helpers.VerifyNetworkType(networkType) if (isValid == false){ networkTypeString := helpers.ConvertByteToString(networkType) return false, 0, 0, errors.New("GetModeratorRanking called with invalid networkType: " + networkTypeString) } moderatorScoresMap, err := getEnabledModeratorScoresMap(networkType) if (err != nil) { return false, 0, 0, err } moderatorScore, exists := moderatorScoresMap[moderatorIdentityHash] if (exists == false){ // We may not have downloaded their profile or their identity score // Their profile may also be disabled // We cannot determine their ranking return false, 0, 0, nil } moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash) if (err != nil) { moderatorIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityHash[:]) return false, 0, 0, errors.New("moderatorScoresMap contains invalid moderator identity hash: " + moderatorIdentityHashHex) } totalNumberOfModerators := len(moderatorScoresMap) moderatorsWithLowerScoreCounter := 0 for currentModeratorIdentityHash, currentModeratorScore := range moderatorScoresMap{ if (currentModeratorIdentityHash == moderatorIdentityHash){ continue } if (moderatorScore == currentModeratorScore){ currentModeratorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(currentModeratorIdentityHash) if (err != nil) { moderatorIdentityHashHex := encoding.EncodeBytesToHexString(currentModeratorIdentityHash[:]) return false, 0, 0, errors.New("moderatorScoresMap contains invalid moderator identity hash: " + moderatorIdentityHashHex) } // We sort moderators with the same identity score in alphabetical order if (moderatorIdentityHashString < currentModeratorIdentityHashString){ moderatorsWithLowerScoreCounter += 1 } continue } if (moderatorScore > currentModeratorScore){ moderatorsWithLowerScoreCounter += 1 } } moderatorRank := totalNumberOfModerators - moderatorsWithLowerScoreCounter return true, moderatorRank, totalNumberOfModerators, nil } // This function returns a list of all moderators ranked, starting from highest to lowest rank func GetRankedModeratorsList(networkType byte)([][16]byte, error){ isValid := helpers.VerifyNetworkType(networkType) if (isValid == false){ networkTypeString := helpers.ConvertByteToString(networkType) return nil, errors.New("GetRankedModeratorsList called with invalid networkType: " + networkTypeString) } moderatorScoresMap, err := getEnabledModeratorScoresMap(networkType) if (err != nil) { return nil, err } moderatorIdentitiesList := helpers.GetListOfMapKeys(moderatorScoresMap) compareIdentitiesFunction := func(moderatorIdentityA [16]byte, moderatorIdentityB [16]byte)int { if (moderatorIdentityA == moderatorIdentityB){ panic("compareIdentitiesFunction called with identical moderator identities.") } moderatorAScore, exists := moderatorScoresMap[moderatorIdentityA] if (exists == false) { panic("Moderator score not found in moderatorScoresMap") } moderatorBScore, exists := moderatorScoresMap[moderatorIdentityB] if (exists == false) { panic("Moderator score not found in moderatorScoresMap") } if (moderatorAScore == moderatorBScore){ // This will sort the moderators in unicode order // This is to make sure that everyone calculates moderator order the same way moderatorIdentityAString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityA) if (err != nil) { moderatorAIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityA[:]) panic("moderatorScoresMap contains invalid moderator identity hash: " + moderatorAIdentityHashHex) } moderatorIdentityBString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityB) if (err != nil) { moderatorBIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityB[:]) panic("moderatorScoresMap contains invalid moderator identity hash: " + moderatorBIdentityHashHex) } if (moderatorIdentityAString < moderatorIdentityBString){ return -1 } return 1 } if (moderatorAScore < moderatorBScore){ return 1 } return -1 } slices.SortFunc(moderatorIdentitiesList, compareIdentitiesFunction) return moderatorIdentitiesList, nil } // This function returns a map of all enabled (not disabled) moderators with their identity scores // It will omit any moderators whose scores have not been downloaded or are not sufficient //Outputs: // -map[[16]byte]float64: Identity Hash -> Moderator Score // -error func getEnabledModeratorScoresMap(networkType byte)(map[[16]byte]float64, error){ enabledModeratorsList, err := enabledModerators.GetEnabledModeratorsList(true, networkType) if (err != nil) { return nil, err } moderatorScoresMap := make(map[[16]byte]float64) for _, moderatorIdentityHash := range enabledModeratorsList{ scoreIsKnown, moderatorScore, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(moderatorIdentityHash) if (err != nil) { return nil, err } if (scoreIsKnown == false){ continue } if (scoreIsSufficient == false){ // Moderator has not funded their identity sufficiently. continue } moderatorScoresMap[moderatorIdentityHash] = moderatorScore } return moderatorScoresMap, nil }