seekia/internal/moderation/moderatorRanking/moderatorRanking.go

188 lines
6.4 KiB
Go
Raw Normal View History

// 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
}