4855 lines
188 KiB
Go
4855 lines
188 KiB
Go
package gui
|
|
|
|
// moderatorGui.go implements pages for moderators to review and browse content and identities, and to manage their own reviews.
|
|
|
|
//TODO: Add moderate full profiles page
|
|
//TODO: Add page to view my hidden content
|
|
|
|
import "fyne.io/fyne/v2"
|
|
import "fyne.io/fyne/v2/canvas"
|
|
import "fyne.io/fyne/v2/container"
|
|
import "fyne.io/fyne/v2/dialog"
|
|
import "fyne.io/fyne/v2/layout"
|
|
import "fyne.io/fyne/v2/theme"
|
|
import "fyne.io/fyne/v2/widget"
|
|
|
|
import "seekia/internal/appMemory"
|
|
import "seekia/internal/badgerDatabase"
|
|
import "seekia/internal/contentMetadata"
|
|
import "seekia/internal/encoding"
|
|
import "seekia/internal/helpers"
|
|
import "seekia/internal/identity"
|
|
import "seekia/internal/imagery"
|
|
import "seekia/internal/messaging/chatMessageStorage"
|
|
import "seekia/internal/moderation/bannedModeratorConsensus"
|
|
import "seekia/internal/moderation/moderatorRanking"
|
|
import "seekia/internal/moderation/myHiddenContent"
|
|
import "seekia/internal/moderation/myIdentityScore"
|
|
import "seekia/internal/moderation/myReviews"
|
|
import "seekia/internal/moderation/mySkippedContent"
|
|
import "seekia/internal/moderation/myUnreviewed"
|
|
import "seekia/internal/moderation/readReviews"
|
|
import "seekia/internal/moderation/reportStorage"
|
|
import "seekia/internal/moderation/reviewStorage"
|
|
import "seekia/internal/moderation/verifiedVerdict"
|
|
import "seekia/internal/myIdentity"
|
|
import "seekia/internal/mySettings"
|
|
import "seekia/internal/network/appNetworkType/getAppNetworkType"
|
|
import "seekia/internal/network/backgroundDownloads"
|
|
import "seekia/internal/profiles/attributeDisplay"
|
|
import "seekia/internal/profiles/calculatedAttributes"
|
|
import "seekia/internal/profiles/myProfileStatus"
|
|
import "seekia/internal/profiles/profileFormat"
|
|
import "seekia/internal/profiles/profileStorage"
|
|
import "seekia/internal/profiles/readProfiles"
|
|
|
|
import "slices"
|
|
import "bytes"
|
|
import "strings"
|
|
import "time"
|
|
import "errors"
|
|
|
|
func setModeratePage(window fyne.Window, previousPageExists bool, previousPage func()){
|
|
|
|
appMemory.SetMemoryEntry("CurrentViewedPage", "Moderate")
|
|
|
|
currentPage := func(){setModeratePage(window, previousPageExists, previousPage)}
|
|
homePage := func(){setHomePage(window)}
|
|
|
|
title := getPageTitleCentered("Moderate")
|
|
|
|
page := container.NewVBox(title)
|
|
|
|
if (previousPageExists == true){
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
page.Add(backButton)
|
|
}
|
|
|
|
page.Add(widget.NewSeparator())
|
|
|
|
description := getLabelCentered("Be a Seekia moderator.")
|
|
page.Add(description)
|
|
page.Add(widget.NewSeparator())
|
|
|
|
rulesIcon, err := getFyneImageIcon("Info")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
profileIcon, err := getFyneImageIcon("Profile")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
settingsIcon, err := getFyneImageIcon("Settings")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
moderatorsIcon, err := getFyneImageIcon("Users")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
statsIcon, err := getFyneImageIcon("Stats")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
contentIcon, err := getFyneImageIcon("Choice")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
manageProfileButton := widget.NewButton("Profile", func(){
|
|
setProfilePage(window, true, "Moderator", true, currentPage)
|
|
})
|
|
manageProfileButtonWithIcon := container.NewGridWithColumns(1, profileIcon, manageProfileButton)
|
|
|
|
moderatorSettingsButton := widget.NewButton("Settings", func(){
|
|
setModeratorSettingsPage(window, currentPage)
|
|
})
|
|
moderatorSettingsButtonWithIcon := container.NewGridWithColumns(1, settingsIcon, moderatorSettingsButton)
|
|
|
|
rulesButton := widget.NewButton("Rules", func(){
|
|
setViewSeekiaRulesPage(window, currentPage)
|
|
//TODO: Create a rules page for moderators, explaining how to be a moderator
|
|
})
|
|
rulesButtonWithIcon := container.NewGridWithColumns(1, rulesIcon, rulesButton)
|
|
|
|
moderatorsButton := widget.NewButton("Mods", func(){
|
|
setViewModeratorsPage(window, currentPage)
|
|
})
|
|
moderatorsButtonWithIcon := container.NewGridWithColumns(1, moderatorsIcon, moderatorsButton)
|
|
|
|
statsButton := widget.NewButton("Stats", func(){
|
|
// TODO: Page to show statistics about the user's moderator reviews, and moderation statistics of the entire network
|
|
// Example: Unreviewed profiles, number of banned profiles, and more
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
statsButtonWithIcon := container.NewGridWithColumns(1, statsIcon, statsButton)
|
|
|
|
contentButton := widget.NewButton("Content", func(){
|
|
setBrowseContentPage(window, currentPage)
|
|
})
|
|
contentButtonWithIcon := container.NewGridWithColumns(1, contentIcon, contentButton)
|
|
|
|
buttonsRow := getContainerCentered(container.NewGridWithRows(1, rulesButtonWithIcon, manageProfileButtonWithIcon, moderatorSettingsButtonWithIcon, moderatorsButtonWithIcon, statsButtonWithIcon, contentButtonWithIcon))
|
|
|
|
page.Add(buttonsRow)
|
|
page.Add(widget.NewSeparator())
|
|
|
|
exists, moderatorModeStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
if (exists == false || moderatorModeStatus == "Off"){
|
|
|
|
description1 := getBoldLabelCentered("You must enable moderator mode to moderate.")
|
|
description2 := getLabelCentered("Enable it on the Settings page.")
|
|
|
|
page.Add(description1)
|
|
page.Add(description2)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
identityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
if (identityExists == false){
|
|
|
|
description1 := getBoldLabelCentered("Your moderator identity does not exist.")
|
|
description2 := getLabelCentered("You must choose an identity.")
|
|
description3 := getLabelCentered("This is how users of Seekia will identify you.")
|
|
|
|
chooseIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Choose Identity", theme.NavigateNextIcon(), func(){
|
|
setChooseNewIdentityHashPage(window, "Moderator", currentPage, currentPage)
|
|
}))
|
|
|
|
page.Add(description1)
|
|
page.Add(description2)
|
|
page.Add(description3)
|
|
page.Add(chooseIdentityButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
identityExists, iAmOnlineStatus, err := myProfileStatus.GetMyProfileIsActiveStatus(myIdentityHash, appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
if (identityExists == false) {
|
|
setErrorEncounteredPage(window, errors.New("My identity not found after being found already."), homePage)
|
|
return
|
|
}
|
|
if (iAmOnlineStatus == false){
|
|
|
|
description1 := getBoldLabelCentered("Your Moderator profile is offline.")
|
|
description2 := getLabelCentered("Broadcast your profile on the Profile - Broadcast page.")
|
|
|
|
page.Add(description1)
|
|
page.Add(description2)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
//TODO: Check for moderation parameters
|
|
|
|
moderateDescriptionA := getBoldLabelCentered("You are ready to moderate.")
|
|
moderateDescriptionB := getLabelCentered("Choose the type of content to moderate.")
|
|
page.Add(moderateDescriptionA)
|
|
page.Add(moderateDescriptionB)
|
|
page.Add(widget.NewSeparator())
|
|
|
|
mateIcon, err := getFyneImageIcon("Mate")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
mateButton := widget.NewButton("Mate Profiles", func(){
|
|
setChooseProfileContentToModeratePage(window, "Mate", currentPage)
|
|
})
|
|
mateColumn := container.NewGridWithColumns(1, mateIcon, mateButton)
|
|
|
|
hostIcon, err := getFyneImageIcon("Host")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
hostButton := widget.NewButton("Host Profiles", func(){
|
|
setChooseProfileContentToModeratePage(window, "Host", currentPage)
|
|
})
|
|
hostColumn := container.NewGridWithColumns(1, hostIcon, hostButton)
|
|
|
|
moderatorIcon, err := getFyneImageIcon("Moderate")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
moderatorButton := widget.NewButton("Moderator Profiles", func(){
|
|
setChooseProfileContentToModeratePage(window, "Moderator", currentPage)
|
|
})
|
|
moderatorColumn := container.NewGridWithColumns(1, moderatorIcon, moderatorButton)
|
|
|
|
profilesRow := getContainerCentered(container.NewGridWithRows(1, mateColumn, hostColumn, moderatorColumn))
|
|
page.Add(profilesRow)
|
|
|
|
textMessagesImage, err := getFyneImageIcon("InspectText")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
textMessagesButton := widget.NewButton("Text Messages", func(){
|
|
setModerateMessagesPage(window, "Text", false, [26]byte{}, currentPage)
|
|
})
|
|
textMessagesColumn := container.NewGridWithColumns(1, textMessagesImage, textMessagesButton)
|
|
|
|
imageMessagesIcon, err := getFyneImageIcon("Photo")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
imageMessagesButton := widget.NewButton("Image Messages", func(){
|
|
setModerateMessagesPage(window, "Image", false, [26]byte{}, currentPage)
|
|
})
|
|
imageMessagesColumn := container.NewGridWithColumns(1, imageMessagesIcon, imageMessagesButton)
|
|
|
|
messageButtonsRow := getContainerCentered(container.NewGridWithRows(1, textMessagesColumn, imageMessagesColumn))
|
|
page.Add(messageButtonsRow)
|
|
|
|
identitiesIcon, err := getFyneImageIcon("Profile")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, homePage)
|
|
return
|
|
}
|
|
|
|
identitiesButton := widget.NewButton("Identities", func(){
|
|
setModerateIdentitiesPage(window, currentPage)
|
|
})
|
|
|
|
identitiesColumn := getContainerCentered(container.NewGridWithColumns(1, identitiesIcon, identitiesButton))
|
|
page.Add(identitiesColumn)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setChooseProfileContentToModeratePage(window fyne.Window, profileType string, previousPage func()){
|
|
|
|
setLoadingScreen(window, "Moderate " + profileType + " Profiles", "Loading profiles...")
|
|
|
|
currentPage := func(){setChooseProfileContentToModeratePage(window, profileType, previousPage)}
|
|
|
|
title := getPageTitleCentered("Moderate " + profileType + " Profiles")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
//TODO: Check if we are moderating profiles of this profileType
|
|
|
|
description := getLabelCentered("Choose a profile attribute to moderate (under construction).")
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
moderateFullProfilesButton := getWidgetCentered(widget.NewButton("Moderate Full Profiles", func(){
|
|
//TODO: A page to moderate full profiles, which have at least 1 full profile ban.
|
|
// This page will show profiles whose full profile has been banned.
|
|
// This is necessary, because profiles which have been fully banned must be fully approved to undo the effect of the ban.
|
|
// Approving all of the profile's attributes individually is cumbersome, and takes up more space in the form of reviews.
|
|
// Also, viewing a full profile is necessary when the full profile has been banned, because
|
|
// whatever is unruleful about the profile can't be isolated to a single attribute.
|
|
// If it could be isolated to a single attribute, the moderator would have banned that attribute, not the full profile
|
|
// The exception is with malicious moderators, who could abuse this feature to waste
|
|
// the time of moderators by banning many full profiles.
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
nameLabel := getItalicLabelCentered("Name")
|
|
isCanonicalLabel := getItalicLabelCentered("Is Canonical")
|
|
anyUnreviewedLabel := getItalicLabelCentered("Any Unreviewed?")
|
|
emptyLabel := widget.NewLabel("")
|
|
|
|
attributeNamesColumn := container.NewVBox(nameLabel, widget.NewSeparator())
|
|
attributeIsCanonicalColumn := container.NewVBox(isCanonicalLabel, widget.NewSeparator())
|
|
anyUnreviewedExistColumn := container.NewVBox(anyUnreviewedLabel, widget.NewSeparator())
|
|
viewAttributeButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator())
|
|
|
|
addAttributeRow := func(attributeName string, attributeIsCanonical bool, attributeIdentifier int)error{
|
|
|
|
attributeIsCanonicalString := helpers.ConvertBoolToYesOrNoString(attributeIsCanonical)
|
|
|
|
anyExist, _, _, _, err := myUnreviewed.GetMyHighestPriorityUnreviewedProfileAttributeHash(profileType, attributeIdentifier, appNetworkType)
|
|
if (err != nil) { return err }
|
|
|
|
getAnyUnreviewedExistLabel := func()*fyne.Container{
|
|
|
|
if (anyExist == false){
|
|
|
|
noLabel := getLabelCentered(translate("No"))
|
|
return noLabel
|
|
}
|
|
|
|
yesLabel := getBoldLabelCentered(translate("Yes"))
|
|
|
|
return yesLabel
|
|
}
|
|
|
|
anyUnreviewedExistLabel := getAnyUnreviewedExistLabel()
|
|
|
|
attributeNameLabel := getBoldLabelCentered(attributeName)
|
|
attributeIsCanonicalLabel := getBoldLabelCentered(attributeIsCanonicalString)
|
|
viewAttributeButton := widget.NewButtonWithIcon("", theme.NavigateNextIcon(), func(){
|
|
setModerateProfileAttributesPage(window, profileType, attributeIdentifier, false, [27]byte{}, [28]byte{}, [16]byte{}, currentPage)
|
|
})
|
|
|
|
attributeNamesColumn.Add(attributeNameLabel)
|
|
attributeIsCanonicalColumn.Add(attributeIsCanonicalLabel)
|
|
anyUnreviewedExistColumn.Add(anyUnreviewedExistLabel)
|
|
viewAttributeButtonsColumn.Add(viewAttributeButton)
|
|
|
|
attributeNamesColumn.Add(widget.NewSeparator())
|
|
attributeIsCanonicalColumn.Add(widget.NewSeparator())
|
|
anyUnreviewedExistColumn.Add(widget.NewSeparator())
|
|
viewAttributeButtonsColumn.Add(widget.NewSeparator())
|
|
|
|
return nil
|
|
}
|
|
|
|
addAttributeRows := func()error{
|
|
|
|
if (profileType == "Mate"){
|
|
err := addAttributeRow("Photos", false, 18)
|
|
if (err != nil){ return err }
|
|
}
|
|
|
|
err := addAttributeRow("Username", false, 10)
|
|
if (err != nil) { return err }
|
|
|
|
err = addAttributeRow("Description", false, 9)
|
|
if (err != nil) { return err }
|
|
|
|
if (profileType == "Mate"){
|
|
err := addAttributeRow("Age", true, 8)
|
|
if (err != nil) { return err }
|
|
|
|
err = addAttributeRow("Sex", true, 7)
|
|
if (err != nil) { return err }
|
|
|
|
err = addAttributeRow("Height", true, 6)
|
|
if (err != nil) { return err }
|
|
}
|
|
|
|
//TODO: Add more attributes
|
|
|
|
return nil
|
|
}
|
|
|
|
err = addAttributeRows()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
isCanonicalHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
setAttributeIsCanonicalExplainerPage(window, currentPage)
|
|
})
|
|
anyUnreviewedExistHelpButton := widget.NewButtonWithIcon("", theme.QuestionIcon(), func(){
|
|
setAnyUnreviewedAttributesExistExplainerPage(window, currentPage)
|
|
})
|
|
|
|
attributeIsCanonicalColumn.Add(isCanonicalHelpButton)
|
|
anyUnreviewedExistColumn.Add(anyUnreviewedExistHelpButton)
|
|
|
|
attributeGrid := container.NewHBox(layout.NewSpacer(), attributeNamesColumn, attributeIsCanonicalColumn, anyUnreviewedExistColumn, viewAttributeButtonsColumn, layout.NewSpacer())
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), moderateFullProfilesButton, widget.NewSeparator(), attributeGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
// This page is used by a moderator to browse their unreviewed profile attributes, review the content, and submit a verdict
|
|
// It provides skip and hide buttons, and serve new attributes to review to the moderator
|
|
func setModerateProfileAttributesPage(window fyne.Window, profileType string, attributeIdentifier int, attributeProvided bool, attributeHash [27]byte, attributeProfileHash [28]byte, attributeAuthorIdentityHash [16]byte, previousPage func()){
|
|
|
|
setLoadingScreen(window, "Moderating Attributes", "Loading attribute...")
|
|
|
|
currentPage := func(){setModerateProfileAttributesPage(window, profileType, attributeIdentifier, attributeProvided, attributeHash, attributeProfileHash, attributeAuthorIdentityHash, previousPage)}
|
|
|
|
refreshPageWithNewContent := func(){setModerateProfileAttributesPage(window, profileType, attributeIdentifier, false, [27]byte{}, [28]byte{}, [16]byte{}, previousPage)}
|
|
|
|
title := getPageTitleCentered("Moderating Attributes")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (attributeProvided == false){
|
|
|
|
attributeExists, newAttributeHash, newAttributeProfileHash, newAttributeAuthorIdentityHash, err := myUnreviewed.GetMyHighestPriorityUnreviewedProfileAttributeHash(profileType, attributeIdentifier, appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (attributeExists == false){
|
|
|
|
attributeName, err := profileFormat.GetAttributeNameFromAttributeIdentifier(attributeIdentifier)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
description1 := getBoldLabelCentered("No " + attributeName + " attributes remaining to moderate.")
|
|
description2 := getLabelCentered("Check back later for new attributes to review.")
|
|
//TODO: Add check for if space is full, and add description to say to increase space allowed for moderation content
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
setModerateProfileAttributesPage(window, profileType, attributeIdentifier, true, newAttributeHash, newAttributeProfileHash, newAttributeAuthorIdentityHash, previousPage)
|
|
return
|
|
}
|
|
|
|
viewAttributeDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("View Attribute Details", theme.VisibilityIcon(), func(){
|
|
setViewAttributeModerationDetailsPage(window, attributeHash, currentPage)
|
|
}))
|
|
|
|
profileExists, profileBytes, err := profileStorage.GetStoredProfile(attributeProfileHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (profileExists == false){
|
|
// Profile must have been deleted after myUnreviewed found it
|
|
// We will refresh page and show loading screen so we can tell if this is happening
|
|
setLoadingScreen(window, "Moderating Attributes", "Trying to find attribute...")
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
refreshPageWithNewContent()
|
|
return
|
|
}
|
|
|
|
attributeName, err := profileFormat.GetAttributeNameFromAttributeIdentifier(attributeIdentifier)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
attributeTitle, _, _, _, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
attributeNameLabel := widget.NewLabel("Attribute Name:")
|
|
attributeTitleLabel := getBoldLabel(attributeTitle)
|
|
attributeTitleRow := container.NewHBox(layout.NewSpacer(), attributeNameLabel, attributeTitleLabel, layout.NewSpacer())
|
|
|
|
attributeDisplayContainer, err := getProfileAttributeDisplayForModeration(window, attributeName, attributeIdentifier, profileBytes, currentPage)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
appNetworkTypeString := helpers.ConvertByteToString(appNetworkType)
|
|
attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])
|
|
|
|
submitAttributeReview := func(verdict string, reasonExists bool, reason string)error{
|
|
|
|
newReviewMap := map[string]string{
|
|
"NetworkType": appNetworkTypeString,
|
|
"ReviewedHash": attributeHashHex,
|
|
"Verdict": verdict,
|
|
}
|
|
|
|
if (reasonExists == true){
|
|
newReviewMap["Reason"] = reason
|
|
}
|
|
|
|
myIdentityExists, err := myReviews.CreateAndBroadcastMyReview(newReviewMap)
|
|
if (err != nil) { return err }
|
|
if (myIdentityExists == false) {
|
|
return errors.New("My moderator identity not found when trying to submit review.")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
submitBanIdentityReview := func(reasonExists bool, reason string)error{
|
|
|
|
attributeAuthorString, _, err := identity.EncodeIdentityHashBytesToString(attributeAuthorIdentityHash)
|
|
if (err != nil) { return err }
|
|
|
|
attributeProfileHashHex := encoding.EncodeBytesToHexString(attributeProfileHash[:])
|
|
|
|
identityReviewMap := map[string]string{
|
|
"NetworkType": appNetworkTypeString,
|
|
"ReviewedHash": attributeAuthorString,
|
|
"Verdict": "Ban",
|
|
"ErrantAttributes": attributeHashHex,
|
|
"ErrantProfiles": attributeProfileHashHex,
|
|
}
|
|
|
|
if (reasonExists == true){
|
|
identityReviewMap["Reason"] = reason
|
|
}
|
|
|
|
myIdentityExists, err := myReviews.CreateAndBroadcastMyReview(identityReviewMap)
|
|
if (err != nil) { return err }
|
|
if (myIdentityExists == false) {
|
|
return errors.New("My moderator identity not found when trying to submit review.")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
approveAttributeWithReasonFunction := func(reasonExists bool, reason string)error{
|
|
|
|
err := submitAttributeReview("Approve", reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
banAttributeWithReasonFunction := func(reasonExists bool, reason string)error{
|
|
err := submitAttributeReview("Ban", reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
banAttributeAndIdentityWithReasonFunction := func(reasonExists bool, reason string)error{
|
|
err := submitAttributeReview("Ban", reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
err = submitBanIdentityReview(reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
approveAttributeButton := widget.NewButtonWithIcon("Approve Attribute", theme.ConfirmIcon(), func(){
|
|
|
|
setEnterReasonAndSubmitReviewPage(window, "Submit Approve Review", "Approve Attribute", "Approve", approveAttributeWithReasonFunction, currentPage, refreshPageWithNewContent)
|
|
})
|
|
banAttributeButton := widget.NewButtonWithIcon("Ban Attribute", theme.CancelIcon(), func(){
|
|
|
|
setEnterReasonAndSubmitReviewPage(window, "Submit Ban Review", "Ban Attribute", "Ban", banAttributeWithReasonFunction, currentPage, refreshPageWithNewContent)
|
|
})
|
|
|
|
banAttributeAndIdentityButton := widget.NewButtonWithIcon("Ban Attribute And Identity", theme.CancelIcon(), func(){
|
|
|
|
setEnterReasonAndSubmitReviewPage(window, "Submit Ban Reviews", "Ban Attribute And Identity", "Ban", banAttributeAndIdentityWithReasonFunction, currentPage, refreshPageWithNewContent)
|
|
})
|
|
|
|
reviewButtonsColumn := getContainerCentered(container.NewGridWithColumns(1, approveAttributeButton, banAttributeButton, banAttributeAndIdentityButton))
|
|
|
|
skipButton := widget.NewButtonWithIcon("Skip", theme.MediaFastForwardIcon(), func(){
|
|
|
|
// This will skip this attribute. It will be moved to the back of the myUnreviewed queue
|
|
err := mySkippedContent.AddAttributeToMySkippedAttributesMap(attributeHash, attributeAuthorIdentityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
refreshPageWithNewContent()
|
|
})
|
|
hideButton := widget.NewButtonWithIcon("Hide", theme.VisibilityOffIcon(), func(){
|
|
setConfirmHideContentPage(window, attributeHash[:], attributeAuthorIdentityHash, currentPage, refreshPageWithNewContent)
|
|
})
|
|
|
|
skipAndHideButtonsColumn := getContainerCentered(container.NewGridWithColumns(1, skipButton, hideButton))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), viewAttributeDetailsButton, widget.NewSeparator(), attributeTitleRow, widget.NewSeparator(), attributeDisplayContainer, widget.NewSeparator(), reviewButtonsColumn, widget.NewSeparator(), skipAndHideButtonsColumn)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page is used by a moderator to browse their unreviewed messages, review their content, and submit a verdict
|
|
func setModerateMessagesPage(window fyne.Window, imageOrText string, messageProvided bool, messageHash [26]byte, previousPage func()){
|
|
|
|
currentPage := func(){setModerateMessagesPage(window, imageOrText, messageProvided, messageHash, previousPage)}
|
|
refreshPageWithNewContent := func(){setModerateMessagesPage(window, imageOrText, false, [26]byte{}, previousPage)}
|
|
|
|
title := getPageTitleCentered("Moderating Messages")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (messageProvided == false){
|
|
|
|
exists, moderatingMessages, err := mySettings.GetSetting("ModerateMessagesOnOffStatus")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (exists == false || moderatingMessages != "On"){
|
|
|
|
description1 := getBoldLabelCentered("You are not moderating messages.")
|
|
description2 := getLabelCentered("You must enable message moderation mode.")
|
|
|
|
enableButton := getWidgetCentered(widget.NewButtonWithIcon("Enable", theme.NavigateNextIcon(), func(){
|
|
setManageModerateMessagesModePage(window, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, enableButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
setLoadingScreen(window, "Moderate Messages", "Loading message...")
|
|
|
|
messageExists, newMessageHash, err := myUnreviewed.GetMyHighestPriorityUnreviewedMessageHash(appNetworkType, imageOrText)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (messageExists == false){
|
|
|
|
description1 := getBoldLabelCentered("No messages remain to moderate.")
|
|
description2 := getLabelCentered("Check back later for new messages.")
|
|
//TODO: Add check for if space is full, and add message to say to increase space allowed for moderation content
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
setModerateMessagesPage(window, imageOrText, true, newMessageHash, previousPage)
|
|
return
|
|
}
|
|
|
|
viewMessageDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("View Message Details", theme.VisibilityIcon(), func(){
|
|
setViewMessageModerationDetailsPage(window, messageHash, currentPage)
|
|
}))
|
|
|
|
//Outputs:
|
|
// -bool: Necessary information found to display message
|
|
// -[16]byte: Message author
|
|
// -[32]byte: Message cipher key
|
|
// -string: Message communication
|
|
// -error
|
|
getMessageMetadata := func()(bool, [16]byte, [32]byte, string, error){
|
|
|
|
messageExists, cipherKeyFound, ableToDecrypt, messageCipherKey, senderIdentityHash, messageCommunication, err := chatMessageStorage.GetDecryptedMessageForModeration(messageHash)
|
|
if (err != nil){ return false, [16]byte{}, [32]byte{}, "", err }
|
|
if (messageExists == false){
|
|
// We cannot review messages which we do not have downloaded
|
|
// Message may have been deleted after earlier check
|
|
return false, [16]byte{}, [32]byte{}, "", nil
|
|
}
|
|
if (cipherKeyFound == false){
|
|
// No valid reviews/reports exist for this message.
|
|
// myUnreviewed should have checked this before.
|
|
// Report could have been deleted.
|
|
return false, [16]byte{}, [32]byte{}, "", nil
|
|
}
|
|
if (ableToDecrypt == false){
|
|
// myUnreviewed should have checked for this
|
|
return false, [16]byte{}, [32]byte{}, "", errors.New("myUnreviewed returning message that cannot be read.")
|
|
}
|
|
|
|
return true, senderIdentityHash, messageCipherKey, messageCommunication, nil
|
|
}
|
|
|
|
messageInfoFound, senderIdentityHash, messageCipherKey, messageCommunication, err := getMessageMetadata()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (messageInfoFound == false){
|
|
// We will refresh page and show loading screen so we can tell if this is happening
|
|
setLoadingScreen(window, "Moderate Messages", "Trying to find message...")
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
refreshPageWithNewContent()
|
|
return
|
|
}
|
|
|
|
messageContentContainer, err := getMessageDisplayForModeration(window, messageCommunication, currentPage)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
appNetworkTypeString := helpers.ConvertByteToString(appNetworkType)
|
|
messageHashHex := encoding.EncodeBytesToHexString(messageHash[:])
|
|
|
|
submitMessageReview := func(verdict string, reasonExists bool, reason string)error{
|
|
|
|
messageCipherKeyHex := encoding.EncodeBytesToHexString(messageCipherKey[:])
|
|
|
|
newReviewMap := map[string]string{
|
|
"NetworkType": appNetworkTypeString,
|
|
"ReviewedHash": messageHashHex,
|
|
"MessageCipherKey": messageCipherKeyHex,
|
|
"Verdict": verdict,
|
|
}
|
|
|
|
if (reasonExists == true){
|
|
newReviewMap["Reason"] = reason
|
|
}
|
|
|
|
myIdentityExists, err := myReviews.CreateAndBroadcastMyReview(newReviewMap)
|
|
if (err != nil) { return err }
|
|
if (myIdentityExists == false) {
|
|
return errors.New("My moderator identity not found when trying to submit review.")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
submitBanIdentityReview := func(reasonExists bool, reason string)error{
|
|
|
|
senderIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(senderIdentityHash)
|
|
if (err != nil) { return err }
|
|
|
|
identityReviewMap := map[string]string{
|
|
"NetworkType": appNetworkTypeString,
|
|
"ReviewedHash": senderIdentityHashString,
|
|
"Verdict": "Ban",
|
|
"ErrantMessages": messageHashHex,
|
|
}
|
|
|
|
if (reasonExists == true){
|
|
identityReviewMap["Reason"] = reason
|
|
}
|
|
|
|
myIdentityExists, err := myReviews.CreateAndBroadcastMyReview(identityReviewMap)
|
|
if (err != nil) { return err }
|
|
if (myIdentityExists == false) {
|
|
return errors.New("My moderator identity not found when trying to submit review.")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
approveMessageWithReasonFunction := func(reasonExists bool, reason string)error{
|
|
|
|
err := submitMessageReview("Approve", reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
banMessageWithReasonFunction := func(reasonExists bool, reason string)error{
|
|
err := submitMessageReview("Ban", reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
banMessageAndIdentityWithReasonFunction := func(reasonExists bool, reason string)error{
|
|
err := submitMessageReview("Ban", reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
err = submitBanIdentityReview(reasonExists, reason)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
approveMessageButton := widget.NewButtonWithIcon("Approve Message", theme.ConfirmIcon(), func(){
|
|
|
|
setEnterReasonAndSubmitReviewPage(window, "Submit Approve Review", "Approve Message", "Approve", approveMessageWithReasonFunction, currentPage, refreshPageWithNewContent)
|
|
})
|
|
banMessageButton := widget.NewButtonWithIcon("Ban Message", theme.CancelIcon(), func(){
|
|
|
|
setEnterReasonAndSubmitReviewPage(window, "Submit Ban Review", "Ban Message", "Ban", banMessageWithReasonFunction, currentPage, refreshPageWithNewContent)
|
|
})
|
|
|
|
banMessageAndSenderButton := widget.NewButtonWithIcon("Ban Message And Sender", theme.CancelIcon(), func(){
|
|
|
|
setEnterReasonAndSubmitReviewPage(window, "Submit Ban Reviews", "Ban Message and Sender", "Ban", banMessageAndIdentityWithReasonFunction, currentPage, refreshPageWithNewContent)
|
|
})
|
|
|
|
reviewButtonsColumn := getContainerCentered(container.NewGridWithColumns(1, approveMessageButton, banMessageButton, banMessageAndSenderButton))
|
|
|
|
skipButton := widget.NewButtonWithIcon("Skip", theme.MediaFastForwardIcon(), func(){
|
|
|
|
// This will skip this attribute. It will be moved to the back of the myUnreviewed queue
|
|
err := mySkippedContent.AddMessageToMySkippedMessagesMap(messageHash, senderIdentityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
refreshPageWithNewContent()
|
|
})
|
|
hideButton := widget.NewButtonWithIcon("Hide", theme.VisibilityOffIcon(), func(){
|
|
setConfirmHideContentPage(window, messageHash[:], senderIdentityHash, currentPage, refreshPageWithNewContent)
|
|
})
|
|
|
|
skipAndHideButtonsColumn := getContainerCentered(container.NewGridWithColumns(1, skipButton, hideButton))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), viewMessageDetailsButton, widget.NewSeparator(), messageContentContainer, widget.NewSeparator(), reviewButtonsColumn, widget.NewSeparator(), skipAndHideButtonsColumn)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
// This will hide the profile/message/attribute permanently so it does not show up anymore
|
|
// This is useful if the content is in a language the user does not understand
|
|
func setConfirmHideContentPage(window fyne.Window, contentHash []byte, authorIdentityHash [16]byte, previousPage func(), pageToVisitAfter func()){
|
|
|
|
currentPage := func(){setConfirmHideContentPage(window, contentHash, authorIdentityHash, previousPage, pageToVisitAfter)}
|
|
|
|
contentType, err := helpers.GetContentTypeFromContentHash(contentHash)
|
|
if (err != nil){
|
|
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
|
setErrorEncounteredPage(window, errors.New("setConfirmHideContentPage called with invalid contentHash: " + contentHashHex), previousPage)
|
|
return
|
|
}
|
|
|
|
if (contentType != "Message" && contentType != "Profile" && contentType != "Attribute"){
|
|
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
|
setErrorEncounteredPage(window, errors.New("setConfirmHideContentPage called with invalid contentHash: " + contentHashHex), previousPage)
|
|
return
|
|
}
|
|
|
|
title := getPageTitleCentered("Confirm Hide " + contentType)
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description1 := getBoldLabelCentered("Confirm Hide " + contentType + "?")
|
|
|
|
description2 := getLabelCentered("This will prevent this " + contentType + " from showing up in your moderation queue.")
|
|
description3 := getLabelCentered("This is useful when you don't want to review the " + contentType + ".")
|
|
description4 := getLabelCentered("For example, the " + contentType + " may be written in a language you don't understand.")
|
|
|
|
confirmButton := getWidgetCentered(widget.NewButtonWithIcon("Confirm", theme.ConfirmIcon(), func(){
|
|
|
|
if (contentType == "Message"){
|
|
|
|
if (len(contentHash) != 26){
|
|
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
|
setErrorEncounteredPage(window, errors.New("GetContentTypeFromContentHash returning Message for different length content hash: " + contentHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
messageHash := [26]byte(contentHash)
|
|
|
|
err := myHiddenContent.AddMessageToMyHiddenMessagesMap(messageHash, authorIdentityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
} else if (contentType == "Profile"){
|
|
|
|
if (len(contentHash) != 28){
|
|
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
|
setErrorEncounteredPage(window, errors.New("GetContentTypeFromContentHash returning Profile for different length content hash: " + contentHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
profileHash := [28]byte(contentHash)
|
|
|
|
err := myHiddenContent.AddProfileToMyHiddenProfilesMap(profileHash, authorIdentityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
|
|
} else if (contentType == "Attribute"){
|
|
|
|
if (len(contentHash) != 27){
|
|
contentHashHex := encoding.EncodeBytesToHexString(contentHash)
|
|
setErrorEncounteredPage(window, errors.New("GetContentTypeFromContentHash returning Attribute for different length content hash: " + contentHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
attributeHash := [27]byte(contentHash)
|
|
|
|
err := myHiddenContent.AddAttributeToMyHiddenAttributesMap(attributeHash, authorIdentityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
}
|
|
|
|
pageToVisitAfter()
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, confirmButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setEnterReasonAndSubmitReviewPage(window fyne.Window, pageTitle string, actionName string, verdict string, submitFunctionWithReason func(bool, string)error, previousPage func(), pageToVisitAfter func()){
|
|
|
|
title := getPageTitleCentered(pageTitle)
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
actionLabel := getItalicLabelCentered("Action:")
|
|
actionDescription := getBoldLabelCentered(actionName)
|
|
|
|
enterReasonLabel := getLabelCentered("Enter " + verdict + " Reason (Optional):")
|
|
|
|
reasonEntry := widget.NewMultiLineEntry()
|
|
reasonEntry.SetPlaceHolder("Enter reason...")
|
|
|
|
reasonEntryBoxed := getWidgetBoxed(reasonEntry)
|
|
|
|
submitButton := getWidgetCentered(widget.NewButtonWithIcon("Submit", theme.ConfirmIcon(), func(){
|
|
|
|
reason := reasonEntry.Text
|
|
|
|
if (reason == ""){
|
|
err := submitFunctionWithReason(false, "")
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
} else {
|
|
err := submitFunctionWithReason(true, reason)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
}
|
|
|
|
pageToVisitAfter()
|
|
}))
|
|
|
|
widener := widget.NewLabel(" ")
|
|
|
|
submitButtonWithWidener := container.NewGridWithColumns(1, submitButton, widener)
|
|
|
|
entryWithSubmitButton := getContainerCentered(container.NewGridWithColumns(1, reasonEntryBoxed, submitButtonWithWidener))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), actionLabel, actionDescription, widget.NewSeparator(), enterReasonLabel, entryWithSubmitButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setViewProfileForModerationPage(window fyne.Window, profileHash [28]byte, previousPage func()){
|
|
|
|
currentPage := func(){setViewProfileForModerationPage(window, profileHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Profile")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
profileHashTitle := widget.NewLabel("Profile Hash:")
|
|
|
|
profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
|
|
|
|
profileHashTrimmed, _, err := helpers.TrimAndFlattenString(profileHashHex, 10)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
profileHashLabel := getBoldLabel(profileHashTrimmed)
|
|
viewProfileHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewContentHashPage(window, "Profile", profileHash[:], currentPage)
|
|
})
|
|
profileHashRow := container.NewHBox(layout.NewSpacer(), profileHashTitle, profileHashLabel, viewProfileHashButton, layout.NewSpacer())
|
|
|
|
getProfileDisplayContainer := func()(*fyne.Container, error){
|
|
|
|
profileExists, profileBytes, err := profileStorage.GetStoredProfile(profileHash)
|
|
if (err != nil) { return nil, err }
|
|
if (profileExists == false){
|
|
description1 := getBoldLabelCentered("Profile not downloaded.")
|
|
description2 := getLabelCentered("Try to download?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButton("Download", func(){
|
|
setDownloadContentFromHashPage(window, "Profile", profileHash[:], currentPage)
|
|
}))
|
|
|
|
content := container.NewVBox(description1, description2, downloadButton)
|
|
return content, nil
|
|
}
|
|
|
|
ableToRead, currentProfileHash, profileVersion, _, profileIdentityHash, _, _, rawProfileMap, err := readProfiles.ReadProfileAndHash(false, profileBytes)
|
|
if (err != nil) { return nil, err }
|
|
if (ableToRead == false){
|
|
return nil, errors.New("Database corrupt: Contains invalid profile.")
|
|
}
|
|
if (profileHash != currentProfileHash) {
|
|
return nil, errors.New("Database corrupt: Profile hash does not match entry key")
|
|
}
|
|
|
|
profileAuthorLabel := widget.NewLabel("Profile Author:")
|
|
|
|
profileIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(profileIdentityHash)
|
|
if (err != nil){ return nil, err }
|
|
|
|
profileIdentityHashLabel := getBoldLabel(profileIdentityHashString)
|
|
profileIdentityHashRow := container.NewHBox(layout.NewSpacer(), profileAuthorLabel, profileIdentityHashLabel, layout.NewSpacer())
|
|
|
|
getAnyProfileAttributeFunction, err := calculatedAttributes.GetRetrieveAnyProfileAttributeIncludingCalculatedFunction(profileVersion, rawProfileMap)
|
|
if (err != nil) { return nil, err }
|
|
|
|
viewProfileButton := getWidgetCentered(widget.NewButtonWithIcon("View Profile", theme.VisibilityIcon(), func(){
|
|
setViewUserProfilePage(window, false, profileHash, 0, getAnyProfileAttributeFunction, currentPage)
|
|
}))
|
|
|
|
profileDisplayWithInfo := container.NewVBox(profileIdentityHashRow, viewProfileButton)
|
|
|
|
return profileDisplayWithInfo, nil
|
|
}
|
|
|
|
profileDisplayContainer, err := getProfileDisplayContainer()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), profileHashRow, profileDisplayContainer)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
// This page allows a moderator to view a profile attribute value
|
|
// It is different from setModerateProfileAttributesPage,
|
|
// which allows the moderator to review the attribute, provides skip/hide buttons, and serves
|
|
// the next attribute to review
|
|
func setViewProfileAttributeForModerationPage(window fyne.Window, attributeHash [27]byte, previousPage func()){
|
|
|
|
currentPage := func(){setViewProfileAttributeForModerationPage(window, attributeHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Profile Attribute")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
attributeHashTitle := widget.NewLabel("Attribute Hash:")
|
|
|
|
attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])
|
|
|
|
attributeHashTrimmed, _, err := helpers.TrimAndFlattenString(attributeHashHex, 10)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
attributeHashLabel := getBoldLabel(attributeHashTrimmed)
|
|
viewAttributeHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewContentHashPage(window, "Attribute", attributeHash[:], currentPage)
|
|
})
|
|
attributeHashRow := container.NewHBox(layout.NewSpacer(), attributeHashTitle, attributeHashLabel, viewAttributeHashButton, layout.NewSpacer())
|
|
|
|
// We have to find the profile hash that the attribute belongs to
|
|
// If we cannot find any profiles with this attribute, we will offer the user to try to download profiles for this attribute hash
|
|
|
|
attributeMetadataFound, attributeIdentifier, _, _, _, profileFound, _, profileBytes, err := profileStorage.GetProfileAttributeMetadataAndProfile(attributeHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (attributeMetadataFound == false || profileFound == false){
|
|
|
|
description1 := getBoldLabelCentered("You do not have this profile attribute downloaded.")
|
|
description2 := getLabelCentered("Try to download it?")
|
|
description3 := getLabelCentered("It may not exist on the network anymore.")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), attributeHashRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
attributeName, err := profileFormat.GetAttributeNameFromAttributeIdentifier(attributeIdentifier)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
attributeTitle, _, _, _, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
attributeNameLabel := widget.NewLabel("Attribute Name:")
|
|
attributeTitleLabel := getBoldLabel(attributeTitle)
|
|
attributeTitleRow := container.NewHBox(layout.NewSpacer(), attributeNameLabel, attributeTitleLabel, layout.NewSpacer())
|
|
|
|
attributeDisplayContainer, err := getProfileAttributeDisplayForModeration(window, attributeName, attributeIdentifier, profileBytes, currentPage)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), attributeHashRow, widget.NewSeparator(), attributeTitleRow, widget.NewSeparator(), attributeDisplayContainer)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setViewMessageForModerationPage(window fyne.Window, messageHash [26]byte, previousPage func()){
|
|
|
|
currentPage := func(){setViewMessageForModerationPage(window, messageHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Message")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
messageHashHex := encoding.EncodeBytesToHexString(messageHash[:])
|
|
|
|
messageHashTitle := widget.NewLabel("Message Hash:")
|
|
messageHashTrimmed, _, err := helpers.TrimAndFlattenString(messageHashHex, 10)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
messageHashLabel := getBoldLabel(messageHashTrimmed)
|
|
viewMessageHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewContentHashPage(window, "Message", messageHash[:], currentPage)
|
|
})
|
|
messageHashRow := container.NewHBox(layout.NewSpacer(), messageHashTitle, messageHashLabel, viewMessageHashButton, layout.NewSpacer())
|
|
|
|
messageExists, cipherKeyFound, ableToDecrypt, _, senderIdentityHash, messageCommunication, err := chatMessageStorage.GetDecryptedMessageForModeration(messageHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (messageExists == false){
|
|
description1 := getBoldLabelCentered("Message not downloaded.")
|
|
description2 := getLabelCentered("Try to download?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButton("Download", func(){
|
|
setDownloadContentFromHashPage(window, "Message", messageHash[:], currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), description1, description2, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
if (cipherKeyFound == false){
|
|
// No valid reviews/reports exist for message hash. User can try to download
|
|
description1 := getBoldLabelCentered("No reviews or reports for message found.")
|
|
description2 := getLabelCentered("Without a review/report, the contents are encrypted.")
|
|
description3 := getLabelCentered("Try to download reviews/reports?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, messageHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (ableToDecrypt == false){
|
|
description1 := getBoldLabelCentered("Message is corrupt.")
|
|
description2 := getLabelCentered("It was created by a malicious user.")
|
|
description3 := getLabelCentered("It cannot be decrypted.")
|
|
description4 := getLabelCentered("No moderator should be able to approve it.")
|
|
description5 := getLabelCentered("Any moderators who have approved the message will be automatically banned.")
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), description1, description2, description3, description4, description5)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
senderIdentityHashTitle := widget.NewLabel("Sender Identity Hash:")
|
|
|
|
senderIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(senderIdentityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
senderIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(senderIdentityHashString, 10)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
senderIdentityHashLabel := getBoldLabel(senderIdentityHashTrimmed)
|
|
viewSenderIdentityHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewIdentityHashPage(window, senderIdentityHash, currentPage)
|
|
})
|
|
senderIdentityHashRow := container.NewHBox(layout.NewSpacer(), senderIdentityHashTitle, senderIdentityHashLabel, viewSenderIdentityHashButton, layout.NewSpacer())
|
|
|
|
messageContentLabel := getBoldItalicLabelCentered("Message Content:")
|
|
|
|
messageContentContainer, err := getMessageDisplayForModeration(window, messageCommunication, currentPage)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), senderIdentityHashRow, widget.NewSeparator(), messageContentLabel, messageContentContainer)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
// This function will return a container to display a profile attribute
|
|
func getProfileAttributeDisplayForModeration(window fyne.Window, attributeName string, attributeIdentifier int, profileBytes []byte, currentPage func())(*fyne.Container, error){
|
|
|
|
ableToRead, _, _, _, _, profileIsDisabled, rawProfileMap, err := readProfiles.ReadProfile(false, profileBytes)
|
|
if (err != nil) { return nil, err }
|
|
if (ableToRead == false){
|
|
return nil, errors.New("getProfileAttributeDisplayForModeration called with invalid profile.")
|
|
}
|
|
|
|
if (profileIsDisabled == true){
|
|
return nil, errors.New("getProfileAttributeDisplayForModeration called with disabled profile.")
|
|
}
|
|
|
|
exists, attributeValue, err := readProfiles.GetFormattedProfileAttributeFromRawProfileMap(rawProfileMap, attributeName)
|
|
if (err != nil) { return nil, err }
|
|
if (exists == false){
|
|
attributeIdentifierString := helpers.ConvertIntToString(attributeIdentifier)
|
|
return nil, errors.New("getProfileAttributeDisplayForModeration called with profile missing attribute: " + attributeIdentifierString)
|
|
}
|
|
|
|
_, _, formatValueFunction, attributeUnits, _, err := attributeDisplay.GetProfileAttributeDisplayInfo(attributeName)
|
|
if (err != nil) { return nil, err }
|
|
|
|
if (attributeName == "Photos"){
|
|
|
|
photosBase64List := strings.Split(attributeValue, "+")
|
|
if (len(photosBase64List) == 0) {
|
|
return nil, errors.New("Verified mate profile has an empty photos list")
|
|
}
|
|
|
|
getNumberOfImagesGridColumns := func()int{
|
|
if (len(photosBase64List) == 1){
|
|
return 1
|
|
}
|
|
if (len(photosBase64List) == 2){
|
|
return 2
|
|
}
|
|
return 3
|
|
}
|
|
|
|
numberOfImagesGridColumns := getNumberOfImagesGridColumns()
|
|
|
|
imagesGrid := container.NewGridWithColumns(numberOfImagesGridColumns)
|
|
|
|
for _, base64Photo := range photosBase64List{
|
|
|
|
goImage, err := imagery.ConvertWebpBase64StringToImageObject(base64Photo)
|
|
if (err != nil) { return nil, err }
|
|
|
|
viewImageButton := widget.NewButtonWithIcon("", theme.ZoomInIcon(), func(){
|
|
setViewFullpageImagePage(window, goImage, currentPage)
|
|
})
|
|
|
|
fyneImage := canvas.NewImageFromImage(goImage)
|
|
fyneImage.FillMode = canvas.ImageFillContain
|
|
imageSize := getCustomFyneSize(10)
|
|
fyneImage.SetMinSize(imageSize)
|
|
|
|
viewImageButtonCentered := getWidgetCentered(viewImageButton)
|
|
|
|
imageWithFullpageButton := container.NewVBox(fyneImage, viewImageButtonCentered)
|
|
|
|
imagesGrid.Add(imageWithFullpageButton)
|
|
}
|
|
|
|
imagesGridCentered := getContainerCentered(imagesGrid)
|
|
|
|
return imagesGridCentered, nil
|
|
}
|
|
|
|
//TODO: Add more attributes that need a custom display, such as 23andMe_AncestryComposition
|
|
|
|
attributeValueFormatted, err := formatValueFunction(attributeValue)
|
|
if (err != nil) { return nil, err }
|
|
|
|
attributeValueTrimmed, _, err := helpers.TrimAndFlattenString(attributeValueFormatted, 20)
|
|
if (err != nil) { return nil, err }
|
|
|
|
viewTextButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Attribute", attributeValueFormatted, false, currentPage)
|
|
})
|
|
|
|
valueLabel := widget.NewLabel("Value:")
|
|
|
|
attributeValueLabel := getBoldLabel(attributeValueTrimmed + " " + attributeUnits)
|
|
|
|
attributeValueRow := container.NewHBox(layout.NewSpacer(), valueLabel, attributeValueLabel, viewTextButton, layout.NewSpacer())
|
|
|
|
return attributeValueRow, nil
|
|
}
|
|
|
|
func getMessageDisplayForModeration(window fyne.Window, messageCommunication string, currentPage func())(*fyne.Container, error){
|
|
|
|
isImageMessage := strings.HasPrefix(messageCommunication, ">!>Photo=")
|
|
if (isImageMessage == true){
|
|
|
|
imageBase64Webp := strings.TrimPrefix(messageCommunication, ">!>Photo=")
|
|
|
|
goImage, err := imagery.ConvertWEBPBase64StringToCroppedDownsizedImageObject(imageBase64Webp)
|
|
if (err != nil) { return nil, err }
|
|
|
|
viewImageButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.ZoomInIcon(), func(){
|
|
setViewFullpageImagePage(window, goImage, currentPage)
|
|
}))
|
|
|
|
fyneImage := canvas.NewImageFromImage(goImage)
|
|
fyneImage.FillMode = canvas.ImageFillContain
|
|
imageSize := getCustomFyneSize(20)
|
|
fyneImage.SetMinSize(imageSize)
|
|
|
|
imageCentered := getFyneImageCentered(fyneImage)
|
|
|
|
contentDisplayContainer := container.NewVBox(imageCentered, viewImageButton)
|
|
|
|
return contentDisplayContainer, nil
|
|
}
|
|
//imageOrText == "Text"
|
|
|
|
communicationTrimmed, _, err := helpers.TrimAndFlattenString(messageCommunication, 25)
|
|
if (err != nil) { return nil, err }
|
|
|
|
communicationLabel := getLabelCentered(communicationTrimmed)
|
|
|
|
viewCommunicationButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Message", messageCommunication, false, currentPage)
|
|
})
|
|
|
|
viewTextRow := container.NewHBox(layout.NewSpacer(), communicationLabel, viewCommunicationButton, layout.NewSpacer())
|
|
|
|
return viewTextRow, nil
|
|
}
|
|
|
|
func setDownloadContentFromHashPage(window fyne.Window, contentType string, contentHash []byte, previousPage func()){
|
|
|
|
//TODO: Make sure the content has not expired from the network, and is not banned (in which case it will not exist on the network)
|
|
}
|
|
|
|
func setModerateIdentitiesPage(window fyne.Window, previousPage func()){
|
|
|
|
currentPage := func(){setModerateIdentitiesPage(window, previousPage)}
|
|
|
|
title := getPageTitleCentered("Moderate Identities")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description := getLabelCentered("Choose a method to moderate user identities.")
|
|
|
|
viewControversialContentButton := widget.NewButton("View Controversial Content", func(){
|
|
|
|
_ = mySettings.SetSetting("ViewedContentSortByAttribute", "Controversy")
|
|
_ = mySettings.SetSetting("ViewedContentSortDirection", "Descending")
|
|
_ = mySettings.SetSetting("ViewedContentGeneratedStatus", "No")
|
|
_ = mySettings.SetSetting("ViewedContentViewIndex", "0")
|
|
|
|
setBrowseContentPage(window, currentPage)
|
|
})
|
|
|
|
viewControversialModeratorsButton := widget.NewButton("View Controversial Moderators", func(){
|
|
|
|
_ = mySettings.SetSetting("ViewedModeratorsSortByAttribute", "Controversy")
|
|
_ = mySettings.SetSetting("ViewedModeratorsSortDirection", "Descending")
|
|
_ = mySettings.SetSetting("ViewedModeratorsGeneratedStatus", "No")
|
|
_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")
|
|
|
|
setViewModeratorsPage(window, currentPage)
|
|
})
|
|
|
|
viewMostBannedModeratorsButton := widget.NewButton("View Most Banned Moderators", func(){
|
|
|
|
_ = mySettings.SetSetting("ViewedModeratorsSortByAttribute", "BanAdvocates")
|
|
_ = mySettings.SetSetting("ViewedModeratorsSortDirection", "Descending")
|
|
_ = mySettings.SetSetting("ViewedModeratorsGeneratedStatus", "No")
|
|
_ = mySettings.SetSetting("ViewedModeratorsViewIndex", "0")
|
|
|
|
setViewModeratorsPage(window, currentPage)
|
|
})
|
|
|
|
viewMostReportedModeratorsButton := widget.NewButton("View Most Reported Moderators", func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
|
|
viewMostBannedHostsButton := widget.NewButton("View Most Banned Hosts", func(){
|
|
|
|
_ = mySettings.SetSetting("ViewedHostsSortByAttribute", "BanAdvocates")
|
|
_ = mySettings.SetSetting("ViewedHostsSortDirection", "Descending")
|
|
_ = mySettings.SetSetting("ViewedHostsGeneratedStatus", "No")
|
|
_ = mySettings.SetSetting("ViewedHostsViewIndex", "0")
|
|
|
|
setViewHostsPage(window, currentPage)
|
|
})
|
|
|
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, viewControversialContentButton, viewControversialModeratorsButton, viewMostBannedModeratorsButton, viewMostReportedModeratorsButton, viewMostBannedHostsButton))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, buttonsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page allows moderators to view the moderation status of an identity
|
|
func setViewIdentityModerationDetailsPage(window fyne.Window, identityHash [16]byte, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Moderation Details", "Loading details...")
|
|
|
|
currentPage := func(){setViewIdentityModerationDetailsPage(window, identityHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Moderation Details - Identity")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
identityHashLabel := widget.NewLabel("Identity Hash:")
|
|
|
|
identityHashString, _, err := identity.EncodeIdentityHashBytesToString(identityHash)
|
|
if (err != nil){
|
|
identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
|
|
setErrorEncounteredPage(window, errors.New("setViewIdentityModerationDetailsPage called with invalid identity hash: " + identityHashHex), previousPage)
|
|
return
|
|
}
|
|
|
|
identityHashTrimmed, _, err := helpers.TrimAndFlattenString(identityHashString, 10)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
viewIdentityHashButton := widget.NewButton(identityHashTrimmed, func(){
|
|
setViewIdentityHashPage(window, identityHash, currentPage)
|
|
})
|
|
|
|
identityHashRow := container.NewHBox(layout.NewSpacer(), identityHashLabel, viewIdentityHashButton, layout.NewSpacer())
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
downloadingRequiredReviews, parametersExist, identityIsBannedConsensus, numberOfBanAdvocates, banScoreSum, _, err := verifiedVerdict.GetVerifiedIdentityVerdict(identityHash, appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
getModeratorConsensusRow := func()*fyne.Container{
|
|
|
|
moderatorConsensusLabel := widget.NewLabel("Moderator Consensus:")
|
|
|
|
if (downloadingRequiredReviews == false || parametersExist == false){
|
|
|
|
verdictConsensusLabel := getBoldLabel("Unknown")
|
|
moderatorConsensusRow := container.NewHBox(layout.NewSpacer(), moderatorConsensusLabel, verdictConsensusLabel, layout.NewSpacer())
|
|
|
|
return moderatorConsensusRow
|
|
}
|
|
|
|
getConsensusVerdictString := func()string{
|
|
if (identityIsBannedConsensus == false){
|
|
return "Not Banned"
|
|
}
|
|
return "Banned"
|
|
}
|
|
consensusVerdictString := getConsensusVerdictString()
|
|
|
|
verdictConsensusLabel := getBoldLabel(consensusVerdictString)
|
|
moderatorConsensusRow := container.NewHBox(layout.NewSpacer(), moderatorConsensusLabel, verdictConsensusLabel, layout.NewSpacer())
|
|
|
|
return moderatorConsensusRow
|
|
}
|
|
|
|
moderatorConsensusRow := getModeratorConsensusRow()
|
|
|
|
getMyVerdict := func()(string, error){
|
|
|
|
myIdentityExists, iHaveBanned, err := myReviews.GetMyNewestIdentityModerationVerdict(identityHash, appNetworkType)
|
|
if (err != nil) { return "", err }
|
|
if (myIdentityExists == false || iHaveBanned == false){
|
|
return "None", nil
|
|
}
|
|
return "Ban", nil
|
|
}
|
|
|
|
myVerdict, err := getMyVerdict()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
myVerdictLabel := widget.NewLabel("My Verdict:")
|
|
myVerdictText := getBoldLabel(myVerdict)
|
|
|
|
//TODO: Add button to change my verdict, and see when my verdict was authored.
|
|
|
|
myVerdictRow := container.NewHBox(layout.NewSpacer(), myVerdictLabel, myVerdictText, layout.NewSpacer())
|
|
|
|
//TODO: Add button to view identity sticky status and verdict history
|
|
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getBoldLabelCentered("This identity is outside of your moderation range.")
|
|
description2 := getLabelCentered("We cannot determine the moderation consensus.")
|
|
description3 := getLabelCentered("Do you want to download the reviews to view the consensus?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, identityHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), identityHashRow, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
|
|
description1 := getLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for the parameters to be downloaded.")
|
|
|
|
viewStatusButton := getWidgetCentered(widget.NewButtonWithIcon("View Status", theme.VisibilityIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), identityHashRow, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, viewStatusButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
numberBanString := helpers.ConvertIntToString(numberOfBanAdvocates)
|
|
banAdvocatesLabel := widget.NewLabel("Ban Advocates:")
|
|
numberBanLabel := getBoldLabel(numberBanString)
|
|
numberBanRow := container.NewHBox(layout.NewSpacer(), banAdvocatesLabel, numberBanLabel, layout.NewSpacer())
|
|
|
|
banScoreString := helpers.ConvertFloat64ToStringRounded(banScoreSum, 2)
|
|
banScoreLabel := getLabelCentered("Ban Score:")
|
|
banScoreText := getBoldLabel(banScoreString)
|
|
banScoreRow := container.NewHBox(layout.NewSpacer(), banScoreLabel, banScoreText, layout.NewSpacer())
|
|
|
|
viewReviewerVerdictsButton := getWidgetCentered(widget.NewButton("View Reviewers", func(){
|
|
setViewIdentityReviewerVerdictsPage(window, identityHash, 0, currentPage)
|
|
}))
|
|
|
|
numberOfReports, err := reportStorage.GetNumberOfReportsForReportedHash(identityHash[:], appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
numberOfReportsString := helpers.ConvertInt64ToString(numberOfReports)
|
|
numberOfReportsLabel := widget.NewLabel("Number of reports:")
|
|
numberOfReportsText := getBoldLabel(numberOfReportsString)
|
|
numberOfReportsRow := container.NewHBox(layout.NewSpacer(), numberOfReportsLabel, numberOfReportsText, layout.NewSpacer())
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), identityHashRow, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), numberBanRow, banScoreRow, viewReviewerVerdictsButton, widget.NewSeparator(), numberOfReportsRow)
|
|
|
|
if (numberOfReports != 0){
|
|
viewReportsButton := getWidgetCentered(widget.NewButton("View Reports", func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
page.Add(viewReportsButton)
|
|
}
|
|
page.Add(widget.NewSeparator())
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page.Add(updateButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page allows moderators to view the moderation status of a profile
|
|
func setViewProfileModerationDetailsPage(window fyne.Window, profileHash [28]byte, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Moderation Details", "Loading details...")
|
|
|
|
currentPage := func(){setViewProfileModerationDetailsPage(window, profileHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Moderation Details - Profile")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
profileHashLabel := widget.NewLabel("Profile Hash:")
|
|
|
|
profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
|
|
|
|
profileHashTrimmed, _, err := helpers.TrimAndFlattenString(profileHashHex, 6)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
viewProfileHashButton := widget.NewButton(profileHashTrimmed, func(){
|
|
setViewContentHashPage(window, "Profile", profileHash[:], currentPage)
|
|
})
|
|
|
|
profileHashRow := container.NewHBox(layout.NewSpacer(), profileHashLabel, viewProfileHashButton, layout.NewSpacer())
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
profileIsDisabled, profileMetadataIsKnown, _, profileNetworkType, profileIdentityHash, _, downloadingRequiredReviews, parametersExist, profileVerdict, numberOfApproveAdvocates, numberOfBanAdvocates, approveScoreSum, banScoreSum, _, _, _, _, _, _, _, _, _, err := verifiedVerdict.GetVerifiedProfileVerdict(profileHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (profileMetadataIsKnown == true){
|
|
|
|
if (profileNetworkType != appNetworkType){
|
|
setErrorEncounteredPage(window, errors.New("setViewProfileModerationDetailsPage called with profile for different network type."), previousPage)
|
|
return
|
|
}
|
|
}
|
|
|
|
getProfileAuthorRow := func()(*fyne.Container, error){
|
|
|
|
profileAuthorLabel := widget.NewLabel("Profile Author:")
|
|
|
|
if (profileMetadataIsKnown == false){
|
|
|
|
unknownLabel := getBoldLabel("Unknown")
|
|
|
|
profileAuthorRow := container.NewHBox(layout.NewSpacer(), profileAuthorLabel, unknownLabel, layout.NewSpacer())
|
|
|
|
return profileAuthorRow, nil
|
|
}
|
|
|
|
profileIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(profileIdentityHash)
|
|
if (err != nil){ return nil, err }
|
|
|
|
profileIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(profileIdentityHashString, 10)
|
|
if (err != nil){ return nil, err }
|
|
|
|
viewProfileIdentityHashButton := widget.NewButton(profileIdentityHashTrimmed, func(){
|
|
setViewIdentityModerationDetailsPage(window, profileIdentityHash, currentPage)
|
|
})
|
|
|
|
profileAuthorRow := container.NewHBox(layout.NewSpacer(), profileAuthorLabel, viewProfileIdentityHashButton, layout.NewSpacer())
|
|
|
|
return profileAuthorRow, nil
|
|
}
|
|
|
|
profileAuthorRow, err := getProfileAuthorRow()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (profileIsDisabled == true){
|
|
|
|
description1 := getBoldLabelCentered("This profile is disabled.")
|
|
description2 := getLabelCentered("It cannot be banned.")
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), profileHashRow, widget.NewSeparator(), profileAuthorRow, widget.NewSeparator(), description1, description2)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
getModeratorConsensusRow := func()*fyne.Container{
|
|
|
|
moderatorConsensusLabel := widget.NewLabel("Moderator Consensus:")
|
|
|
|
if (profileMetadataIsKnown == false || downloadingRequiredReviews == false || parametersExist == false){
|
|
|
|
verdictConsensusLabel := getBoldLabel("Unknown")
|
|
|
|
moderatorConsensusRow := container.NewHBox(layout.NewSpacer(), moderatorConsensusLabel, verdictConsensusLabel, layout.NewSpacer())
|
|
|
|
return moderatorConsensusRow
|
|
}
|
|
|
|
verdictConsensusLabel := getBoldLabel(profileVerdict)
|
|
|
|
moderatorConsensusRow := container.NewHBox(layout.NewSpacer(), moderatorConsensusLabel, verdictConsensusLabel, layout.NewSpacer())
|
|
|
|
return moderatorConsensusRow
|
|
}
|
|
|
|
moderatorConsensusRow := getModeratorConsensusRow()
|
|
|
|
getMyVerdict := func()(string, error){
|
|
|
|
if (profileIsDisabled == true){
|
|
return "None", nil
|
|
}
|
|
|
|
myIdentityExists, profileIsDisabledB, profileMetadataExists, myReviewExists, myReviewVerdict, err := myReviews.GetMyNewestProfileModerationVerdict(profileHash, true)
|
|
if (err != nil) { return "", err }
|
|
if (myIdentityExists == false){
|
|
return "None", nil
|
|
}
|
|
if (profileIsDisabled != profileIsDisabledB){
|
|
return "", errors.New("GetMyNewestProfileModerationVerdict returning different profileIsDisabled status than GetVerifiedProfileVerdict.")
|
|
}
|
|
if (profileMetadataExists == false){
|
|
return "Unknown", nil
|
|
}
|
|
if (myReviewExists == false){
|
|
return "None", nil
|
|
}
|
|
|
|
return myReviewVerdict, nil
|
|
}
|
|
|
|
myVerdict, err := getMyVerdict()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
myVerdictLabel := widget.NewLabel("My Verdict:")
|
|
myVerdictText := getBoldLabel(myVerdict)
|
|
|
|
myVerdictRow := container.NewHBox(layout.NewSpacer(), myVerdictLabel, myVerdictText, layout.NewSpacer())
|
|
|
|
//TODO: Add button to view profile sticky status and verdict history
|
|
|
|
if (profileMetadataIsKnown == false){
|
|
// We do not have the required profile
|
|
// We can attempt to download it.
|
|
|
|
description1 := getLabelCentered("This profile is not downloaded.")
|
|
description2 := getLabelCentered("It must be downloaded to know its moderation status.")
|
|
description3 := getLabelCentered("You can try to download it, but it may have been deleted from the network.")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
//TODO: Add a way to also download profile's reviews/reports at the same time so we can quickly determine verdict
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), profileHashRow, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
viewProfileButton := getWidgetCentered(widget.NewButtonWithIcon("View Profile", theme.VisibilityIcon(), func(){
|
|
setViewProfileForModerationPage(window, profileHash, currentPage)
|
|
}))
|
|
|
|
viewAttributesButton := getWidgetCentered(widget.NewButtonWithIcon("View Attributes", theme.VisibilityIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getLabelCentered("This profile is outside of your moderation range.")
|
|
description2 := getLabelCentered("We cannot determine the moderation consensus.")
|
|
description3 := getLabelCentered("Do you want to download the reviews to view the consensus?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, profileHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), profileHashRow, widget.NewSeparator(), profileAuthorRow, viewProfileButton, widget.NewSeparator(), viewAttributesButton, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
|
|
description1 := getLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for the parameters to be downloaded.")
|
|
|
|
viewStatusButton := getWidgetCentered(widget.NewButtonWithIcon("View Status", theme.VisibilityIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), profileHashRow, widget.NewSeparator(), profileAuthorRow, widget.NewSeparator(), viewProfileButton, widget.NewSeparator(), viewAttributesButton, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, viewStatusButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
numberApproveString := helpers.ConvertIntToString(numberOfApproveAdvocates)
|
|
approveAdvocatesLabel := widget.NewLabel("Approve Advocates:")
|
|
numberApproveLabel := getBoldLabel(numberApproveString)
|
|
numberApproveRow := container.NewHBox(layout.NewSpacer(), approveAdvocatesLabel, numberApproveLabel, layout.NewSpacer())
|
|
|
|
numberBanString := helpers.ConvertIntToString(numberOfBanAdvocates)
|
|
banAdvocatesLabel := widget.NewLabel("Ban Advocates:")
|
|
numberBanLabel := getBoldLabel(numberBanString)
|
|
numberBanRow := container.NewHBox(layout.NewSpacer(), banAdvocatesLabel, numberBanLabel, layout.NewSpacer())
|
|
|
|
approveScoreString := helpers.ConvertFloat64ToStringRounded(approveScoreSum, 2)
|
|
approveScoreLabel := getLabelCentered("Approve Score:")
|
|
approveScoreText := getBoldLabel(approveScoreString)
|
|
approveScoreRow := container.NewHBox(layout.NewSpacer(), approveScoreLabel, approveScoreText, layout.NewSpacer())
|
|
|
|
banScoreString := helpers.ConvertFloat64ToStringRounded(banScoreSum, 2)
|
|
banScoreLabel := getLabelCentered("Ban Score:")
|
|
banScoreText := getBoldLabel(banScoreString)
|
|
banScoreRow := container.NewHBox(layout.NewSpacer(), banScoreLabel, banScoreText, layout.NewSpacer())
|
|
|
|
viewReviewerVerdictsButton := getWidgetCentered(widget.NewButton("View Reviewers", func(){
|
|
setViewProfileReviewerVerdictsPage(window, profileHash, 0, currentPage)
|
|
}))
|
|
|
|
numberOfReports, err := reportStorage.GetNumberOfReportsForReportedHash(profileHash[:], appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
numberOfReportsString := helpers.ConvertInt64ToString(numberOfReports)
|
|
numberOfReportsLabel := widget.NewLabel("Number of reports:")
|
|
numberOfReportsText := getBoldLabel(numberOfReportsString)
|
|
numberOfReportsRow := container.NewHBox(layout.NewSpacer(), numberOfReportsLabel, numberOfReportsText, layout.NewSpacer())
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), profileHashRow, widget.NewSeparator(), profileAuthorRow, widget.NewSeparator(), viewProfileButton, widget.NewSeparator(), viewAttributesButton, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), numberApproveRow, numberBanRow, approveScoreRow, banScoreRow, viewReviewerVerdictsButton, widget.NewSeparator(), numberOfReportsRow)
|
|
|
|
if (numberOfReports != 0){
|
|
viewReportsButton := getWidgetCentered(widget.NewButton("View Reports", func(){
|
|
//TODO
|
|
}))
|
|
page.Add(viewReportsButton)
|
|
}
|
|
page.Add(widget.NewSeparator())
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), func(){
|
|
currentPage()
|
|
}))
|
|
|
|
page.Add(updateButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page allows moderators to view the moderation status of a profile attribute
|
|
func setViewAttributeModerationDetailsPage(window fyne.Window, attributeHash [27]byte, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Moderation Details", "Loading details...")
|
|
|
|
currentPage := func(){setViewAttributeModerationDetailsPage(window, attributeHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Moderation Details - Attribute")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
attributeHashLabel := widget.NewLabel("Attribute Hash:")
|
|
|
|
attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])
|
|
|
|
attributeHashTrimmed, _, err := helpers.TrimAndFlattenString(attributeHashHex, 6)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
viewAttributeHashButton := widget.NewButton(attributeHashTrimmed, func(){
|
|
setViewContentHashPage(window, "Attribute", attributeHash[:], currentPage)
|
|
})
|
|
|
|
attributeHashRow := container.NewHBox(layout.NewSpacer(), attributeHashLabel, viewAttributeHashButton, layout.NewSpacer())
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
attributeMetadataIsKnown, _, attributeAuthor, attributeNetworkType, attributeProfileHashesList, err := profileStorage.GetProfileAttributeMetadata(attributeHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (attributeMetadataIsKnown == true){
|
|
|
|
if (appNetworkType != attributeNetworkType){
|
|
setErrorEncounteredPage(window, errors.New("setViewAttributeModerationDetailsPage called with attribute belonging to different appNetworkType."), previousPage)
|
|
return
|
|
}
|
|
}
|
|
|
|
getAttributeAuthorRow := func()(*fyne.Container, error){
|
|
|
|
attributeAuthorLabel := widget.NewLabel("Attribute Author:")
|
|
|
|
if (attributeMetadataIsKnown == false){
|
|
|
|
unknownLabel := getBoldLabel("Unknown")
|
|
|
|
attributeAuthorRow := container.NewHBox(layout.NewSpacer(), attributeAuthorLabel, unknownLabel, layout.NewSpacer())
|
|
|
|
return attributeAuthorRow, nil
|
|
}
|
|
|
|
attributeAuthorString, _, err := identity.EncodeIdentityHashBytesToString(attributeAuthor)
|
|
if (err != nil){ return nil, err }
|
|
|
|
authorIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(attributeAuthorString, 10)
|
|
if (err != nil){ return nil, err }
|
|
|
|
viewAttributeAuthorButton := widget.NewButton(authorIdentityHashTrimmed, func(){
|
|
setViewIdentityModerationDetailsPage(window, attributeAuthor, currentPage)
|
|
})
|
|
|
|
attributeAuthorRow := container.NewHBox(layout.NewSpacer(), attributeAuthorLabel, viewAttributeAuthorButton, layout.NewSpacer())
|
|
|
|
return attributeAuthorRow, nil
|
|
}
|
|
|
|
attributeAuthorRow, err := getAttributeAuthorRow()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
getMyVerdict := func()(string, error){
|
|
|
|
myIdentityExists, attributeMetadataKnown, myReviewExists, myReviewVerdict, _, err := myReviews.GetMyNewestProfileAttributeModerationVerdict(attributeHash, true)
|
|
if (err != nil) { return "", err }
|
|
if (myIdentityExists == false){
|
|
return "None", nil
|
|
}
|
|
if (attributeMetadataKnown == false){
|
|
// Metadata must have been recently deleted
|
|
return "Unknown", nil
|
|
}
|
|
if (myReviewExists == false){
|
|
return "None", nil
|
|
}
|
|
return myReviewVerdict, nil
|
|
}
|
|
|
|
myVerdict, err := getMyVerdict()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
myVerdictLabel := widget.NewLabel("My Verdict:")
|
|
myVerdictText := getBoldLabel(myVerdict)
|
|
|
|
myVerdictRow := container.NewHBox(layout.NewSpacer(), myVerdictLabel, myVerdictText, layout.NewSpacer())
|
|
|
|
if (attributeMetadataIsKnown == false){
|
|
// We do not have a profile containing this attribute
|
|
// We can attempt to download it.
|
|
|
|
description1 := getLabelCentered("This attribute is not downloaded.")
|
|
description2 := getLabelCentered("It must be downloaded to know its moderation status.")
|
|
description3 := getLabelCentered("You can try to download it, but it may have been deleted from the network.")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
//TODO: Add a way to also download reviews/reports at the same time so we can determine attribute verdict quickly
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), attributeHashRow, widget.NewSeparator(), attributeAuthorRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
viewAttributeButton := getWidgetCentered(widget.NewButtonWithIcon("View Attribute", theme.VisibilityIcon(), func(){
|
|
setViewProfileAttributeForModerationPage(window, attributeHash, currentPage)
|
|
}))
|
|
|
|
viewAttributeProfilesButton := getWidgetCentered(widget.NewButtonWithIcon("View Attribute Profiles", theme.VisibilityIcon(), func(){
|
|
//TODO: A list of profiles the attribute belongs to.
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(attributeAuthor)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getLabelCentered("This attribute's author is outside of your moderation range.")
|
|
description2 := getLabelCentered("We cannot determine the moderation consensus.")
|
|
description3 := getLabelCentered("Do you want to download the reviews to view the consensus?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, attributeAuthor[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), attributeHashRow, widget.NewSeparator(), attributeAuthorRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), viewAttributeButton, viewAttributeProfilesButton, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
//TODO: Check for parameters
|
|
parametersExist := true
|
|
|
|
if (parametersExist == false){
|
|
|
|
description1 := getLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for the parameters to download.")
|
|
description3 := getLabelCentered("Once they download, you will be able to see who has reviewed the attribute.")
|
|
|
|
viewStatusButton := getWidgetCentered(widget.NewButtonWithIcon("View Status", theme.VisibilityIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), attributeHashRow, widget.NewSeparator(), attributeAuthorRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), viewAttributeButton, viewAttributeProfilesButton, widget.NewSeparator(), description1, description2, description3, viewStatusButton, refreshButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
attributeApproveAdvocatesMap, attributeBanAdvocatesMap, err := reviewStorage.GetProfileAttributeVerdictMaps(attributeHash, attributeNetworkType, true, attributeProfileHashesList)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
numberOfApproveAdvocates := len(attributeApproveAdvocatesMap)
|
|
numberOfBanAdvocates := len(attributeBanAdvocatesMap)
|
|
|
|
numberApproveString := helpers.ConvertIntToString(numberOfApproveAdvocates)
|
|
approveAdvocatesLabel := widget.NewLabel("Approve Advocates:")
|
|
numberApproveLabel := getBoldLabel(numberApproveString)
|
|
numberApproveRow := container.NewHBox(layout.NewSpacer(), approveAdvocatesLabel, numberApproveLabel, layout.NewSpacer())
|
|
|
|
numberBanString := helpers.ConvertIntToString(numberOfBanAdvocates)
|
|
banAdvocatesLabel := widget.NewLabel("Ban Advocates:")
|
|
numberBanLabel := getBoldLabel(numberBanString)
|
|
numberBanRow := container.NewHBox(layout.NewSpacer(), banAdvocatesLabel, numberBanLabel, layout.NewSpacer())
|
|
|
|
viewReviewerVerdictsButton := getWidgetCentered(widget.NewButton("View Reviewers", func(){
|
|
setViewAttributeReviewerVerdictsPage(window, attributeHash, 0, currentPage)
|
|
}))
|
|
|
|
numberOfReports, err := reportStorage.GetNumberOfReportsForReportedHash(attributeHash[:], appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
numberOfReportsString := helpers.ConvertInt64ToString(numberOfReports)
|
|
numberOfReportsLabel := widget.NewLabel("Number of reports:")
|
|
numberOfReportsText := getBoldLabel(numberOfReportsString)
|
|
numberOfReportsRow := container.NewHBox(layout.NewSpacer(), numberOfReportsLabel, numberOfReportsText, layout.NewSpacer())
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), attributeHashRow, widget.NewSeparator(), attributeAuthorRow, widget.NewSeparator(), viewAttributeButton, viewAttributeProfilesButton, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), numberApproveRow, numberBanRow, viewReviewerVerdictsButton, widget.NewSeparator(), numberOfReportsRow)
|
|
|
|
if (numberOfReports != 0){
|
|
viewReportsButton := getWidgetCentered(widget.NewButton("View Reports", func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
page.Add(viewReportsButton)
|
|
}
|
|
page.Add(widget.NewSeparator())
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page.Add(updateButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page allows moderators to view the moderation status of a message
|
|
func setViewMessageModerationDetailsPage(window fyne.Window, messageHash [26]byte, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Moderation Details", "Loading details...")
|
|
|
|
currentPage := func(){setViewMessageModerationDetailsPage(window, messageHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Moderation Details - Message")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
messageHashLabel := widget.NewLabel("Message Hash:")
|
|
|
|
messageHashHex := encoding.EncodeBytesToHexString(messageHash[:])
|
|
|
|
messageHashTrimmed, _, err := helpers.TrimAndFlattenString(messageHashHex, 6)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
viewMessageHashButton := widget.NewButton(messageHashTrimmed, func(){
|
|
setViewContentHashPage(window, "Message", messageHash[:], currentPage)
|
|
})
|
|
|
|
messageHashRow := container.NewHBox(layout.NewSpacer(), messageHashLabel, viewMessageHashButton, layout.NewSpacer())
|
|
|
|
//TODO: Add button to view message sticky status and message verdict history
|
|
|
|
getMessageAuthorRow := func()(*fyne.Container, error){
|
|
|
|
messageAuthorLabel := widget.NewLabel("Message Author:")
|
|
|
|
messageExists, messageCipherKeyFound, messageIsDecryptable, _, messageAuthorIdentityHash, _, err := chatMessageStorage.GetDecryptedMessageForModeration(messageHash)
|
|
if (err != nil){ return nil, err }
|
|
if (messageExists == false || messageCipherKeyFound == false || messageIsDecryptable == false){
|
|
|
|
//TODO: Show user if message is not decryptable, in which case, author must be malicious
|
|
|
|
unknownLabel := getBoldLabel("Unknown")
|
|
|
|
messageAuthorRow := container.NewHBox(layout.NewSpacer(), messageAuthorLabel, unknownLabel, layout.NewSpacer())
|
|
|
|
return messageAuthorRow, nil
|
|
}
|
|
|
|
messageAuthorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(messageAuthorIdentityHash)
|
|
if (err != nil){ return nil, err }
|
|
|
|
messageAuthorIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(messageAuthorIdentityHashString, 10)
|
|
if (err != nil){ return nil, err }
|
|
|
|
viewMessageAuthorIdentityHashButton := widget.NewButton(messageAuthorIdentityHashTrimmed, func(){
|
|
setViewIdentityModerationDetailsPage(window, messageAuthorIdentityHash, currentPage)
|
|
})
|
|
|
|
messageAuthorRow := container.NewHBox(layout.NewSpacer(), messageAuthorLabel, viewMessageAuthorIdentityHashButton, layout.NewSpacer())
|
|
|
|
return messageAuthorRow, nil
|
|
}
|
|
|
|
messageAuthorRow, err := getMessageAuthorRow()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
messageMetadataIsKnown, _, messageNetworkType, _, _, downloadingRequiredReviews, parametersExist, messageVerdict, numberOfApproveAdvocates, numberOfBanAdvocates, approveScoreSum, banScoreSum, _, _, err := verifiedVerdict.GetVerifiedMessageVerdict(messageHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (messageMetadataIsKnown == true){
|
|
|
|
if (appNetworkType != messageNetworkType){
|
|
setErrorEncounteredPage(window, errors.New("setViewMessageModerationDetailsPage called with message belonging to different appNetworkType."), previousPage)
|
|
return
|
|
}
|
|
}
|
|
|
|
getModeratorConsensusRow := func()*fyne.Container{
|
|
|
|
moderatorConsensusLabel := widget.NewLabel("Moderator Consensus:")
|
|
|
|
if (messageMetadataIsKnown == false || downloadingRequiredReviews == false || parametersExist == false){
|
|
verdictConsensusLabel := getBoldItalicLabel("Unknown")
|
|
|
|
moderatorConsensusRow := container.NewHBox(layout.NewSpacer(), moderatorConsensusLabel, verdictConsensusLabel, layout.NewSpacer())
|
|
|
|
return moderatorConsensusRow
|
|
}
|
|
|
|
verdictConsensusLabel := getBoldLabel(messageVerdict)
|
|
moderatorConsensusRow := container.NewHBox(layout.NewSpacer(), moderatorConsensusLabel, verdictConsensusLabel, layout.NewSpacer())
|
|
|
|
return moderatorConsensusRow
|
|
}
|
|
|
|
moderatorConsensusRow := getModeratorConsensusRow()
|
|
|
|
getMyVerdict := func()(string, error){
|
|
|
|
myIdentityExists, messageMetadataExists, myReviewExists, myReviewVerdict, err := myReviews.GetMyNewestMessageModerationVerdict(messageHash)
|
|
if (err != nil) { return "", err }
|
|
if (myIdentityExists == false){
|
|
return "None", nil
|
|
}
|
|
if (messageMetadataExists == false){
|
|
return "Unknown", nil
|
|
}
|
|
if (myReviewExists == false){
|
|
return "None", nil
|
|
}
|
|
return myReviewVerdict, nil
|
|
}
|
|
|
|
myVerdict, err := getMyVerdict()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
myVerdictLabel := widget.NewLabel("My Verdict:")
|
|
myVerdictText := getBoldLabel(myVerdict)
|
|
|
|
myVerdictRow := container.NewHBox(layout.NewSpacer(), myVerdictLabel, myVerdictText, layout.NewSpacer())
|
|
|
|
if (messageMetadataIsKnown == false){
|
|
// We do not have the required message
|
|
// We can attempt to download it.
|
|
|
|
description1 := getBoldLabelCentered("This message is not downloaded.")
|
|
description2 := getLabelCentered("It must be downloaded to know its moderation status.")
|
|
description3 := getLabelCentered("You can try to download it, but it may have been deleted from the network.")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
//TODO: Add a way to also download reviews/reports at the same time, so we can determine message verdict quickly
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), messageAuthorRow, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
viewMessageButton := getWidgetCentered(widget.NewButtonWithIcon("View Message", theme.VisibilityIcon(), func(){
|
|
setViewMessageForModerationPage(window, messageHash, currentPage)
|
|
}))
|
|
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getLabelCentered("This message is outside of your moderation range.")
|
|
description2 := getLabelCentered("We cannot determine the moderation consensus.")
|
|
description3 := getLabelCentered("Do you want to download the reviews to view the consensus?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, messageHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), messageAuthorRow, widget.NewSeparator(), viewMessageButton, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, description3, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
|
|
description1 := getLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for the parameters to be downloaded.")
|
|
|
|
viewStatusButton := getWidgetCentered(widget.NewButtonWithIcon("View Status", theme.VisibilityIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), messageAuthorRow, widget.NewSeparator(), viewMessageButton, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), description1, description2, viewStatusButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
numberApproveString := helpers.ConvertIntToString(numberOfApproveAdvocates)
|
|
approveAdvocatesLabel := widget.NewLabel("Approve Advocates:")
|
|
numberApproveLabel := getBoldLabel(numberApproveString)
|
|
numberApproveRow := container.NewHBox(layout.NewSpacer(), approveAdvocatesLabel, numberApproveLabel, layout.NewSpacer())
|
|
|
|
numberBanString := helpers.ConvertIntToString(numberOfBanAdvocates)
|
|
banAdvocatesLabel := widget.NewLabel("Ban Advocates:")
|
|
numberBanLabel := getBoldLabel(numberBanString)
|
|
numberBanRow := container.NewHBox(layout.NewSpacer(), banAdvocatesLabel, numberBanLabel, layout.NewSpacer())
|
|
|
|
approveScoreString := helpers.ConvertFloat64ToStringRounded(approveScoreSum, 2)
|
|
approveScoreLabel := getLabelCentered("Approve Score:")
|
|
approveScoreText := getBoldLabel(approveScoreString)
|
|
approveScoreRow := container.NewHBox(layout.NewSpacer(), approveScoreLabel, approveScoreText, layout.NewSpacer())
|
|
|
|
banScoreString := helpers.ConvertFloat64ToStringRounded(banScoreSum, 2)
|
|
banScoreLabel := getLabelCentered("Ban Score:")
|
|
banScoreText := getBoldLabel(banScoreString)
|
|
banScoreRow := container.NewHBox(layout.NewSpacer(), banScoreLabel, banScoreText, layout.NewSpacer())
|
|
|
|
viewReviewerVerdictsButton := getWidgetCentered(widget.NewButton("View Reviewers", func(){
|
|
setViewMessageReviewerVerdictsPage(window, messageHash, 0, currentPage)
|
|
}))
|
|
|
|
numberOfReports, err := reportStorage.GetNumberOfReportsForReportedHash(messageHash[:], messageNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
numberOfReportsString := helpers.ConvertInt64ToString(numberOfReports)
|
|
numberOfReportsLabel := widget.NewLabel("Number of reports:")
|
|
numberOfReportsText := getBoldLabel(numberOfReportsString)
|
|
numberOfReportsRow := container.NewHBox(layout.NewSpacer(), numberOfReportsLabel, numberOfReportsText, layout.NewSpacer())
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), messageHashRow, widget.NewSeparator(), messageAuthorRow, widget.NewSeparator(), viewMessageButton, widget.NewSeparator(), moderatorConsensusRow, widget.NewSeparator(), myVerdictRow, widget.NewSeparator(), numberApproveRow, numberBanRow, approveScoreRow, banScoreRow, viewReviewerVerdictsButton, widget.NewSeparator(), numberOfReportsRow)
|
|
|
|
if (numberOfReports != 0){
|
|
viewReportsButton := getWidgetCentered(widget.NewButton("View Reports", func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
page.Add(viewReportsButton)
|
|
}
|
|
page.Add(widget.NewSeparator())
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page.Add(updateButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setDownloadReviewsAndReportsForReviewedHashPage(window fyne.Window, reviewedHash []byte, previousPage func(), pageToVisitAfter func()){
|
|
|
|
|
|
//TODO: This page must also wait for moderator identity hashes from newly downloaded reviews to be downloaded
|
|
// This page must also make sure that the content is downloaded
|
|
|
|
showUnderConstructionDialog(window)
|
|
}
|
|
|
|
|
|
// This page will show all moderators who have banned the identity
|
|
func setViewIdentityReviewerVerdictsPage(window fyne.Window, identityHash [16]byte, viewIndex int, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Identity Ban Advocates", "Loading verdicts...")
|
|
|
|
currentPage := func(){setViewIdentityReviewerVerdictsPage(window, identityHash, viewIndex, previousPage)}
|
|
|
|
title := getPageTitleCentered("View Identity Ban Advocates")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(identityHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (downloadingRequiredReviews == false){
|
|
description1 := getBoldLabelCentered("This identity is outside of your moderator range.")
|
|
description2 := getLabelCentered("Download the reviews for this identity?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButton("Download", func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, identityHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, downloadButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
banAdvocatesMap, err := reviewStorage.GetIdentityBanAdvocatesMap(identityHash, appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (len(banAdvocatesMap) == 0){
|
|
|
|
noReviewersDescription := getBoldLabelCentered("No moderators have banned this identity.")
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), noReviewersDescription, updateButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
description := getLabelCentered("Below are the moderators who have banned the identity.")
|
|
|
|
//TODO: Navigation buttons and pages
|
|
|
|
//Outputs:
|
|
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
|
|
// -bool: Parameters exist
|
|
// -*fyne.Container: Reviewer verdicts grid
|
|
// -error
|
|
getReviewerVerdictsGrid := func()(bool, bool, *fyne.Container, error){
|
|
|
|
notBannedReviewersList := make([][16]byte, 0)
|
|
bannedReviewersList := make([][16]byte, 0)
|
|
|
|
for moderatorIdentityHash, _ := range banAdvocatesMap{
|
|
|
|
requiredDataIsBeingDownloaded, parametersExist, isBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(false, moderatorIdentityHash, appNetworkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (requiredDataIsBeingDownloaded == false){
|
|
return false, parametersExist, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, nil, nil
|
|
}
|
|
|
|
if (isBanned == true){
|
|
bannedReviewersList = append(bannedReviewersList, moderatorIdentityHash)
|
|
} else{
|
|
notBannedReviewersList = append(notBannedReviewersList, moderatorIdentityHash)
|
|
}
|
|
}
|
|
|
|
err := helpers.SortIdentityHashListToUnicodeOrder(notBannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
err = helpers.SortIdentityHashListToUnicodeOrder(bannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
allReviewersListSorted := slices.Concat(notBannedReviewersList, bannedReviewersList)
|
|
|
|
//TODO: Add pages and navigation
|
|
|
|
emptyLabelA := widget.NewLabel("")
|
|
moderatorLabel := getItalicLabelCentered("Moderator")
|
|
isBannedLabel := getItalicLabelCentered("Is Banned")
|
|
reasonLabel := getItalicLabelCentered("Reason")
|
|
emptyLabelC := widget.NewLabel("")
|
|
|
|
viewModeratorButtonsColumn := container.NewVBox(emptyLabelA, widget.NewSeparator())
|
|
moderatorIdentityHashColumn := container.NewVBox(moderatorLabel, widget.NewSeparator())
|
|
moderatorIsBannedColumn := container.NewVBox(isBannedLabel, widget.NewSeparator())
|
|
reasonColumn := container.NewVBox(reasonLabel, widget.NewSeparator())
|
|
viewReviewButtonsColumn := container.NewVBox(emptyLabelC, widget.NewSeparator())
|
|
|
|
for _, moderatorIdentityHash := range allReviewersListSorted{
|
|
|
|
viewModeratorButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewModeratorDetailsPage(window, moderatorIdentityHash, currentPage)
|
|
})
|
|
|
|
moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
identityHashTrimmed, _, err := helpers.TrimAndFlattenString(moderatorIdentityHashString, 10)
|
|
if (err != nil) { return false, false, nil, err }
|
|
identityHashLabel := getBoldLabelCentered(identityHashTrimmed)
|
|
|
|
moderatorIsBannedBool := slices.Contains(bannedReviewersList, moderatorIdentityHash)
|
|
moderatorIsBanned := helpers.ConvertBoolToYesOrNoString(moderatorIsBannedBool)
|
|
moderatorIsBannedTranslated := translate(moderatorIsBanned)
|
|
|
|
moderatorIsBannedLabel := getBoldLabelCentered(moderatorIsBannedTranslated)
|
|
|
|
reviewFound, newestReviewBytes, _, err := reviewStorage.GetModeratorNewestIdentityReview(moderatorIdentityHash, identityHash, appNetworkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (reviewFound == false){
|
|
// Review was deleted or changed after reviewers were retrieved
|
|
continue
|
|
}
|
|
|
|
ableToRead, reviewHash, _, reviewNetworkType, retrievedModeratorIdentityHash, _, _, currentReviewedHash, reviewVerdict, reviewMap, err := readReviews.ReadReviewAndHash(false, newestReviewBytes)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (ableToRead == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestIdentityReview returning invalid review.")
|
|
}
|
|
if (reviewNetworkType != appNetworkType){
|
|
return false, false, nil, errors.New("GetModeratorNewestIdentityReview returning review of different networkType.")
|
|
}
|
|
if (moderatorIdentityHash != retrievedModeratorIdentityHash) {
|
|
return false, false, nil, errors.New("GetModeratorNewestIdentityReview returning review by different moderator.")
|
|
}
|
|
areEqual := bytes.Equal(currentReviewedHash, identityHash[:])
|
|
if (areEqual == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestIdentityReview returning review for different reviewedHash.")
|
|
}
|
|
if (reviewVerdict != "Ban"){
|
|
return false, false, nil, errors.New("GetModeratorNewestIdentityReview returning non-Ban review: " + reviewVerdict)
|
|
}
|
|
|
|
getViewReasonButtonOrText := func()(*fyne.Container, error){
|
|
|
|
reasonString, exists := reviewMap["Reason"]
|
|
if (exists == false) {
|
|
noneLabel := getBoldLabelCentered(translate("None"))
|
|
return noneLabel, nil
|
|
}
|
|
|
|
viewReasonButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Verdict Reason", reasonString, false, currentPage)
|
|
}))
|
|
|
|
return viewReasonButton, nil
|
|
}
|
|
viewReasonButtonOrText, err := getViewReasonButtonOrText()
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
viewReviewButton := widget.NewButtonWithIcon("View Review", theme.VisibilityIcon(), func(){
|
|
setViewReviewDetailsPage(window, reviewHash, currentPage)
|
|
})
|
|
|
|
viewModeratorButtonsColumn.Add(viewModeratorButton)
|
|
moderatorIdentityHashColumn.Add(identityHashLabel)
|
|
moderatorIsBannedColumn.Add(moderatorIsBannedLabel)
|
|
reasonColumn.Add(viewReasonButtonOrText)
|
|
viewReviewButtonsColumn.Add(viewReviewButton)
|
|
|
|
viewModeratorButtonsColumn.Add(widget.NewSeparator())
|
|
moderatorIdentityHashColumn.Add(widget.NewSeparator())
|
|
moderatorIsBannedColumn.Add(widget.NewSeparator())
|
|
reasonColumn.Add(widget.NewSeparator())
|
|
viewReviewButtonsColumn.Add(widget.NewSeparator())
|
|
}
|
|
|
|
reviewsGrid := container.NewHBox(layout.NewSpacer(), viewModeratorButtonsColumn, moderatorIdentityHashColumn, moderatorIsBannedColumn, reasonColumn, viewReviewButtonsColumn, layout.NewSpacer())
|
|
|
|
return true, true, reviewsGrid, nil
|
|
}
|
|
|
|
moderatorModeEnabled, parametersExist, verdictsGrid, err := getReviewerVerdictsGrid()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (moderatorModeEnabled == false){
|
|
|
|
description1 := getBoldLabelCentered("Moderator mode is disabled.")
|
|
description2 := getLabelCentered("You must enable moderator mode to view the reviewer verdicts.")
|
|
|
|
enableModeratorModeButton := getWidgetCentered(widget.NewButtonWithIcon("Enable Moderator Mode", theme.NavigateNextIcon(), func(){
|
|
setManageModeratorModePage(window, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, enableModeratorModeButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
|
|
description1 := getBoldLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for them to download.")
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
//TODO: Add button to view progress
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, refreshButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), verdictsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page will show all moderators who have banned/approved the profile
|
|
func setViewProfileReviewerVerdictsPage(window fyne.Window, profileHash [28]byte, viewIndex int, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Profile Verdicts", "Loading verdicts...")
|
|
|
|
currentPage := func(){setViewProfileReviewerVerdictsPage(window, profileHash, viewIndex, previousPage)}
|
|
|
|
title := getPageTitleCentered("View Profile Verdicts")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
_, profileIsDisabled, err := readProfiles.ReadProfileHashMetadata(profileHash)
|
|
if (err != nil){
|
|
profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
|
|
setErrorEncounteredPage(window, errors.New("setViewProfileReviewerVerdictsPage called with invalid profileHash: " + profileHashHex), previousPage)
|
|
return
|
|
}
|
|
if (profileIsDisabled == true){
|
|
description1 := getBoldLabelCentered("This profile is disabled.")
|
|
description2 := getLabelCentered("It cannot be reviewed.")
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
profileMetadataIsKnown, _, profileNetworkType, profileIdentityHash, _, _, _, profileAttributeHashesMap, err := contentMetadata.GetProfileMetadata(profileHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (profileMetadataIsKnown == false){
|
|
|
|
description1 := getLabelCentered("The profile is not downloaded.")
|
|
description2 := getLabelCentered("You must download it to view its reviews.")
|
|
description3 := getLabelCentered("It may not be possible if the profile has been deleted from the network.")
|
|
description4 := getLabelCentered("Try to download the profile?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (profileNetworkType != appNetworkType){
|
|
setErrorEncounteredPage(window, errors.New("setViewProfileReviewerVerdictsPage called with profile belonging to different networkType."), previousPage)
|
|
return
|
|
}
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(profileIdentityHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getBoldLabelCentered("This profile's author is outside of your moderator range.")
|
|
description2 := getLabelCentered("Download the reviews for this profile?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButton("Download", func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, profileHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, downloadButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
profileAttributeHashesList := helpers.GetListOfMapValues(profileAttributeHashesMap)
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := reviewStorage.GetProfileVerdictMaps(profileHash, profileNetworkType, true, profileAttributeHashesList)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (len(approveAdvocatesMap) == 0 && len(banAdvocatesMap) == 0){
|
|
|
|
noReviewersDescription := getLabelCentered("No moderators have reviewed the profile.")
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), noReviewersDescription, updateButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
description := getLabelCentered("Below are the moderators who have reviewed the profile.")
|
|
|
|
//TODO: Navigation pages and buttons
|
|
|
|
//Outputs:
|
|
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
|
|
// -bool: Parameters exist
|
|
// -*fyne.Container: Reviewer verdicts grid
|
|
// -error
|
|
getReviewerVerdictsGrid := func()(bool, bool, *fyne.Container, error){
|
|
|
|
approveAdvocatesList := helpers.GetListOfMapKeys(approveAdvocatesMap)
|
|
banAdvocatesList := helpers.GetListOfMapKeys(banAdvocatesMap)
|
|
|
|
allReviewersList := slices.Concat(approveAdvocatesList, banAdvocatesList)
|
|
|
|
notBannedReviewersList := make([][16]byte, 0)
|
|
bannedReviewersList := make([][16]byte, 0)
|
|
|
|
for _, moderatorIdentityHash := range allReviewersList{
|
|
|
|
requiredDataIsBeingDownloaded, parametersExist, isBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(false, moderatorIdentityHash, profileNetworkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (requiredDataIsBeingDownloaded == false){
|
|
return false, parametersExist, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, nil, nil
|
|
}
|
|
|
|
if (isBanned == true){
|
|
bannedReviewersList = append(bannedReviewersList, moderatorIdentityHash)
|
|
} else{
|
|
notBannedReviewersList = append(notBannedReviewersList, moderatorIdentityHash)
|
|
}
|
|
}
|
|
|
|
err := helpers.SortIdentityHashListToUnicodeOrder(notBannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
err = helpers.SortIdentityHashListToUnicodeOrder(bannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
allReviewersListSorted := slices.Concat(notBannedReviewersList, bannedReviewersList)
|
|
|
|
//TODO: Add pages and navigation
|
|
|
|
emptyLabel1 := widget.NewLabel("")
|
|
emptyLabel2 := widget.NewLabel("")
|
|
emptyLabel3 := widget.NewLabel("")
|
|
emptyLabel4 := widget.NewLabel("")
|
|
emptyLabel5 := widget.NewLabel("")
|
|
approvedLabel := getItalicLabelCentered("Approved")
|
|
bannedLabel := getItalicLabelCentered("Banned")
|
|
|
|
emptyLabel6 := widget.NewLabel("")
|
|
authorLabel := getItalicLabelCentered("Author")
|
|
isBannedLabel := getItalicLabelCentered("Is Banned")
|
|
verdictLabel := getItalicLabelCentered("Verdict")
|
|
fullProfileLabel := getItalicLabelCentered("Full Profile")
|
|
attributesLabelA := getItalicLabelCentered("Attributes")
|
|
attributesLabelB := getItalicLabelCentered("Attributes")
|
|
|
|
viewModeratorButtonsColumn := container.NewVBox(emptyLabel1, emptyLabel6, widget.NewSeparator())
|
|
moderatorIdentityHashColumn := container.NewVBox(emptyLabel2, authorLabel, widget.NewSeparator())
|
|
moderatorIsBannedColumn := container.NewVBox(emptyLabel3, isBannedLabel, widget.NewSeparator())
|
|
verdictColumn := container.NewVBox(emptyLabel4, verdictLabel, widget.NewSeparator())
|
|
fullProfileReviewColumn := container.NewVBox(emptyLabel5, fullProfileLabel, widget.NewSeparator())
|
|
approvedAttributesColumn := container.NewVBox(approvedLabel, attributesLabelA, widget.NewSeparator())
|
|
bannedAttributesColumn := container.NewVBox(bannedLabel, attributesLabelB, widget.NewSeparator())
|
|
|
|
for _, moderatorIdentityHash := range allReviewersListSorted{
|
|
|
|
viewModeratorButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewModeratorDetailsPage(window, moderatorIdentityHash, currentPage)
|
|
})
|
|
|
|
moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
identityHashTrimmed, _, err := helpers.TrimAndFlattenString(moderatorIdentityHashString, 10)
|
|
if (err != nil) { return false, false, nil, err }
|
|
identityHashLabel := getBoldLabelCentered(identityHashTrimmed)
|
|
|
|
moderatorIsBannedBool := slices.Contains(bannedReviewersList, moderatorIdentityHash)
|
|
moderatorIsBanned := helpers.ConvertBoolToYesOrNoString(moderatorIsBannedBool)
|
|
moderatorIsBannedTranslated := translate(moderatorIsBanned)
|
|
|
|
moderatorIsBannedLabel := getBoldLabelCentered(moderatorIsBannedTranslated)
|
|
|
|
profileVerdictExists, profileVerdict, fullProfileReviewExists, fullProfileReviewBytes, _, attributeApproveReviewsMap, attributeBanReviewsMap, err := reviewStorage.GetModeratorNewestProfileReviews(moderatorIdentityHash, profileHash, profileNetworkType, profileAttributeHashesList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (profileVerdictExists == false){
|
|
// Review was deleted or changed after reviewers were retrieved
|
|
continue
|
|
}
|
|
|
|
profileVerdictLabel := getBoldLabelCentered(profileVerdict)
|
|
|
|
viewModeratorButtonsColumn.Add(viewModeratorButton)
|
|
moderatorIdentityHashColumn.Add(identityHashLabel)
|
|
moderatorIsBannedColumn.Add(moderatorIsBannedLabel)
|
|
verdictColumn.Add(profileVerdictLabel)
|
|
|
|
if (fullProfileReviewExists == false){
|
|
|
|
noneLabel := getLabelCentered("None")
|
|
|
|
fullProfileReviewColumn.Add(noneLabel)
|
|
} else {
|
|
|
|
ableToRead, reviewHash, _, reviewNetworkType, retrievedModeratorIdentityHash, _, _, currentReviewedHash, _, _, err := readReviews.ReadReviewAndHash(false, fullProfileReviewBytes)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (ableToRead == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileReviews returning invalid full profile review.")
|
|
}
|
|
if (reviewNetworkType != profileNetworkType){
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileReviews returning full profile review belonging to different network type.")
|
|
}
|
|
if (moderatorIdentityHash != retrievedModeratorIdentityHash) {
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileReviews returning full profile review by different moderator.")
|
|
}
|
|
areEqual := bytes.Equal(currentReviewedHash, profileHash[:])
|
|
if (areEqual == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileReviews returning full profile review for different reviewedHash.")
|
|
}
|
|
|
|
fullProfileReviewButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewReviewDetailsPage(window, reviewHash, currentPage)
|
|
})
|
|
|
|
fullProfileReviewColumn.Add(fullProfileReviewButton)
|
|
}
|
|
|
|
if (len(attributeApproveReviewsMap) == 0){
|
|
|
|
noneLabel := getLabelCentered("None")
|
|
approvedAttributesColumn.Add(noneLabel)
|
|
} else {
|
|
|
|
numberOfApprovedAttributes := len(attributeApproveReviewsMap)
|
|
numberOfApprovedAttributesString := helpers.ConvertIntToString(numberOfApprovedAttributes)
|
|
|
|
viewApprovedAttributesButton := widget.NewButtonWithIcon(numberOfApprovedAttributesString, theme.VisibilityIcon(), func(){
|
|
//TODO: A page to view the attribute approvals
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
|
|
approvedAttributesColumn.Add(viewApprovedAttributesButton)
|
|
}
|
|
|
|
if (len(attributeBanReviewsMap) == 0){
|
|
|
|
noneLabel := getLabelCentered("None")
|
|
bannedAttributesColumn.Add(noneLabel)
|
|
} else {
|
|
|
|
numberOfBannedAttributes := len(attributeBanReviewsMap)
|
|
numberOfBannedAttributesString := helpers.ConvertIntToString(numberOfBannedAttributes)
|
|
|
|
viewBannedAttributesButton := widget.NewButtonWithIcon(numberOfBannedAttributesString, theme.VisibilityIcon(), func(){
|
|
//TODO: A page to view the attribute bans
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
|
|
bannedAttributesColumn.Add(viewBannedAttributesButton)
|
|
}
|
|
|
|
viewModeratorButtonsColumn.Add(widget.NewSeparator())
|
|
moderatorIdentityHashColumn.Add(widget.NewSeparator())
|
|
moderatorIsBannedColumn.Add(widget.NewSeparator())
|
|
fullProfileReviewColumn.Add(widget.NewSeparator())
|
|
approvedAttributesColumn.Add(widget.NewSeparator())
|
|
bannedAttributesColumn.Add(widget.NewSeparator())
|
|
}
|
|
|
|
reviewsGrid := container.NewHBox(layout.NewSpacer(), viewModeratorButtonsColumn, moderatorIdentityHashColumn, moderatorIsBannedColumn, fullProfileReviewColumn, approvedAttributesColumn, bannedAttributesColumn, layout.NewSpacer())
|
|
|
|
return true, true, reviewsGrid, nil
|
|
}
|
|
|
|
moderatorModeEnabled, parametersExist, verdictsGrid, err := getReviewerVerdictsGrid()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (moderatorModeEnabled == false){
|
|
|
|
description1 := getBoldLabelCentered("Moderator mode is disabled.")
|
|
description2 := getLabelCentered("You must enable moderator mode to view the reviewer verdicts.")
|
|
|
|
enableModeratorModeButton := getWidgetCentered(widget.NewButtonWithIcon("Enable Moderator Mode", theme.NavigateNextIcon(), func(){
|
|
setManageModeratorModePage(window, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, enableModeratorModeButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
description1 := getBoldLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for them to download.")
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
//TODO: Add button to view progress
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, refreshButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), verdictsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
// This page will show all moderators who have banned/approved the attribute
|
|
func setViewAttributeReviewerVerdictsPage(window fyne.Window, attributeHash [27]byte, viewIndex int, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Attribute Verdicts", "Loading verdicts...")
|
|
|
|
currentPage := func(){setViewAttributeReviewerVerdictsPage(window, attributeHash, viewIndex, previousPage)}
|
|
|
|
title := getPageTitleCentered("View Attribute Verdicts")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
attributeMetadataIsKnown, _, attributeAuthor, attributeNetworkType, attributeProfileHashesList, err := profileStorage.GetProfileAttributeMetadata(attributeHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (attributeMetadataIsKnown == false){
|
|
|
|
description1 := getBoldLabelCentered("The attribute is not downloaded.")
|
|
description2 := getLabelCentered("You must download it to view its reviews.")
|
|
description3 := getLabelCentered("It may not be possible if the attribute has been deleted from the network.")
|
|
description4 := getLabelCentered("Try to download the attribute?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO: Create a way to download profiles which contain an attribute
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (appNetworkType != attributeNetworkType){
|
|
setErrorEncounteredPage(window, errors.New("setViewAttributeReviewerVerdictsPage called with attribute belonging to different network type than app."), previousPage)
|
|
return
|
|
}
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(attributeAuthor)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getBoldLabelCentered("This attribute's author is outside of your moderator range.")
|
|
description2 := getLabelCentered("Download the reviews for this attribute?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButton("Download", func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, attributeHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, downloadButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
attributeApproveAdvocatesMap, attributeBanAdvocatesMap, err := reviewStorage.GetProfileAttributeVerdictMaps(attributeHash, attributeNetworkType, true, attributeProfileHashesList)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (len(attributeApproveAdvocatesMap) == 0 && len(attributeBanAdvocatesMap) == 0){
|
|
|
|
noReviewersDescription := getBoldLabelCentered("No moderators have reviewed the attribute.")
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), noReviewersDescription, updateButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
description1 := getLabelCentered("These are the moderators who have reviewed the attribute.")
|
|
description2 := getLabelCentered("This includes moderators who have approved a profile that contains this attribute.")
|
|
|
|
//TODO: Navigation pages and buttons
|
|
|
|
//Outputs:
|
|
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
|
|
// -bool: Parameters exist
|
|
// -*fyne.Container: Reviewer verdicts grid
|
|
// -error
|
|
getReviewerVerdictsGrid := func()(bool, bool, *fyne.Container, error){
|
|
|
|
approveAdvocatesList := helpers.GetListOfMapKeys(attributeApproveAdvocatesMap)
|
|
banAdvocatesList := helpers.GetListOfMapKeys(attributeApproveAdvocatesMap)
|
|
|
|
allReviewersList := slices.Concat(approveAdvocatesList, banAdvocatesList)
|
|
|
|
notBannedReviewersList := make([][16]byte, 0)
|
|
bannedReviewersList := make([][16]byte, 0)
|
|
|
|
for _, moderatorIdentityHash := range allReviewersList{
|
|
|
|
requiredDataIsBeingDownloaded, parametersExist, isBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(false, moderatorIdentityHash, attributeNetworkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (requiredDataIsBeingDownloaded == false){
|
|
return false, parametersExist, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, nil, nil
|
|
}
|
|
|
|
if (isBanned == true){
|
|
bannedReviewersList = append(bannedReviewersList, moderatorIdentityHash)
|
|
} else{
|
|
notBannedReviewersList = append(notBannedReviewersList, moderatorIdentityHash)
|
|
}
|
|
}
|
|
|
|
err := helpers.SortIdentityHashListToUnicodeOrder(notBannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
err = helpers.SortIdentityHashListToUnicodeOrder(bannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
allReviewersListSorted := slices.Concat(notBannedReviewersList, bannedReviewersList)
|
|
|
|
//TODO: Add pages and navigation
|
|
|
|
emptyLabelA := widget.NewLabel("")
|
|
authorLabel := getItalicLabelCentered("Author")
|
|
isBannedLabel := getItalicLabelCentered("Is Banned")
|
|
reviewTypeTitle := getItalicLabelCentered("Review Type")
|
|
verdictLabel := getItalicLabelCentered("Verdict")
|
|
reasonLabel := getItalicLabelCentered("Reason")
|
|
emptyLabelC := widget.NewLabel("")
|
|
|
|
viewModeratorButtonsColumn := container.NewVBox(emptyLabelA, widget.NewSeparator())
|
|
moderatorIdentityHashColumn := container.NewVBox(authorLabel, widget.NewSeparator())
|
|
moderatorIsBannedColumn := container.NewVBox(isBannedLabel, widget.NewSeparator())
|
|
reviewTypeColumn := container.NewVBox(reviewTypeTitle, widget.NewSeparator())
|
|
verdictColumn := container.NewVBox(verdictLabel, widget.NewSeparator())
|
|
reasonColumn := container.NewVBox(reasonLabel, widget.NewSeparator())
|
|
viewReviewButtonsColumn := container.NewVBox(emptyLabelC, widget.NewSeparator())
|
|
|
|
for _, moderatorIdentityHash := range allReviewersListSorted{
|
|
|
|
viewModeratorButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewModeratorDetailsPage(window, moderatorIdentityHash, currentPage)
|
|
})
|
|
|
|
moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
identityHashTrimmed, _, err := helpers.TrimAndFlattenString(moderatorIdentityHashString, 10)
|
|
if (err != nil) { return false, false, nil, err }
|
|
identityHashLabel := getBoldLabelCentered(identityHashTrimmed)
|
|
|
|
moderatorIsBannedBool := slices.Contains(bannedReviewersList, moderatorIdentityHash)
|
|
moderatorIsBanned := helpers.ConvertBoolToYesOrNoString(moderatorIsBannedBool)
|
|
moderatorIsBannedTranslated := translate(moderatorIsBanned)
|
|
|
|
moderatorIsBannedLabel := getBoldLabelCentered(moderatorIsBannedTranslated)
|
|
|
|
reviewFound, reviewType, newestReviewBytes, newestReviewMap, reviewVerdict, _, err := reviewStorage.GetModeratorNewestProfileAttributeReview(moderatorIdentityHash, attributeHash, attributeNetworkType, true)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (reviewFound == false){
|
|
// Review was deleted or changed after reviewers were retrieved
|
|
continue
|
|
}
|
|
|
|
reviewTypeLabel := getBoldLabelCentered(reviewType)
|
|
|
|
ableToRead, reviewHash, _, reviewNetworkType, retrievedModeratorIdentityHash, _, _, _, _, _, err := readReviews.ReadReviewAndHash(false, newestReviewBytes)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (ableToRead == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileAttributeReview returning invalid review.")
|
|
}
|
|
if (reviewNetworkType != attributeNetworkType){
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileAttributeReview returning review belonging to different networkType.")
|
|
}
|
|
if (moderatorIdentityHash != retrievedModeratorIdentityHash) {
|
|
return false, false, nil, errors.New("GetModeratorNewestProfileAttributeReview returning review by different moderator.")
|
|
}
|
|
|
|
reviewVerdictTranslated := translate(reviewVerdict)
|
|
reviewVerdictLabel := getBoldLabelCentered(reviewVerdictTranslated)
|
|
|
|
getViewReasonButtonOrText := func()(*fyne.Container, error){
|
|
|
|
reasonString, exists := newestReviewMap["Reason"]
|
|
if (exists == false) {
|
|
noneLabel := getBoldLabelCentered(translate("None"))
|
|
return noneLabel, nil
|
|
}
|
|
|
|
viewReasonButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Verdict Reason", reasonString, false, currentPage)
|
|
}))
|
|
|
|
return viewReasonButton, nil
|
|
}
|
|
viewReasonButtonOrText, err := getViewReasonButtonOrText()
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
viewReviewButton := widget.NewButtonWithIcon("View Review", theme.VisibilityIcon(), func(){
|
|
setViewReviewDetailsPage(window, reviewHash, currentPage)
|
|
})
|
|
|
|
viewModeratorButtonsColumn.Add(viewModeratorButton)
|
|
moderatorIdentityHashColumn.Add(identityHashLabel)
|
|
moderatorIsBannedColumn.Add(moderatorIsBannedLabel)
|
|
reviewTypeColumn.Add(reviewTypeLabel)
|
|
verdictColumn.Add(reviewVerdictLabel)
|
|
reasonColumn.Add(viewReasonButtonOrText)
|
|
viewReviewButtonsColumn.Add(viewReviewButton)
|
|
|
|
viewModeratorButtonsColumn.Add(widget.NewSeparator())
|
|
moderatorIdentityHashColumn.Add(widget.NewSeparator())
|
|
moderatorIsBannedColumn.Add(widget.NewSeparator())
|
|
reviewTypeColumn.Add(widget.NewSeparator())
|
|
verdictColumn.Add(widget.NewSeparator())
|
|
reasonColumn.Add(widget.NewSeparator())
|
|
viewReviewButtonsColumn.Add(widget.NewSeparator())
|
|
}
|
|
|
|
reviewsGrid := container.NewHBox(layout.NewSpacer(), viewModeratorButtonsColumn, moderatorIdentityHashColumn, moderatorIsBannedColumn, reviewTypeColumn, verdictColumn, reasonColumn, viewReviewButtonsColumn, layout.NewSpacer())
|
|
|
|
return true, true, reviewsGrid, nil
|
|
}
|
|
|
|
moderatorModeEnabled, parametersExist, verdictsGrid, err := getReviewerVerdictsGrid()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (moderatorModeEnabled == false){
|
|
|
|
description1 := getBoldLabelCentered("Moderator mode is disabled.")
|
|
description2 := getLabelCentered("You must enable moderator mode to view the reviewer verdicts.")
|
|
|
|
enableModeratorModeButton := getWidgetCentered(widget.NewButtonWithIcon("Enable Moderator Mode", theme.NavigateNextIcon(), func(){
|
|
setManageModeratorModePage(window, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, enableModeratorModeButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
description1 := getBoldLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for them to download.")
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
//TODO: Add button to view progress
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, refreshButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, verdictsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
// This page will show all moderators who have banned/approved the message
|
|
func setViewMessageReviewerVerdictsPage(window fyne.Window, messageHash [26]byte, viewIndex int, previousPage func()){
|
|
|
|
setLoadingScreen(window, "View Message Verdicts", "Loading verdicts...")
|
|
|
|
currentPage := func(){setViewMessageReviewerVerdictsPage(window, messageHash, viewIndex, previousPage)}
|
|
|
|
title := getPageTitleCentered("View Message Verdicts")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
messageMetadataIsKnown, _, messageNetworkType, _, messageInbox, messageCipherKeyHash, err := contentMetadata.GetMessageMetadata(messageHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (messageMetadataIsKnown == false){
|
|
|
|
description1 := getBoldLabelCentered("The message is not downloaded.")
|
|
description2 := getLabelCentered("You must download the message to view its reviews.")
|
|
description3 := getLabelCentered("It may not be possible if the message has been deleted from the network.")
|
|
description4 := getLabelCentered("Try to download the message?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButtonWithIcon("Download", theme.DownloadIcon(), func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, downloadButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (appNetworkType != messageNetworkType){
|
|
// TODO: Show an explanatory page instead of an error. Users may want to view messages by pasting a hash into a text entry lookup, without knowing which network type the message belongs to.
|
|
// Add this explanatory page for all of the relevant pages within the moderatorGui file.
|
|
setErrorEncounteredPage(window, errors.New("setViewMessageReviewerVerdictsPage called with message belonging to different network type than app."), previousPage)
|
|
return
|
|
}
|
|
|
|
downloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineMessageVerdict(messageNetworkType, messageInbox, true, messageHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (downloadingRequiredReviews == false){
|
|
|
|
description1 := getBoldLabelCentered("This message's inbox is outside of your moderator range.")
|
|
description2 := getLabelCentered("Download the reviews for this message?")
|
|
|
|
downloadButton := getWidgetCentered(widget.NewButton("Download", func(){
|
|
setDownloadReviewsAndReportsForReviewedHashPage(window, messageHash[:], currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, downloadButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := reviewStorage.GetMessageVerdictMaps(messageHash, messageNetworkType, messageCipherKeyHash)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
if (len(approveAdvocatesMap) == 0 && len(banAdvocatesMap) == 0){
|
|
|
|
noReviewersDescription := getBoldLabelCentered("No moderators have reviewed the message.")
|
|
|
|
updateButton := getWidgetCentered(widget.NewButtonWithIcon("Update", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), noReviewersDescription, updateButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
description := getLabelCentered("Below are the moderators who have reviewed the message.")
|
|
|
|
//TODO: Navigation button and pages
|
|
|
|
//Outputs:
|
|
// -bool: Downloading required reviews/profiles (moderator mode is enabled)
|
|
// -bool: Parameters exist
|
|
// -*fyne.Container: Reviewer verdicts grid
|
|
// -error
|
|
getReviewerVerdictsGrid := func()(bool, bool, *fyne.Container, error){
|
|
|
|
approveAdvocatesList := helpers.GetListOfMapKeys(approveAdvocatesMap)
|
|
banAdvocatesList := helpers.GetListOfMapKeys(banAdvocatesMap)
|
|
|
|
allReviewersList := slices.Concat(approveAdvocatesList, banAdvocatesList)
|
|
|
|
notBannedReviewersList := make([][16]byte, 0)
|
|
bannedReviewersList := make([][16]byte, 0)
|
|
|
|
for _, moderatorIdentityHash := range allReviewersList{
|
|
|
|
requiredDataIsBeingDownloaded, parametersExist, isBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(false, moderatorIdentityHash, messageNetworkType)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (requiredDataIsBeingDownloaded == false){
|
|
return false, parametersExist, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, nil, nil
|
|
}
|
|
|
|
if (isBanned == true){
|
|
bannedReviewersList = append(bannedReviewersList, moderatorIdentityHash)
|
|
} else{
|
|
notBannedReviewersList = append(notBannedReviewersList, moderatorIdentityHash)
|
|
}
|
|
}
|
|
|
|
err := helpers.SortIdentityHashListToUnicodeOrder(notBannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
err = helpers.SortIdentityHashListToUnicodeOrder(bannedReviewersList)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
allReviewersListSorted := slices.Concat(notBannedReviewersList, bannedReviewersList)
|
|
|
|
//TODO: Add pages and navigation
|
|
|
|
emptyLabelA := widget.NewLabel("")
|
|
authorLabel := getItalicLabelCentered("Author")
|
|
isBannedLabel := getItalicLabelCentered("Is Banned")
|
|
verdictLabel := getItalicLabelCentered("Verdict")
|
|
reasonLabel := getItalicLabelCentered("Reason")
|
|
emptyLabelC := widget.NewLabel("")
|
|
|
|
viewModeratorButtonsColumn := container.NewVBox(emptyLabelA, widget.NewSeparator())
|
|
moderatorIdentityHashColumn := container.NewVBox(authorLabel, widget.NewSeparator())
|
|
moderatorIsBannedColumn := container.NewVBox(isBannedLabel, widget.NewSeparator())
|
|
verdictColumn := container.NewVBox(verdictLabel, widget.NewSeparator())
|
|
reasonColumn := container.NewVBox(reasonLabel, widget.NewSeparator())
|
|
viewReviewButtonsColumn := container.NewVBox(emptyLabelC, widget.NewSeparator())
|
|
|
|
for _, moderatorIdentityHash := range allReviewersListSorted{
|
|
|
|
viewModeratorButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewModeratorDetailsPage(window, moderatorIdentityHash, currentPage)
|
|
})
|
|
|
|
moderatorIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
identityHashTrimmed, _, err := helpers.TrimAndFlattenString(moderatorIdentityHashString, 10)
|
|
if (err != nil) { return false, false, nil, err }
|
|
identityHashLabel := getBoldLabelCentered(identityHashTrimmed)
|
|
|
|
moderatorIsBannedBool := slices.Contains(bannedReviewersList, moderatorIdentityHash)
|
|
moderatorIsBanned := helpers.ConvertBoolToYesOrNoString(moderatorIsBannedBool)
|
|
moderatorIsBannedTranslated := translate(moderatorIsBanned)
|
|
|
|
moderatorIsBannedLabel := getBoldLabelCentered(moderatorIsBannedTranslated)
|
|
|
|
reviewFound, newestReviewBytes, _, err := reviewStorage.GetModeratorNewestMessageReview(moderatorIdentityHash, messageHash, messageNetworkType, messageCipherKeyHash)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (reviewFound == false){
|
|
// Review was deleted or changed after reviewers were retrieved
|
|
continue
|
|
}
|
|
|
|
ableToRead, reviewHash, _, reviewNetworkType, retrievedModeratorIdentityHash, _, _, currentReviewedHash, reviewVerdict, reviewMap, err := readReviews.ReadReviewAndHash(false, newestReviewBytes)
|
|
if (err != nil) { return false, false, nil, err }
|
|
if (ableToRead == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestMessageReview returning invalid review.")
|
|
}
|
|
if (reviewNetworkType != messageNetworkType){
|
|
return false, false, nil, errors.New("GetModeratorNewestMessageReview returning review belonging to different networkType.")
|
|
}
|
|
if (moderatorIdentityHash != retrievedModeratorIdentityHash) {
|
|
return false, false, nil, errors.New("GetModeratorNewestMessageReview returning review by different moderator.")
|
|
}
|
|
areEqual := bytes.Equal(currentReviewedHash, messageHash[:])
|
|
if (areEqual == false){
|
|
return false, false, nil, errors.New("GetModeratorNewestMessageReview returning review for different reviewedHash.")
|
|
}
|
|
|
|
reviewVerdictTranslated := translate(reviewVerdict)
|
|
reviewVerdictLabel := getBoldLabelCentered(reviewVerdictTranslated)
|
|
|
|
getViewReasonButtonOrText := func()(*fyne.Container, error){
|
|
|
|
reasonString, exists := reviewMap["Reason"]
|
|
if (exists == false) {
|
|
noneLabel := getBoldLabelCentered(translate("None"))
|
|
return noneLabel, nil
|
|
}
|
|
|
|
viewReasonButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Verdict Reason", reasonString, false, currentPage)
|
|
}))
|
|
|
|
return viewReasonButton, nil
|
|
}
|
|
viewReasonButtonOrText, err := getViewReasonButtonOrText()
|
|
if (err != nil) { return false, false, nil, err }
|
|
|
|
viewReviewButton := widget.NewButtonWithIcon("View Review", theme.VisibilityIcon(), func(){
|
|
setViewReviewDetailsPage(window, reviewHash, currentPage)
|
|
})
|
|
|
|
viewModeratorButtonsColumn.Add(viewModeratorButton)
|
|
moderatorIdentityHashColumn.Add(identityHashLabel)
|
|
moderatorIsBannedColumn.Add(moderatorIsBannedLabel)
|
|
verdictColumn.Add(reviewVerdictLabel)
|
|
reasonColumn.Add(viewReasonButtonOrText)
|
|
viewReviewButtonsColumn.Add(viewReviewButton)
|
|
|
|
viewModeratorButtonsColumn.Add(widget.NewSeparator())
|
|
moderatorIdentityHashColumn.Add(widget.NewSeparator())
|
|
moderatorIsBannedColumn.Add(widget.NewSeparator())
|
|
verdictColumn.Add(widget.NewSeparator())
|
|
reasonColumn.Add(widget.NewSeparator())
|
|
viewReviewButtonsColumn.Add(widget.NewSeparator())
|
|
}
|
|
|
|
reviewsGrid := container.NewHBox(layout.NewSpacer(), viewModeratorButtonsColumn, moderatorIdentityHashColumn, moderatorIsBannedColumn, verdictColumn, reasonColumn, viewReviewButtonsColumn, layout.NewSpacer())
|
|
|
|
return true, true, reviewsGrid, nil
|
|
}
|
|
|
|
moderatorModeEnabled, parametersExist, verdictsGrid, err := getReviewerVerdictsGrid()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (moderatorModeEnabled == false){
|
|
|
|
description1 := getBoldLabelCentered("Moderator mode is disabled.")
|
|
description2 := getLabelCentered("You must enable moderator mode to view the reviewer verdicts.")
|
|
|
|
enableModeratorModeButton := getWidgetCentered(widget.NewButtonWithIcon("Enable Moderator Mode", theme.NavigateNextIcon(), func(){
|
|
setManageModeratorModePage(window, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, enableModeratorModeButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
|
|
description1 := getBoldLabelCentered("Your app is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for them to download.")
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
//TODO: Add button to view progress
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, refreshButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), verdictsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setViewModeratorDetailsPage(window fyne.Window, moderatorIdentityHash [16]byte, previousPage func()){
|
|
|
|
appMemory.SetMemoryEntry("CurrentViewedPage", "ModeratorDetails")
|
|
|
|
currentPage := func(){setViewModeratorDetailsPage(window, moderatorIdentityHash, previousPage)}
|
|
|
|
moderatorIdentityHashString, userIdentityType, err := identity.EncodeIdentityHashBytesToString(moderatorIdentityHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (userIdentityType != "Moderator"){
|
|
setErrorEncounteredPage(window, errors.New("ViewModeratorDetailsPage called with non-moderator identity: " + moderatorIdentityHashString), previousPage)
|
|
return
|
|
}
|
|
|
|
title := getPageTitleCentered("Moderator Details")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
identityHashLabel := widget.NewLabel("Identity Hash:")
|
|
identityHashText := getBoldLabel(moderatorIdentityHashString)
|
|
identityHashRow := container.NewHBox(layout.NewSpacer(), identityHashLabel, identityHashText, layout.NewSpacer())
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
rankingKnown, moderatorRank, totalNumberOfModerators, err := moderatorRanking.GetModeratorRanking(moderatorIdentityHash, appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
getModeratorRankText := func()string{
|
|
if (rankingKnown == false){
|
|
result := translate("Unknown")
|
|
return result
|
|
}
|
|
|
|
moderatorRankString := helpers.ConvertIntToString(moderatorRank)
|
|
totalNumberOfModeratorsString := helpers.ConvertIntToString(totalNumberOfModerators)
|
|
|
|
moderatorRankText := moderatorRankString + "/" + totalNumberOfModeratorsString
|
|
|
|
return moderatorRankText
|
|
}
|
|
|
|
moderatorRankText := getModeratorRankText()
|
|
|
|
moderatorRankTitle := widget.NewLabel("Moderator Rank:")
|
|
moderatorRankLabel := getBoldLabel(moderatorRankText)
|
|
|
|
moderatorRankRow := container.NewHBox(layout.NewSpacer(), moderatorRankTitle, moderatorRankLabel, layout.NewSpacer())
|
|
|
|
showModeratorModeIsDisabledPage := func(){
|
|
|
|
description1 := getBoldLabelCentered("Moderator mode is disabled.")
|
|
description2 := getLabelCentered("You must enable moderator mode to view the moderator details.")
|
|
|
|
enableModeratorModeButton := getWidgetCentered(widget.NewButtonWithIcon("Enable Moderator Mode", theme.NavigateNextIcon(), func(){
|
|
setManageModeratorModePage(window, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, enableModeratorModeButton)
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
moderatorModeIsEnabled, parametersExist, isBannedStatus, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(false, moderatorIdentityHash, appNetworkType)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (moderatorModeIsEnabled == false){
|
|
|
|
showModeratorModeIsDisabledPage()
|
|
return
|
|
}
|
|
if (parametersExist == false){
|
|
|
|
description1 := getBoldLabelCentered("Your client is missing the moderation parameters.")
|
|
description2 := getLabelCentered("Please wait for them to download.")
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), currentPage))
|
|
|
|
//TODO: Add button to view progress
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, refreshButton)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
getBannedStatusString := func()string{
|
|
if (isBannedStatus == true){
|
|
return "Banned"
|
|
}
|
|
return "Not Banned"
|
|
}
|
|
bannedStatusString := getBannedStatusString()
|
|
|
|
isBannedLabel := widget.NewLabel("Moderation Status:")
|
|
bannedStatusLabel := getBoldLabel(bannedStatusString)
|
|
bannedStatusRow := container.NewHBox(layout.NewSpacer(), isBannedLabel, bannedStatusLabel, layout.NewSpacer())
|
|
|
|
downloadingRequiredReviews, numberOfBanAdvocates, err := reviewStorage.GetNumberOfBanAdvocatesForIdentity(moderatorIdentityHash, appNetworkType)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (downloadingRequiredReviews == false){
|
|
showModeratorModeIsDisabledPage()
|
|
return
|
|
}
|
|
|
|
numberOfBanAdvocatesString := helpers.ConvertIntToString(numberOfBanAdvocates)
|
|
|
|
numberOfBanAdvocatesLabel := widget.NewLabel("Number Of Ban Advocates:")
|
|
numberOfBanAdvocatesText := getBoldLabel(numberOfBanAdvocatesString)
|
|
numberOfBanAdvocatesRow := container.NewHBox(layout.NewSpacer(), numberOfBanAdvocatesLabel, numberOfBanAdvocatesText, layout.NewSpacer())
|
|
|
|
viewProfileButton := widget.NewButtonWithIcon("View Profile", theme.AccountIcon(), func(){
|
|
setViewPeerProfilePageFromIdentityHash(window, moderatorIdentityHash, currentPage)
|
|
})
|
|
|
|
viewReviewsButton := widget.NewButtonWithIcon("View Reviews", theme.ListIcon(), func(){
|
|
setViewAllReviewsCreatedByModeratorPage(window, moderatorIdentityHash, "Profile", 0, currentPage)
|
|
})
|
|
|
|
viewBanAdvocatesButton := widget.NewButtonWithIcon("View Ban Advocates", theme.ErrorIcon(), func(){
|
|
setViewIdentityReviewerVerdictsPage(window, moderatorIdentityHash, 0, currentPage)
|
|
})
|
|
|
|
viewStatisticsButton := widget.NewButtonWithIcon("View Statistics", theme.InfoIcon(), func(){
|
|
//TODO: A page to view a user's moderation statistics
|
|
// An example is the percentage of profiles/attributes/messages they have banned/approved
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
|
|
buttonsGrid := getContainerCentered(container.NewGridWithColumns(1, viewProfileButton, viewReviewsButton, viewBanAdvocatesButton, viewStatisticsButton))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), identityHashRow, widget.NewSeparator(), moderatorRankRow, widget.NewSeparator(), bannedStatusRow, widget.NewSeparator(), numberOfBanAdvocatesRow, widget.NewSeparator(), buttonsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setViewAllReviewsCreatedByModeratorPage(window fyne.Window, moderatorIdentityHash [16]byte, reviewType string, viewIndex int64, previousPage func()){
|
|
|
|
if (reviewType != "Identity" && reviewType != "Profile" && reviewType != "Attribute" && reviewType != "Message"){
|
|
setErrorEncounteredPage(window, errors.New("setViewAllReviewsCreatedByModeratorPage called with invalid reviewType: " + reviewType), previousPage)
|
|
return
|
|
}
|
|
|
|
userIdentityType, err := identity.GetIdentityTypeFromIdentityHash(moderatorIdentityHash)
|
|
if (err != nil) {
|
|
moderatorIdentityHashHex := encoding.EncodeBytesToHexString(moderatorIdentityHash[:])
|
|
setErrorEncounteredPage(window, errors.New("setViewAllReviewsCreatedByModeratorPage called with invalid identity hash: " + moderatorIdentityHashHex), previousPage)
|
|
return
|
|
}
|
|
if (userIdentityType != "Moderator"){
|
|
setErrorEncounteredPage(window, errors.New("setViewAllReviewsCreatedByModeratorPage called with non-moderator identity."), previousPage)
|
|
return
|
|
}
|
|
|
|
currentPage := func(){setViewAllReviewsCreatedByModeratorPage(window, moderatorIdentityHash, reviewType, viewIndex, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Moderator Reviews")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
reviewTypeTitle := getBoldLabelCentered("Review Type:")
|
|
|
|
reviewTypesList := []string{"Identity", "Profile", "Attribute", "Message"}
|
|
|
|
handleSelectFunction := func(newReviewType string){
|
|
|
|
setViewAllReviewsCreatedByModeratorPage(window, moderatorIdentityHash, newReviewType, 0, previousPage)
|
|
}
|
|
|
|
reviewTypeSelector := widget.NewSelect(reviewTypesList, handleSelectFunction)
|
|
reviewTypeSelector.Selected = reviewType
|
|
|
|
reviewTypeSelectorCentered := getWidgetCentered(reviewTypeSelector)
|
|
|
|
description := getLabelCentered("These are the " + reviewType + " reviews created by the moderator.")
|
|
|
|
getReviewsGrid := func()(*fyne.Container, error){
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) { return nil, err }
|
|
|
|
reviewedHashLabel := getItalicLabelCentered("Reviewed Hash")
|
|
verdictLabel := getItalicLabelCentered("Verdict")
|
|
reasonLabel := getItalicLabelCentered("Reason")
|
|
emptyLabelA := widget.NewLabel("")
|
|
|
|
reviewedHashColumn := container.NewVBox(reviewedHashLabel, widget.NewSeparator())
|
|
verdictColumn := container.NewVBox(verdictLabel, widget.NewSeparator())
|
|
reasonColumn := container.NewVBox(reasonLabel, widget.NewSeparator())
|
|
viewReviewButtonsColumn := container.NewVBox(emptyLabelA, widget.NewSeparator())
|
|
|
|
reviewsList, err := reviewStorage.GetAllNewestReviewsCreatedByModerator(moderatorIdentityHash, reviewType, appNetworkType)
|
|
if (err != nil) { return nil, err }
|
|
|
|
if (len(reviewsList) == 0){
|
|
noReviewsExistLabel := getBoldLabelCentered("No " + reviewType + " reviews exist.")
|
|
return noReviewsExistLabel, nil
|
|
}
|
|
|
|
//TODO: Add sort reviews alphabetically and navigation buttons
|
|
|
|
for _, reviewBytes := range reviewsList{
|
|
|
|
ableToRead, reviewHash, _, reviewNetworkType, reviewerIdentityHash, _, currentReviewType, reviewedHash, reviewVerdict, reviewMap, err := readReviews.ReadReviewAndHash(false, reviewBytes)
|
|
if (err != nil) { return nil, err }
|
|
if (ableToRead == false){
|
|
return nil, errors.New("GetAllNewestReviewsCreatedByModerator returning invalid review.")
|
|
}
|
|
if (reviewNetworkType != appNetworkType){
|
|
return nil, errors.New("GetAllNewestReviewsCreatedByModerator returning review belonging to different networkType.")
|
|
}
|
|
if (reviewerIdentityHash != moderatorIdentityHash) {
|
|
return nil, errors.New("GetAllNewestReviewsCreatedByModerator returning review by different moderator.")
|
|
}
|
|
if (currentReviewType != reviewType){
|
|
return nil, errors.New("GetAllNewestReviewsCreatedByModerator returning review of different reviewType")
|
|
}
|
|
|
|
reviewedHashString, err := helpers.EncodeReviewedHashBytesToString(reviewedHash)
|
|
if (err != nil) { return nil, err }
|
|
|
|
reviewedHashTrimmed, _, err := helpers.TrimAndFlattenString(reviewedHashString, 10)
|
|
if (err != nil) { return nil, err }
|
|
|
|
reviewedHashLabel := getBoldLabelCentered(reviewedHashTrimmed)
|
|
|
|
verdictLabel := getBoldLabelCentered(reviewVerdict)
|
|
|
|
getViewReasonButtonOrLabel := func()*fyne.Container{
|
|
reasonString, exists := reviewMap["Reason"]
|
|
if (exists == false) {
|
|
noneLabel := getBoldLabelCentered("None")
|
|
return noneLabel
|
|
}
|
|
viewReasonButton := getWidgetCentered(widget.NewButtonWithIcon("", theme.InfoIcon(), func(){
|
|
setViewTextPage(window, "Viewing Verdict Reason", reasonString, false, currentPage)
|
|
}))
|
|
|
|
return viewReasonButton
|
|
}
|
|
viewReasonButtonOrLabel := getViewReasonButtonOrLabel()
|
|
|
|
viewReviewButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewReviewDetailsPage(window, reviewHash, currentPage)
|
|
})
|
|
|
|
reviewedHashColumn.Add(reviewedHashLabel)
|
|
verdictColumn.Add(verdictLabel)
|
|
reasonColumn.Add(viewReasonButtonOrLabel)
|
|
viewReviewButtonsColumn.Add(viewReviewButton)
|
|
|
|
reviewedHashColumn.Add(widget.NewSeparator())
|
|
verdictColumn.Add(widget.NewSeparator())
|
|
reasonColumn.Add(widget.NewSeparator())
|
|
viewReviewButtonsColumn.Add(widget.NewSeparator())
|
|
}
|
|
|
|
reviewsGrid := container.NewHBox(layout.NewSpacer(), reviewedHashColumn, verdictColumn, reasonColumn, viewReviewButtonsColumn, layout.NewSpacer())
|
|
|
|
return reviewsGrid, nil
|
|
}
|
|
|
|
reviewsGrid, err := getReviewsGrid()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), reviewTypeTitle, reviewTypeSelectorCentered, widget.NewSeparator(), description, widget.NewSeparator(), reviewsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setViewReviewDetailsPage(window fyne.Window, reviewHash [29]byte, previousPage func()){
|
|
|
|
currentPage := func(){setViewReviewDetailsPage(window, reviewHash, previousPage)}
|
|
|
|
title := getPageTitleCentered("Viewing Review Details")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
exists, reviewBytes, err := badgerDatabase.GetReview(reviewHash)
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (exists == false){
|
|
|
|
description := getBoldLabelCentered("Review not found.")
|
|
|
|
//TODO: Download review
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description)
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
getPageContent := func()(*fyne.Container, error){
|
|
|
|
ableToRead, currentReviewHash, _, reviewNetworkType, reviewerIdentityHash, reviewCreationTime, reviewType, reviewedHash, reviewVerdict, reviewMap, err := readReviews.ReadReviewAndHash(false, reviewBytes)
|
|
if (err != nil) { return nil, err }
|
|
if (ableToRead == false){
|
|
return nil, errors.New("Database corrupt: Contains invalid review.")
|
|
}
|
|
if (reviewHash != currentReviewHash) {
|
|
return nil, errors.New("Database corrupt: Review entry key does not match review hash")
|
|
}
|
|
|
|
reviewNetworkTypeLabel := widget.NewLabel("Review Network Type:")
|
|
|
|
reviewNetworkTypeString := helpers.ConvertByteToString(reviewNetworkType)
|
|
|
|
reviewNetworkTypeText := getBoldLabel(reviewNetworkTypeString)
|
|
|
|
reviewNetworkTypeRow := container.NewHBox(layout.NewSpacer(), reviewNetworkTypeLabel, reviewNetworkTypeText, layout.NewSpacer())
|
|
|
|
reviewAuthorLabel := widget.NewLabel("Review Author:")
|
|
|
|
reviewerIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(reviewerIdentityHash)
|
|
if (err != nil) { return nil, err }
|
|
|
|
reviewerIdentityHashTrimmed, _, err := helpers.TrimAndFlattenString(reviewerIdentityHashString, 15)
|
|
if (err != nil) { return nil, err }
|
|
|
|
viewReviewAuthorButton := widget.NewButtonWithIcon(reviewerIdentityHashTrimmed, theme.VisibilityIcon(), func(){
|
|
setViewModeratorDetailsPage(window, reviewerIdentityHash, currentPage)
|
|
})
|
|
|
|
reviewerIdentityRow := container.NewHBox(layout.NewSpacer(), reviewAuthorLabel, viewReviewAuthorButton, layout.NewSpacer())
|
|
|
|
reviewHashTitle := widget.NewLabel("Review Hash:")
|
|
|
|
reviewHashHex := encoding.EncodeBytesToHexString(reviewHash[:])
|
|
|
|
reviewHashTrimmed, _, err := helpers.TrimAndFlattenString(reviewHashHex, 10)
|
|
if (err != nil) { return nil, err }
|
|
reviewHashLabel := getBoldLabel(reviewHashTrimmed)
|
|
viewReviewHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewContentHashPage(window, "Review", reviewHash[:], currentPage)
|
|
})
|
|
reviewHashRow := container.NewHBox(layout.NewSpacer(), reviewHashTitle, reviewHashLabel, viewReviewHashButton, layout.NewSpacer())
|
|
|
|
reviewTypeTitle := widget.NewLabel("Review Type:")
|
|
reviewTypeLabel := getBoldLabel(reviewType)
|
|
reviewTypeRow := container.NewHBox(layout.NewSpacer(), reviewTypeTitle, reviewTypeLabel, layout.NewSpacer())
|
|
|
|
reviewedHashTitle := widget.NewLabel("Reviewed Hash:")
|
|
|
|
reviewedHashString, err := helpers.EncodeReviewedHashBytesToString(reviewedHash)
|
|
if (err != nil) { return nil, err }
|
|
|
|
reviewedHashTrimmed, _, err := helpers.TrimAndFlattenString(reviewedHashString, 10)
|
|
if (err != nil) { return nil, err }
|
|
reviewedHashLabel := getBoldLabel(reviewedHashTrimmed)
|
|
viewReviewedHashButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
|
|
if (reviewType == "Identity"){
|
|
|
|
if (len(reviewedHash) != 16){
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid reviewedHash length."), previousPage)
|
|
return
|
|
}
|
|
|
|
reviewedIdentityHash := [16]byte(reviewedHash)
|
|
|
|
setViewIdentityHashPage(window, reviewedIdentityHash, currentPage)
|
|
} else {
|
|
setViewContentHashPage(window, reviewType, reviewedHash, currentPage)
|
|
}
|
|
})
|
|
reviewedHashRow := container.NewHBox(layout.NewSpacer(), reviewedHashTitle, reviewedHashLabel, viewReviewedHashButton, layout.NewSpacer())
|
|
|
|
creationTimeTranslated, err := helpers.ConvertUnixTimeToTimeFromNowTranslated(reviewCreationTime, true)
|
|
if (err != nil ){ return nil, err }
|
|
|
|
creationTimeTitle := widget.NewLabel("Creation Time:")
|
|
creationTimeLabel := getBoldLabel(creationTimeTranslated)
|
|
creationTimeWarningButton := widget.NewButtonWithIcon("", theme.WarningIcon(), func(){
|
|
title := translate("Creation Time Warning")
|
|
dialogMessage := "Creation times are not verified. They can be faked by the reviewer."
|
|
dialogContent := container.NewVBox(widget.NewLabel(dialogMessage))
|
|
dialog.ShowCustom(title, translate("Close"), dialogContent, window)
|
|
})
|
|
creationTimeRow := container.NewHBox(layout.NewSpacer(), creationTimeTitle, creationTimeLabel, creationTimeWarningButton, layout.NewSpacer())
|
|
|
|
verdictTitle := widget.NewLabel("Verdict:")
|
|
verdictLabel := getBoldLabel(reviewVerdict)
|
|
verdictRow := container.NewHBox(layout.NewSpacer(), verdictTitle, verdictLabel, layout.NewSpacer())
|
|
|
|
getReviewReasonRow := func()(*fyne.Container, error){
|
|
|
|
reasonTitle := widget.NewLabel("Reason:")
|
|
|
|
reasonString, exists := reviewMap["Reason"]
|
|
if (exists == false){
|
|
noneLabel := getBoldItalicLabel(translate("None"))
|
|
reasonRow := container.NewHBox(layout.NewSpacer(), reasonTitle, noneLabel, layout.NewSpacer())
|
|
|
|
return reasonRow, nil
|
|
}
|
|
|
|
reasonTrimmed, _, err := helpers.TrimAndFlattenString(reasonString, 20)
|
|
if (err != nil) { return nil, err }
|
|
reasonLabel := getBoldLabel(reasonTrimmed)
|
|
viewReasonButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Review Reason", reasonString, false, currentPage)
|
|
})
|
|
|
|
reasonRow := container.NewHBox(layout.NewSpacer(), reasonTitle, reasonLabel, viewReasonButton, layout.NewSpacer())
|
|
|
|
return reasonRow, nil
|
|
}
|
|
|
|
reasonRow, err := getReviewReasonRow()
|
|
if (err != nil) { return nil, err }
|
|
|
|
pageContent := container.NewVBox(reviewNetworkTypeRow, widget.NewSeparator(), reviewerIdentityRow, widget.NewSeparator(), reviewHashRow, widget.NewSeparator(), reviewTypeRow, widget.NewSeparator(), reviewedHashRow, widget.NewSeparator(), creationTimeRow, widget.NewSeparator(), verdictRow, widget.NewSeparator(), reasonRow, widget.NewSeparator())
|
|
|
|
if (reviewType == "Identity"){
|
|
_, exists := reviewMap["ErrantMessages"]
|
|
if (exists == true){
|
|
|
|
errantMessagesTitle := widget.NewLabel("Errant Messages:")
|
|
errantMessagesRow := container.NewHBox(layout.NewSpacer(), errantMessagesTitle, layout.NewSpacer())
|
|
|
|
pageContent.Add(errantMessagesRow)
|
|
//TODO: Add errant Profiles and reviews, and add buttons to view each.
|
|
}
|
|
}
|
|
|
|
if (reviewType != "Identity"){
|
|
|
|
viewReviewedContentOrIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("View Reviewed " + reviewType, theme.VisibilityIcon(), func(){
|
|
if (reviewType == "Message"){
|
|
|
|
if (len(reviewedHash) != 26){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedMessageHash := [26]byte(reviewedHash)
|
|
|
|
setViewMessageForModerationPage(window, reviewedMessageHash, currentPage)
|
|
} else if (reviewType == "Profile"){
|
|
|
|
if (len(reviewedHash) != 28){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedProfileHash := [28]byte(reviewedHash)
|
|
|
|
setViewProfileForModerationPage(window, reviewedProfileHash, currentPage)
|
|
} else if (reviewType == "Attribute"){
|
|
|
|
if (len(reviewedHash) != 27){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedAttributeHash := [27]byte(reviewedHash)
|
|
|
|
setViewProfileAttributeForModerationPage(window, reviewedAttributeHash, currentPage)
|
|
}
|
|
}))
|
|
|
|
pageContent.Add(viewReviewedContentOrIdentityButton)
|
|
}
|
|
|
|
viewReviewedHashModerationDetailsButton := getWidgetCentered(widget.NewButtonWithIcon("View Reviewed " + reviewType + " Details", theme.VisibilityIcon(), func(){
|
|
|
|
if (reviewType == "Identity"){
|
|
|
|
if (len(reviewedHash) != 16){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Identity review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedIdentityHash := [16]byte(reviewedHash)
|
|
|
|
setViewIdentityModerationDetailsPage(window, reviewedIdentityHash, currentPage)
|
|
|
|
} else if (reviewType == "Profile"){
|
|
|
|
if (len(reviewedHash) != 28){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Profile review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedProfileHash := [28]byte(reviewedHash)
|
|
|
|
setViewProfileModerationDetailsPage(window, reviewedProfileHash, currentPage)
|
|
|
|
} else if (reviewType == "Attribute"){
|
|
|
|
if (len(reviewedHash) != 27){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Attribute review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedAttributeHash := [27]byte(reviewedHash)
|
|
|
|
setViewAttributeModerationDetailsPage(window, reviewedAttributeHash, currentPage)
|
|
|
|
} else if (reviewType == "Message"){
|
|
|
|
if (len(reviewedHash) != 26){
|
|
reviewedHashHex := encoding.EncodeBytesToHexString(reviewedHash)
|
|
setErrorEncounteredPage(window, errors.New("ReadReview returning invalid length reviewedHash for Message review: " + reviewedHashHex), currentPage)
|
|
return
|
|
}
|
|
|
|
reviewedMessageHash := [26]byte(reviewedHash)
|
|
|
|
setViewMessageModerationDetailsPage(window, reviewedMessageHash, currentPage)
|
|
}
|
|
}))
|
|
|
|
pageContent.Add(viewReviewedHashModerationDetailsButton)
|
|
|
|
//TODO: Add anything else?
|
|
|
|
return pageContent, nil
|
|
}
|
|
|
|
pageContent, err := getPageContent()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), pageContent)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setModeratorSettingsPage(window fyne.Window, previousPage func()){
|
|
|
|
currentPage := func(){setModeratorSettingsPage(window, previousPage)}
|
|
|
|
title := getPageTitleCentered("Moderator Settings")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description := getLabelCentered("Manage your moderation settings.")
|
|
|
|
getSettingsGrid := func()(*fyne.Container, error){
|
|
|
|
settingTitleColumn := container.NewVBox()
|
|
settingStatusColumn := container.NewVBox()
|
|
manageSettingButtonsColumn := container.NewVBox()
|
|
|
|
addSettingRow := func(addSeparator bool, settingTitle string, settingName string, defaultIsOn bool, manageSettingPage func())error{
|
|
|
|
settingTitleLabel := getBoldLabelCentered(settingTitle)
|
|
|
|
getSettingOnOffStatus := func()(string, error){
|
|
|
|
exists, settingOnOffStatus, err := mySettings.GetSetting(settingName)
|
|
if (err != nil){ return "", err }
|
|
if (exists == false){
|
|
if (defaultIsOn == true){
|
|
return "On", nil
|
|
}
|
|
return "Off", nil
|
|
}
|
|
return settingOnOffStatus, nil
|
|
}
|
|
|
|
settingStatus, err := getSettingOnOffStatus()
|
|
if (err != nil) { return err }
|
|
|
|
settingStatusLabel := getBoldLabelCentered(settingStatus)
|
|
|
|
manageSettingButton := widget.NewButtonWithIcon("Manage", theme.SettingsIcon(), manageSettingPage)
|
|
|
|
settingTitleColumn.Add(settingTitleLabel)
|
|
settingStatusColumn.Add(settingStatusLabel)
|
|
manageSettingButtonsColumn.Add(manageSettingButton)
|
|
|
|
if (addSeparator == true){
|
|
|
|
settingTitleColumn.Add(widget.NewSeparator())
|
|
settingStatusColumn.Add(widget.NewSeparator())
|
|
manageSettingButtonsColumn.Add(widget.NewSeparator())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err := addSettingRow(true, "Moderator Mode", "ModeratorModeOnOffStatus", false, func(){
|
|
setManageModeratorModePage(window, currentPage)
|
|
})
|
|
if (err != nil) { return nil, err }
|
|
|
|
err = addSettingRow(true, "Moderate Messages", "ModerateMessagesOnOffStatus", false, func(){
|
|
setManageModerateMessagesModePage(window, currentPage)
|
|
})
|
|
if (err != nil) { return nil, err }
|
|
|
|
err = addSettingRow(true, "Moderate Mate Identities", "ModerateMateContentOnOffStatus", true, func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
if (err != nil) { return nil, err }
|
|
|
|
err = addSettingRow(true, "Moderate Host Identities", "ModerateHostContentOnOffStatus", true, func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
if (err != nil) { return nil, err }
|
|
|
|
err = addSettingRow(true, "Moderate Moderator Identities", "ModerateModeratorContentOnOffStatus", true, func(){
|
|
//TODO
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
if (err != nil) { return nil, err }
|
|
|
|
settingsGrid := container.NewHBox(layout.NewSpacer(), settingTitleColumn, settingStatusColumn, manageSettingButtonsColumn, layout.NewSpacer())
|
|
|
|
return settingsGrid, nil
|
|
}
|
|
|
|
settingsGrid, err := getSettingsGrid()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description, widget.NewSeparator(), settingsGrid)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setManageModeratorModePage(window fyne.Window, previousPage func()){
|
|
|
|
currentPage := func(){setManageModeratorModePage(window, previousPage)}
|
|
|
|
title := getPageTitleCentered("Manage Moderator Mode")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
subtitle := getPageSubtitleCentered("Moderator Mode")
|
|
|
|
description1 := getLabelCentered("Activate this mode if you want to be a moderator.")
|
|
description2 := getLabelCentered("Seekia will start downloading content for you to moderate.")
|
|
|
|
getModeratorModeStatus := func()(string, error){
|
|
exists, moderatorModeStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
|
|
if (err != nil){ return "", err }
|
|
if (exists == false){
|
|
return "Off", nil
|
|
}
|
|
if (moderatorModeStatus != "On" && moderatorModeStatus != "Off"){
|
|
return "", errors.New("MySettings malformed: Invalid moderator mode status: " + moderatorModeStatus)
|
|
}
|
|
return moderatorModeStatus, nil
|
|
}
|
|
|
|
moderatorModeStatus, err := getModeratorModeStatus()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
moderatorModeStatusLabel := getLabelCentered("Moderator Mode Status:")
|
|
moderatorModeStatusText := getBoldLabelCentered(moderatorModeStatus)
|
|
|
|
getEnableDisableText := func()string{
|
|
if (moderatorModeStatus == "On"){
|
|
return "Disable"
|
|
}
|
|
return "Enable"
|
|
}
|
|
|
|
enableDisableText := getEnableDisableText()
|
|
|
|
enableDisableButton := getWidgetCentered(widget.NewButton(enableDisableText, func(){
|
|
|
|
if (moderatorModeStatus == "On"){
|
|
err := mySettings.SetSetting("ModeratorModeOnOffStatus", "Off")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
currentPage()
|
|
return
|
|
}
|
|
setConfirmEnableModeratorModePage(window, currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, widget.NewSeparator(), moderatorModeStatusLabel, moderatorModeStatusText, enableDisableButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setConfirmEnableModeratorModePage(window fyne.Window, previousPage func(), nextPage func()){
|
|
|
|
title := getPageTitleCentered("Enable Moderator Mode")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description1 := getBoldLabelCentered("Enable Moderator Mode?")
|
|
|
|
description2 := getLabelCentered("This mode will download unapproved content for you to moderate.")
|
|
description3 := getLabelCentered("This content may contain illegal and unruleful content.")
|
|
description4 := getLabelCentered("You must accept the legal risks of downloading this content.")
|
|
|
|
enableButton := getWidgetCentered(widget.NewButtonWithIcon("Enable", theme.ConfirmIcon(), func(){
|
|
err := mySettings.SetSetting("ModeratorModeOnOffStatus", "On")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
nextPage()
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, enableButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
|
|
func setManageModerateMessagesModePage(window fyne.Window, previousPage func()){
|
|
|
|
currentPage := func(){setManageModeratorModePage(window, previousPage)}
|
|
|
|
title := getPageTitleCentered("Manage Moderate Messages Mode")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
subtitle := getPageSubtitleCentered("Moderate Messages Mode")
|
|
|
|
description1 := getLabelCentered("Activate this mode if you want to moderate messages.")
|
|
description2 := getLabelCentered("Seekia will start downloading messages for you to moderate.")
|
|
description3 := getLabelCentered("You will be reviewing messages which have been reported by users.")
|
|
description4 := getLabelCentered("Be aware that these messages are more likely to contain unruleful content.")
|
|
|
|
getModerateMessagesModeStatus := func()(string, error){
|
|
exists, moderateMessagesModeStatus, err := mySettings.GetSetting("ModerateMessagesOnOffStatus")
|
|
if (err != nil){ return "", err }
|
|
if (exists == false){
|
|
return "Off", nil
|
|
}
|
|
if (moderateMessagesModeStatus != "On" && moderateMessagesModeStatus != "Off"){
|
|
return "", errors.New("MySettings malformed: Invalid moderate messages mode status: " + moderateMessagesModeStatus)
|
|
}
|
|
return moderateMessagesModeStatus, nil
|
|
}
|
|
|
|
moderateMessagesModeStatus, err := getModerateMessagesModeStatus()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
moderateMessagesModeStatusLabel := getLabelCentered("Moderate Messages Mode Status:")
|
|
moderateMessagesModeStatusText := getBoldLabelCentered(moderateMessagesModeStatus)
|
|
|
|
getEnableDisableText := func()string{
|
|
if (moderateMessagesModeStatus == "On"){
|
|
return "Disable"
|
|
}
|
|
return "Enable"
|
|
}
|
|
|
|
enableDisableText := getEnableDisableText()
|
|
|
|
enableDisableButton := getWidgetCentered(widget.NewButton(enableDisableText, func(){
|
|
|
|
if (moderateMessagesModeStatus == "On"){
|
|
err := mySettings.SetSetting("ModerateMessagesOnOffStatus", "Off")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, currentPage)
|
|
return
|
|
}
|
|
currentPage()
|
|
return
|
|
}
|
|
setConfirmEnableModerateMessagesModePage(window, currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), subtitle, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), moderateMessagesModeStatusLabel, moderateMessagesModeStatusText, enableDisableButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setConfirmEnableModerateMessagesModePage(window fyne.Window, previousPage func(), nextPage func()){
|
|
|
|
title := getPageTitleCentered("Enable Moderate Messages Mode")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description1 := getBoldLabelCentered("Enable Moderate Messages Mode?")
|
|
|
|
description2 := getLabelCentered("This mode will download reported messages for you to moderate.")
|
|
description3 := getLabelCentered("These are likely to contain illegal and unruleful content.")
|
|
description4 := getLabelCentered("You must accept the legal risks of downloading this content.")
|
|
|
|
enableButton := getWidgetCentered(widget.NewButtonWithIcon("Enable", theme.ConfirmIcon(), func(){
|
|
err := mySettings.SetSetting("ModerateMessagesOnOffStatus", "On")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
nextPage()
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, enableButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setBuildMyModeratorProfilePage(window fyne.Window, previousPage func()){
|
|
|
|
currentPage := func(){setBuildMyModeratorProfilePage(window, previousPage)}
|
|
|
|
title := getPageTitleCentered("Build Moderator Profile")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description1 := getLabelCentered("Build your moderator profile.")
|
|
description2 := getLabelCentered("All information is optional.")
|
|
|
|
usernameButton := widget.NewButton("Username", func(){
|
|
setBuildProfilePage_Username(window, "Moderator", currentPage)
|
|
})
|
|
|
|
avatarButton := widget.NewButton("Avatar", func(){
|
|
setBuildProfilePage_Avatar(window, "Moderator", currentPage)
|
|
})
|
|
|
|
descriptionButton := widget.NewButton("Description", func(){
|
|
setBuildProfilePage_Description(window, "Moderator", currentPage)
|
|
})
|
|
|
|
profileLanguageButton := widget.NewButton(translate("Profile Language"), func(){
|
|
setBuildProfilePage_ProfileLanguage(window, "Moderator", currentPage)
|
|
})
|
|
|
|
languageButton := widget.NewButton("Language", func(){
|
|
//TODO
|
|
// The format of this attribute will be different than the one for mates
|
|
// It will not include a fluency field. It will simply contain a list of understood languages
|
|
showUnderConstructionDialog(window)
|
|
})
|
|
|
|
buttonsColumn := getContainerCentered(container.NewGridWithColumns(1, usernameButton, avatarButton, descriptionButton, profileLanguageButton, languageButton))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, widget.NewSeparator(), buttonsColumn)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setViewMyReviewsPage(window fyne.Window, reviewType string, previousPage func()){
|
|
|
|
if (reviewType != "Identity" && reviewType != "Profile" && reviewType != "Attribute" && reviewType != "Message"){
|
|
setErrorEncounteredPage(window, errors.New("setViewMyReviewsPage called with invalid reviewType: " + reviewType), previousPage)
|
|
return
|
|
}
|
|
|
|
setLoadingScreen(window, "View My Reviews", "Loading my reviews...")
|
|
|
|
currentPage := func(){setViewMyReviewsPage(window, reviewType, previousPage)}
|
|
|
|
title := getPageTitleCentered("My Reviews")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (myIdentityExists == false){
|
|
description1 := getBoldLabelCentered("Your moderator identity does not exist.")
|
|
description2 := getLabelCentered("Thus, you have no moderator reviews.")
|
|
description3 := getLabelCentered("Create your identity?")
|
|
|
|
createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){
|
|
setChooseNewIdentityHashPage(window, "Moderator", currentPage, currentPage)
|
|
}))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, createIdentityButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
//TODO: Add info about moderator's number of used reviews out of total that have been funded
|
|
|
|
reviewTypeLabel := getBoldLabelCentered("Review Type:")
|
|
|
|
allReviewTypesList := []string{"Identity", "Profile", "Attribute", "Message"}
|
|
|
|
handleSelectFunction := func(newReviewType string){
|
|
setViewMyReviewsPage(window, newReviewType, previousPage)
|
|
}
|
|
|
|
reviewTypeSelector := widget.NewSelect(allReviewTypesList, handleSelectFunction)
|
|
reviewTypeSelector.Selected = reviewType
|
|
|
|
reviewTypeSelectorCentered := getWidgetCentered(reviewTypeSelector)
|
|
|
|
description := getLabelCentered("Below are your " + reviewType + " reviews.")
|
|
|
|
getResultsContainer := func()(*fyne.Container, error){
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) { return nil, err }
|
|
|
|
myIdentityExists, myReviewsList, err := myReviews.GetMyNewestReviewsListSorted(reviewType, appNetworkType)
|
|
if (err != nil) { return nil, err }
|
|
if (myIdentityExists == false){
|
|
return nil, errors.New("My identity not found after being found already.")
|
|
}
|
|
|
|
totalNumberOfReviews := len(myReviewsList)
|
|
|
|
if (totalNumberOfReviews == 0){
|
|
|
|
reviewTypeLowercase := strings.ToLower(reviewType)
|
|
noReviewsExistText := getBoldLabelCentered("No " + reviewTypeLowercase + " reviews exist.")
|
|
|
|
return noReviewsExistText, nil
|
|
}
|
|
|
|
getFinalPageIndex := func()int{
|
|
if (totalNumberOfReviews <= 5){
|
|
return 0
|
|
}
|
|
|
|
maximumIndex := totalNumberOfReviews -5
|
|
|
|
return maximumIndex
|
|
}
|
|
|
|
finalPageIndex := getFinalPageIndex()
|
|
|
|
getViewIndex := func()(int, error){
|
|
|
|
if (totalNumberOfReviews <= 5){
|
|
return 0, nil
|
|
}
|
|
|
|
exists, currentViewIndex := appMemory.GetMemoryEntry("MyReviewsPageViewIndex_" + reviewType)
|
|
if (exists == false){
|
|
return 0, nil
|
|
}
|
|
|
|
currentViewIndexInt, err := helpers.ConvertStringToInt(currentViewIndex)
|
|
if (err != nil) { return 0, err }
|
|
|
|
maximumIndex := totalNumberOfReviews - 1
|
|
|
|
if (currentViewIndexInt < 0){
|
|
// Index is out of range, restart at 0
|
|
appMemory.SetMemoryEntry("MyReviewsPageViewIndex_" + reviewType, "0")
|
|
|
|
return 0, nil
|
|
}
|
|
if (currentViewIndexInt > maximumIndex){
|
|
finalPageIndexString := helpers.ConvertIntToString(finalPageIndex)
|
|
appMemory.SetMemoryEntry("MyReviewsPageViewIndex_" + reviewType, finalPageIndexString)
|
|
|
|
return finalPageIndex, nil
|
|
}
|
|
|
|
return currentViewIndexInt, nil
|
|
}
|
|
|
|
viewIndex, err := getViewIndex()
|
|
if (err != nil) { return nil, err }
|
|
|
|
getNavigateToBeginningButton := func()fyne.Widget{
|
|
|
|
if (totalNumberOfReviews <= 5 || viewIndex == 0){
|
|
|
|
emptyButton := widget.NewButton(" ", nil)
|
|
return emptyButton
|
|
}
|
|
|
|
goToBeginningButton := widget.NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func(){
|
|
appMemory.SetMemoryEntry("MyReviewsPageViewIndex_" + reviewType, "0")
|
|
currentPage()
|
|
})
|
|
|
|
return goToBeginningButton
|
|
}
|
|
|
|
getNavigateToEndButton := func()fyne.Widget{
|
|
|
|
emptyButton := widget.NewButton(" ", nil)
|
|
|
|
if (totalNumberOfReviews <= 5 || viewIndex >= finalPageIndex){
|
|
return emptyButton
|
|
}
|
|
|
|
goToEndButton := widget.NewButtonWithIcon("", theme.MediaSkipNextIcon(), func(){
|
|
|
|
finalPageIndexString := helpers.ConvertIntToString(finalPageIndex)
|
|
|
|
appMemory.SetMemoryEntry("MyReviewsPageViewIndex_" + reviewType, finalPageIndexString)
|
|
|
|
currentPage()
|
|
})
|
|
|
|
return goToEndButton
|
|
}
|
|
|
|
getNavigateLeftButton := func()fyne.Widget{
|
|
|
|
if (totalNumberOfReviews <= 5 || viewIndex == 0){
|
|
|
|
emptyButton := widget.NewButton(" ", nil)
|
|
return emptyButton
|
|
}
|
|
|
|
button := widget.NewButtonWithIcon("", theme.NavigateBackIcon(), func(){
|
|
|
|
newIndex := helpers.ConvertIntToString(viewIndex-5)
|
|
|
|
appMemory.SetMemoryEntry("MyReviewsPageViewIndex_" + reviewType, newIndex)
|
|
|
|
currentPage()
|
|
})
|
|
|
|
return button
|
|
}
|
|
|
|
getNavigateRightButton := func()fyne.Widget{
|
|
|
|
emptyButton := widget.NewButton(" ", nil)
|
|
|
|
if (totalNumberOfReviews <= 5 || viewIndex >= finalPageIndex){
|
|
|
|
return emptyButton
|
|
}
|
|
|
|
button := widget.NewButtonWithIcon("", theme.NavigateNextIcon(), func(){
|
|
|
|
newIndex := helpers.ConvertIntToString(viewIndex+5)
|
|
|
|
appMemory.SetMemoryEntry("MyReviewsPageViewIndex_" + reviewType, newIndex)
|
|
|
|
currentPage()
|
|
})
|
|
|
|
return button
|
|
}
|
|
|
|
getViewingReviewsLabelWithNavRow := func()*fyne.Container{
|
|
|
|
if (totalNumberOfReviews == 1){
|
|
viewingReviewText := getBoldLabelCentered("Viewing 1 Review")
|
|
|
|
return viewingReviewText
|
|
}
|
|
|
|
totalNumberOfReviewsString := helpers.ConvertIntToString(totalNumberOfReviews)
|
|
|
|
if (totalNumberOfReviews <= 5){
|
|
|
|
viewingReviewsText := getBoldLabelCentered("Viewing " + totalNumberOfReviewsString + " Reviews")
|
|
|
|
return viewingReviewsText
|
|
}
|
|
|
|
// We need to show navigation buttons
|
|
|
|
viewingReviewsText := getBoldLabel("Viewing " + totalNumberOfReviewsString + " Reviews")
|
|
|
|
navigateToBeginningButton := getNavigateToBeginningButton()
|
|
navigateToEndButton := getNavigateToEndButton()
|
|
|
|
navigateLeftButton := getNavigateLeftButton()
|
|
navigateRightButton := getNavigateRightButton()
|
|
|
|
navigationButtonsWithNumShowingRow := container.NewHBox(layout.NewSpacer(), navigateToBeginningButton, navigateLeftButton, viewingReviewsText, navigateRightButton, navigateToEndButton, layout.NewSpacer())
|
|
|
|
return navigationButtonsWithNumShowingRow
|
|
}
|
|
|
|
viewingReviewsLabelWithNavRow := getViewingReviewsLabelWithNavRow()
|
|
|
|
reviewedHashLabel := getItalicLabelCentered("Reviewed Hash")
|
|
creationTimeLabel := getItalicLabelCentered("Creation Time")
|
|
verdictLabel := getItalicLabelCentered("Verdict")
|
|
reasonLabel := getItalicLabelCentered("Reason")
|
|
emptyLabel := widget.NewLabel("")
|
|
|
|
reviewedHashColumn := container.NewVBox(reviewedHashLabel, widget.NewSeparator())
|
|
creationTimeColumn := container.NewVBox(creationTimeLabel, widget.NewSeparator())
|
|
verdictColumn := container.NewVBox(verdictLabel, widget.NewSeparator())
|
|
reasonColumn := container.NewVBox(reasonLabel, widget.NewSeparator())
|
|
viewReviewButtonsColumn := container.NewVBox(emptyLabel, widget.NewSeparator())
|
|
|
|
viewIndexOnwardsReviewsList := myReviewsList[viewIndex:]
|
|
|
|
for index, reviewBytes := range viewIndexOnwardsReviewsList{
|
|
|
|
ableToRead, reviewHash, _, reviewNetworkType, reviewerIdentityHash, reviewCreationTime, currentReviewType, reviewedHash, reviewVerdict, reviewMap, err := readReviews.ReadReviewAndHash(false, reviewBytes)
|
|
if (err != nil) { return nil, err }
|
|
if (ableToRead == false){
|
|
return nil, errors.New("GetMyNewestReviewsListSorted returning invalid review")
|
|
}
|
|
if (reviewNetworkType != appNetworkType){
|
|
return nil, errors.New("GetMyNewestReviewsListSorted returning review belonging to different networkType.")
|
|
}
|
|
if (reviewerIdentityHash != myIdentityHash) {
|
|
return nil, errors.New("GetMyNewestReviewsListSorted returning review for different identity hash.")
|
|
}
|
|
if (currentReviewType != reviewType){
|
|
return nil, errors.New("GetMyNewestReviewsListSorted returning review of a different reviewType")
|
|
}
|
|
|
|
reviewedHashString, err := helpers.EncodeReviewedHashBytesToString(reviewedHash)
|
|
if (err != nil) { return nil, err }
|
|
|
|
reviewedHashTrimmed, _, err := helpers.TrimAndFlattenString(reviewedHashString, 10)
|
|
if (err != nil) { return nil, err }
|
|
reviewedHashLabel := getBoldLabel(reviewedHashTrimmed)
|
|
|
|
creationTimeString, err := helpers.ConvertUnixTimeToTimeFromNowTranslated(reviewCreationTime, false)
|
|
if (err != nil ){ return nil, err }
|
|
|
|
creationTimeLabel := getBoldLabelCentered(creationTimeString)
|
|
|
|
verdictLabel := getBoldLabelCentered(reviewVerdict)
|
|
|
|
getReviewReasonCell := func()(*fyne.Container, error){
|
|
|
|
reasonString, exists := reviewMap["Reason"]
|
|
if (exists == false){
|
|
noneLabel := getBoldItalicLabelCentered(translate("None"))
|
|
|
|
return noneLabel, nil
|
|
}
|
|
|
|
reasonTrimmed, _, err := helpers.TrimAndFlattenString(reasonString, 20)
|
|
if (err != nil) { return nil, err }
|
|
|
|
reasonLabel := getBoldLabel(reasonTrimmed)
|
|
|
|
viewReasonButton := widget.NewButtonWithIcon("", theme.VisibilityIcon(), func(){
|
|
setViewTextPage(window, "Viewing Review Reason", reasonString, false, currentPage)
|
|
})
|
|
|
|
reasonCell := container.NewHBox(layout.NewSpacer(), reasonLabel, viewReasonButton, layout.NewSpacer())
|
|
|
|
return reasonCell, nil
|
|
}
|
|
|
|
reasonCell, err := getReviewReasonCell()
|
|
if (err != nil) { return nil, err }
|
|
|
|
viewReviewButton := widget.NewButtonWithIcon("View", theme.VisibilityIcon(), func(){
|
|
setViewReviewDetailsPage(window, reviewHash, currentPage)
|
|
})
|
|
|
|
reviewedHashColumn.Add(reviewedHashLabel)
|
|
creationTimeColumn.Add(creationTimeLabel)
|
|
verdictColumn.Add(verdictLabel)
|
|
reasonColumn.Add(reasonCell)
|
|
viewReviewButtonsColumn.Add(viewReviewButton)
|
|
|
|
reviewedHashColumn.Add(widget.NewSeparator())
|
|
creationTimeColumn.Add(widget.NewSeparator())
|
|
verdictColumn.Add(widget.NewSeparator())
|
|
reasonColumn.Add(widget.NewSeparator())
|
|
viewReviewButtonsColumn.Add(widget.NewSeparator())
|
|
|
|
if (index >= 4) {
|
|
break
|
|
}
|
|
}
|
|
|
|
reviewsGrid := container.NewHBox(layout.NewSpacer(), reviewedHashColumn, creationTimeColumn, verdictColumn, reasonColumn, viewReviewButtonsColumn, layout.NewSpacer())
|
|
|
|
resultsContainer := container.NewVBox(viewingReviewsLabelWithNavRow, widget.NewSeparator(), reviewsGrid)
|
|
|
|
return resultsContainer, nil
|
|
}
|
|
|
|
resultsContainer, err := getResultsContainer()
|
|
if (err != nil) {
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), reviewTypeLabel, reviewTypeSelectorCentered, widget.NewSeparator(), description, widget.NewSeparator(), resultsContainer)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setViewMyModeratorScorePage(window fyne.Window, previousPage func()){
|
|
|
|
currentPage := func(){setViewMyModeratorScorePage(window, previousPage)}
|
|
|
|
title := getPageTitleCentered("My Moderator Score")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description1 := getLabelCentered("Moderator scores are used to resolve conflicts when moderators disagree.")
|
|
description2 := getLabelCentered("You must have a minimum moderator score to be able to ban other moderators.")
|
|
description3 := getLabelCentered("If you have a higher moderator score than another, you can ban them.")
|
|
description4 := getLabelCentered("Increase your score by sending cryptocurrency.")
|
|
|
|
identityExists, myIdentityScore, _, _, _, err := myIdentityScore.GetMyIdentityScore()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
if (identityExists == false){
|
|
|
|
description5 := getBoldLabelCentered("Your Moderator identity does not exist.")
|
|
description6 := getLabelCentered("You must create it to view your Moderator Identity score.")
|
|
|
|
createIdentityButton := getWidgetCentered(widget.NewButtonWithIcon("Create Identity", theme.NavigateNextIcon(), func(){
|
|
setChooseNewIdentityHashPage(window, "Moderator", currentPage, currentPage)
|
|
}))
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, widget.NewSeparator(), description5, description6, createIdentityButton)
|
|
|
|
setPageContent(page, window)
|
|
return
|
|
}
|
|
|
|
myModeratorScoreString := helpers.ConvertFloat64ToStringRounded(myIdentityScore, 3)
|
|
moderatorScoreTitle := getItalicLabelCentered("My Moderator Identity Score:")
|
|
moderatorScoreLabel := getBoldLabelCentered(myModeratorScoreString)
|
|
|
|
refreshButton := getWidgetCentered(widget.NewButtonWithIcon("Refresh", theme.ViewRefreshIcon(), func(){
|
|
//TODO: Add page to download status and show progress
|
|
showUnderConstructionDialog(window)
|
|
}))
|
|
|
|
getMyModeratorRankText := func()(string, error){
|
|
|
|
myIdentityExists, myIdentityHash, err := myIdentity.GetMyIdentityHash("Moderator")
|
|
if (err != nil) { return "", err }
|
|
if (myIdentityExists == false){
|
|
return "", errors.New("My moderator identity not found after being found already.")
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) { return "", err }
|
|
|
|
rankingKnown, moderatorRank, totalNumberOfModerators, err := moderatorRanking.GetModeratorRanking(myIdentityHash, appNetworkType)
|
|
if (err != nil) { return "", err }
|
|
|
|
if (rankingKnown == false){
|
|
result := translate("Unknown")
|
|
return result, nil
|
|
}
|
|
|
|
moderatorRankString := helpers.ConvertIntToString(moderatorRank)
|
|
totalNumberOfModeratorsString := helpers.ConvertIntToString(totalNumberOfModerators)
|
|
|
|
moderatorRankText := moderatorRankString + "/" + totalNumberOfModeratorsString
|
|
|
|
return moderatorRankText, nil
|
|
}
|
|
|
|
myModeratorRankText, err := getMyModeratorRankText()
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
myModeratorRankTitle := widget.NewLabel("My Moderator Rank:")
|
|
myModeratorRankLabel := getBoldLabel(myModeratorRankText)
|
|
|
|
myModeratorRankRow := container.NewHBox(layout.NewSpacer(), myModeratorRankTitle, myModeratorRankLabel, layout.NewSpacer())
|
|
|
|
getSendFundsButtonWithIcon := func(cryptocurrencyName string)(*fyne.Container, error){
|
|
|
|
cryptocurrencyIcon, err := getFyneImageIcon(cryptocurrencyName)
|
|
if (err != nil){ return nil, err }
|
|
iconSize := getCustomFyneSize(0)
|
|
cryptocurrencyIcon.SetMinSize(iconSize)
|
|
|
|
sendFundsButton := widget.NewButton("Send " + cryptocurrencyName, func(){
|
|
nextPage := func(){setViewMyAddressToIncreaseIdentityScorePage(window, cryptocurrencyName, 50, currentPage)}
|
|
|
|
setCryptoIdentityScorePrivacyWarningPage(window, currentPage, nextPage)
|
|
})
|
|
|
|
sendFundsButtonWithIcon := container.NewGridWithColumns(1, cryptocurrencyIcon, sendFundsButton)
|
|
|
|
return sendFundsButtonWithIcon, nil
|
|
}
|
|
|
|
sendFundsButtonWithIcon_Ethereum, err := getSendFundsButtonWithIcon("Ethereum")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
sendFundsButtonWithIcon_Cardano, err := getSendFundsButtonWithIcon("Cardano")
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
sendFundsButtonsRow := getContainerCentered(container.NewGridWithColumns(2, sendFundsButtonWithIcon_Ethereum, sendFundsButtonWithIcon_Cardano))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, widget.NewSeparator(), moderatorScoreTitle, moderatorScoreLabel, refreshButton, widget.NewSeparator(), myModeratorRankRow, widget.NewSeparator(), sendFundsButtonsRow)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
|
|
func setCryptoIdentityScorePrivacyWarningPage(window fyne.Window, previousPage func(), nextPage func()){
|
|
|
|
title := getPageTitleCentered("Privacy Warning")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
description1 := getBoldLabelCentered("Be aware that your privacy is at risk when using cryptocurrencies.")
|
|
description2 := getLabelCentered("When you send money from your wallet, all users of Seekia will see your wallet and its balance.")
|
|
description3 := getLabelCentered("If you have a large amount of cryptocurrency, you should not send your funds from that wallet.")
|
|
description4 := getLabelCentered("For privacy, you should send funds directly from an exchange.")
|
|
description5 := getLabelCentered("You can also use a tool such as a zero knowledge accumulator for stronger privacy.")
|
|
|
|
description6 := getBoldLabelCentered("Do you understand the privacy risks?")
|
|
|
|
iUnderstandButton := getWidgetCentered(widget.NewButtonWithIcon("I Understand", theme.ConfirmIcon(), nextPage))
|
|
|
|
page := container.NewVBox(title, backButton, widget.NewSeparator(), description1, description2, description3, description4, description5, description6, iUnderstandButton)
|
|
|
|
setPageContent(page, window)
|
|
}
|
|
|
|
func setViewMyAddressToIncreaseIdentityScorePage(window fyne.Window, cryptocurrencyName string, reviewsToFund int64, previousPage func()){
|
|
|
|
if (cryptocurrencyName != "Ethereum" && cryptocurrencyName != "Cardano"){
|
|
setErrorEncounteredPage(window, errors.New("setViewMyAddressToIncreaseIdentityScorePage called with invalid cryptocurrencyName: " + cryptocurrencyName), previousPage)
|
|
return
|
|
}
|
|
|
|
currentPage := func(){setViewMyAddressToIncreaseIdentityScorePage(window, cryptocurrencyName, reviewsToFund, previousPage)}
|
|
|
|
title := getPageTitleCentered("Send Moderator Funds")
|
|
|
|
backButton := getBackButtonCentered(previousPage)
|
|
|
|
//identityExists, identityScoreAddress, err := myIdentityScore.GetMyIdentityScoreReceivingAddress(cryptocurrency)
|
|
//if (err != nil) {
|
|
// setErrorEncounteredPage(window, err, previousPage)
|
|
// return
|
|
//}
|
|
//if (identityExists == false) {
|
|
// This should not occur, this page should not be reached unless identity exists.
|
|
// setErrorEncounteredPage(window, errors.New("Identity not found."), previousPage)
|
|
// return
|
|
//}
|
|
|
|
warning1 := getBoldLabelCentered("Privacy Warning: This address is linked to your moderator identity.")
|
|
warning2 := getLabelCentered("All users of Seekia will be able to see all address transactions.")
|
|
warning3 := getBoldLabelCentered("All funds will be destroyed forever.")
|
|
|
|
cryptoAddressRow, err := getCryptocurrencyAddressLabelWithCopyAndQRButtons(window, cryptocurrencyName, "SeekiaIsNotCompleteYet", currentPage)
|
|
if (err != nil){
|
|
setErrorEncounteredPage(window, err, previousPage)
|
|
return
|
|
}
|
|
|
|
content := container.NewVBox(title, backButton, widget.NewSeparator(), warning1, warning2, warning3, widget.NewSeparator(), cryptoAddressRow)
|
|
|
|
setPageContent(content, window)
|
|
}
|
|
|
|
|