188 lines
6.4 KiB
Go
188 lines
6.4 KiB
Go
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
|