mirror of
https://codeberg.org/pluja/kycnot.me
synced 2025-01-24 05:11:01 -05:00
use integer score, add announcements
This commit is contained in:
parent
d6e6592171
commit
f0b85c80e3
@ -1,201 +1,6 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
type Attribute struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Rating int `json:"rating"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttributeMap struct {
|
|
||||||
Attributes map[string]AttributeNew `json:"attributes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AttributeAccountNeeded = "account-needed"
|
AttributeOpenSource = "l0p2hlenm8cm7jp"
|
||||||
AttributeAPIAvailable = "api"
|
AttributeP2P = "5bcqjb2xzbel9g9"
|
||||||
AttributeBlockFundsIfFlagged = "blocks-if-flagged"
|
|
||||||
AttributeCustodialWallet = "custodial-wallet"
|
|
||||||
AttributeJavaScriptNeeded = "needs-js"
|
|
||||||
AttributeKYCForSomeFeatures = "kyc-features"
|
|
||||||
AttributeKYCIfObligedByLaw = "kyc-law"
|
|
||||||
AttributeMobileAppAvailable = "mobile-app"
|
|
||||||
AttributeNoCustomerSupport = "no-customer-support"
|
|
||||||
AttributeNoJavaScriptNeeded = "no-js"
|
|
||||||
AttributeNonCustodialWallet = "non-custodial"
|
|
||||||
AttributeNoPersonalInfoNeeded = "no-personal-info"
|
|
||||||
AttributeNoRegistrationNeeded = "no-registration"
|
|
||||||
AttributeOpenSource = "open-source"
|
|
||||||
AttributeP2P = "p2p"
|
|
||||||
AttributePartnersMayEnforceKYC = "partners-kyc"
|
|
||||||
AttributePrivateSourceCode = "private-code"
|
|
||||||
AttributeRefundNoKYC = "refunds-no-kyc"
|
|
||||||
AttributeRefundRequiresKYC = "refunds-kyc"
|
|
||||||
AttributeRiskPreventionSystem = "risk-prevention-system"
|
|
||||||
AttributeSellerWalletCustodial = "seller-wallet-custodial"
|
|
||||||
AttributeStrictNoKYCPolicy = "strict-no-kyc"
|
|
||||||
AttributeStrictNoLogPolicy = "strict-no-log"
|
|
||||||
AttributeTelegramBotAvailable = "telegram-bot"
|
|
||||||
AttributeToSNotScrapable = "tos-not-scrapable"
|
|
||||||
AttributeUnclearRefundPolicy = "unclear-refunds"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ServiceAttributes = AttributeMap{
|
|
||||||
Attributes: map[string]AttributeNew{
|
|
||||||
AttributeRiskPreventionSystem: {
|
|
||||||
Title: "Automated Risk-Prevention System",
|
|
||||||
Description: "This service scans transactions automatically in search for suspicious transactions. If the trade is flagged suspicious by the system, the user might be required a KYC procedure in order to complete the trade or get a refund.",
|
|
||||||
Rating: "bad",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeKYCForSomeFeatures: {
|
|
||||||
Title: "KYC is mandatory to use some features",
|
|
||||||
Description: "Some features offered by this service need KYC for the user to use them.",
|
|
||||||
Rating: "bad",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeKYCIfObligedByLaw: {
|
|
||||||
Title: "May require KYC/SOF by policy/law",
|
|
||||||
Description: "If obliged to do so by the law or in accordance with the service's internal policy, it may at any time introduce or amend mandatory identification / verification procedures and require the user to complete identification and/or verification and may also require to submit identification documents (KYC) or provide Source of Funds (SOF) information.",
|
|
||||||
Rating: "bad",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeCustodialWallet: {
|
|
||||||
Title: "Custodial wallet",
|
|
||||||
Description: "A custodial wallet is a type of crypto wallet where a third party holds and manages the private keys to your wallet and your assets in custody. The custodian is responsible for safeguarding your funds, and you entrust them with your private keys. Custodial wallets are usually provided by centralized crypto exchanges like Coinbase or Binance. Using a custodial wallet requires a great deal of trust in the institution.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeAccountNeeded: {
|
|
||||||
Title: "Account needed to use the service",
|
|
||||||
Description: "Users require creating and maintaining an account with the service in order to access and use its features. ",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributePrivateSourceCode: {
|
|
||||||
Title: "Source code is private",
|
|
||||||
Description: "The source code of the service is not publicly available. This means that the service cannot be audited by the community. This is not necessarily bad, but it is something to keep in mind.",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeNoCustomerSupport: {
|
|
||||||
Title: "Poor or no customer support",
|
|
||||||
Description: "The service does not offer customer support, or the quality of service provided by the support team is inadequate or unsatisfactory.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeBlockFundsIfFlagged: {
|
|
||||||
Title: "May block 'suspicious' transactions",
|
|
||||||
Description: "User funds may pass through an analysis system that may flag the source of the funds as suspicious. If this happens, the user may be refunded or may be required a KYC procedure.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeUnclearRefundPolicy: {
|
|
||||||
Title: "Unclear refund policy",
|
|
||||||
Description: "This service has an unclear or nonexistent statement about how they manage user refunds.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeSellerWalletCustodial: {
|
|
||||||
Title: "The seller wallet is custodial",
|
|
||||||
Description: "The seller wallet is custodial, which means that the seller does not have control over the funds. This is a common practice in P2P exchanges, where the service needs to have control over the funds in order to be able to refund the buyer if the trade enters a dispute.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeRefundRequiresKYC: {
|
|
||||||
Title: "Refunds may require KYC",
|
|
||||||
Description: "In certain cases, the refund process of these services may require the completion of a Know Your Customer (KYC) procedure or the disclosure of personal information. Some services, such as aggregators, usually don't control the KYC procedures of their partners so they fall in this category.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeToSNotScrapable: {
|
|
||||||
Title: "ToS page is not possible to scrape",
|
|
||||||
Description: "The ToS page has some mechanism that makes it impossible for KYCNOT.me to scrape its content. These methods include, for example, using a canvas and rendering the text on it.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributePartnersMayEnforceKYC: {
|
|
||||||
Title: "Partners may enforce KYC policies",
|
|
||||||
Description: "The service has partners that may enforce or implement KYC policies. This is common in aggregators, where the service does not control the KYC policies of their partners.",
|
|
||||||
Rating: "warn",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeNonCustodialWallet: {
|
|
||||||
Title: "Non-custodial wallet",
|
|
||||||
Description: "A non-custodial wallet is a type of crypto wallet where the user holds and manages the private keys to the wallet and the assets in custody. The user is responsible for safeguarding their funds, and they are the only ones with access to their private keys. Using a non-custodial wallet requires no trust in any institution.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeOpenSource: {
|
|
||||||
Title: "Open source code",
|
|
||||||
Description: "The source code of the service is publicly available. This means that the service can be audited by the community. This is not necessarily good, but it is something to keep in mind.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeP2P: {
|
|
||||||
Title: "Peer to peer",
|
|
||||||
Description: "Peer-to-peer marketplaces are online platforms where people can trade goods, cryptocurrencies and services directly from each other, without the need for intermediaries like traditional retailers or service providers. In this case, the service is based on such type of market.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeNoRegistrationNeeded: {
|
|
||||||
Title: "No registration needed",
|
|
||||||
Description: "Users can access and use the service without creating an account. This enables a faster and more convenient user experience while also offering enhanced privacy and anonymity.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeNoPersonalInfoNeeded: {
|
|
||||||
Title: "No personal information needed",
|
|
||||||
Description: "Users can create an account with these services without having to provide any personal information such as their name, address, or identification documents. This offers a high degree of privacy and anonymity to users who prefer to keep their personal information private.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeStrictNoKYCPolicy: {
|
|
||||||
Title: "Strict no-KYC policy",
|
|
||||||
Description: "The service has a strict no-KYC policy, which means that it does not require users to complete any KYC procedure in order to access and use its features.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeRefundNoKYC: {
|
|
||||||
Title: "Refunds do not require KYC",
|
|
||||||
Description: "The refund process of these services does not require the completion of a Know Your Customer (KYC) procedure or the disclosure of personal information.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeStrictNoLogPolicy: {
|
|
||||||
Title: "Strict no-log policy",
|
|
||||||
Description: "The service has a strict no-log policy, which means that it does not collect or store any information about its users.",
|
|
||||||
Rating: "good",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeMobileAppAvailable: {
|
|
||||||
Title: "Mobile app available",
|
|
||||||
Description: "The service has a mobile app available for download.",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeNoJavaScriptNeeded: {
|
|
||||||
Title: "No JavaScript needed",
|
|
||||||
Description: "The service does not require the user to enable JavaScript in order to access and use its features.",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeTelegramBotAvailable: {
|
|
||||||
Title: "Telegram bot available",
|
|
||||||
Description: "The service has a Telegram bot available.",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeAPIAvailable: {
|
|
||||||
Title: "API available",
|
|
||||||
Description: "The service has an API available.",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeJavaScriptNeeded: {
|
|
||||||
Title: "JavaScript needed",
|
|
||||||
Description: "The service requires the user to enable JavaScript in order to access and use its features.",
|
|
||||||
Rating: "info",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
@ -1,36 +1,36 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Category string `json:"category"`
|
Category string `json:"category"`
|
||||||
CollectionID string `json:"collectionId"`
|
CollectionID string `json:"collectionId"`
|
||||||
CollectionName string `json:"collectionName"`
|
CollectionName string `json:"collectionName"`
|
||||||
Comments []string `json:"comments"`
|
Comments []string `json:"comments"`
|
||||||
Created string `json:"created"`
|
Created string `json:"created"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Expand map[string][]AttributeNew `json:"expand"`
|
Expand map[string][]Attribute `json:"expand"`
|
||||||
Attributes []string `json:"attributes"`
|
Attributes []string `json:"attributes"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
KycLevel int `json:"kyc_level"`
|
KycLevel int `json:"kyc_level"`
|
||||||
Listed bool `json:"listed"`
|
Listed bool `json:"listed"`
|
||||||
LogoURL string `json:"logo_url"`
|
LogoURL string `json:"logo_url"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
OnionUrls []string `json:"onion_urls"`
|
OnionUrls []string `json:"onion_urls"`
|
||||||
Pending bool `json:"pending"`
|
Pending bool `json:"pending"`
|
||||||
Score string `json:"score"`
|
Score int `json:"score"`
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
TosReviews []TosReview `json:"tos_reviews"`
|
TosReviews []TosReview `json:"tos_reviews"`
|
||||||
LastTosReview string `json:"last_tos_review"`
|
LastTosReview string `json:"last_tos_review"`
|
||||||
TosUrls []string `json:"tos_urls"`
|
TosUrls []string `json:"tos_urls"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Referral string `json:"referral"`
|
Referral string `json:"referral"`
|
||||||
Updated string `json:"updated"`
|
Updated string `json:"updated"`
|
||||||
Urls []string `json:"urls"`
|
Urls []string `json:"urls"`
|
||||||
Verified bool `json:"verified"`
|
Verified bool `json:"verified"`
|
||||||
Xmr bool `json:"xmr"`
|
Xmr bool `json:"xmr"`
|
||||||
Btc bool `json:"btc"`
|
Btc bool `json:"btc"`
|
||||||
Fiat bool `json:"fiat"`
|
Fiat bool `json:"fiat"`
|
||||||
Cash bool `json:"cash"`
|
Cash bool `json:"cash"`
|
||||||
Lightning bool `json:"lightning"`
|
Lightning bool `json:"lightning"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TosReview struct {
|
type TosReview struct {
|
||||||
@ -41,7 +41,7 @@ type TosReview struct {
|
|||||||
Reference string `json:"reference"`
|
Reference string `json:"reference"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AttributeNew struct {
|
type Attribute struct {
|
||||||
CollectionID string `json:"collectionId"`
|
CollectionID string `json:"collectionId"`
|
||||||
CollectionName string `json:"collectionName"`
|
CollectionName string `json:"collectionName"`
|
||||||
Created string `json:"created"`
|
Created string `json:"created"`
|
||||||
@ -51,3 +51,11 @@ type AttributeNew struct {
|
|||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Updated string `json:"updated"`
|
Updated string `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Announcement struct {
|
||||||
|
Title string
|
||||||
|
Body string
|
||||||
|
Link string
|
||||||
|
Warning bool
|
||||||
|
Active bool
|
||||||
|
}
|
||||||
|
@ -111,8 +111,8 @@ func (p *PbClient) UpdateService(id string, service Service) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PbClient) GetAttribute(id string) (*AttributeNew, error) {
|
func (p *PbClient) GetAttribute(id string) (*Attribute, error) {
|
||||||
collection := pocketbase.CollectionSet[AttributeNew](p.Client, "attributes")
|
collection := pocketbase.CollectionSet[Attribute](p.Client, "attributes")
|
||||||
|
|
||||||
response, err := collection.One(id)
|
response, err := collection.One(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -122,8 +122,8 @@ func (p *PbClient) GetAttribute(id string) (*AttributeNew, error) {
|
|||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PbClient) GetAttributes(filters, sort string) ([]AttributeNew, error) {
|
func (p *PbClient) GetAttributes(filters, sort string) ([]Attribute, error) {
|
||||||
collection := pocketbase.CollectionSet[AttributeNew](p.Client, "attributes")
|
collection := pocketbase.CollectionSet[Attribute](p.Client, "attributes")
|
||||||
params := pocketbase.ParamsList{
|
params := pocketbase.ParamsList{
|
||||||
Page: 1,
|
Page: 1,
|
||||||
Size: 250,
|
Size: 250,
|
||||||
@ -145,8 +145,8 @@ func (p *PbClient) GetAttributes(filters, sort string) ([]AttributeNew, error) {
|
|||||||
return response.Items, nil
|
return response.Items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PbClient) CreateAttribute(attribute AttributeNew) error {
|
func (p *PbClient) CreateAttribute(attribute Attribute) error {
|
||||||
collection := pocketbase.CollectionSet[AttributeNew](p.Client, "attributes")
|
collection := pocketbase.CollectionSet[Attribute](p.Client, "attributes")
|
||||||
|
|
||||||
_, err := collection.Create(attribute)
|
_, err := collection.Create(attribute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,3 +155,19 @@ func (p *PbClient) CreateAttribute(attribute AttributeNew) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PbClient) GetAnnouncement() *Announcement {
|
||||||
|
collection := pocketbase.CollectionSet[Announcement](p.Client, "announcements")
|
||||||
|
params := pocketbase.ParamsList{
|
||||||
|
Page: 1,
|
||||||
|
Size: 1,
|
||||||
|
Filters: "active=true",
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := collection.List(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.Items[0]
|
||||||
|
}
|
||||||
|
@ -1,33 +1,47 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"pluja.dev/kycnot.me/database"
|
"pluja.dev/kycnot.me/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ComputeScore(s *database.Service) string {
|
func ComputeScore(s *database.Service) int {
|
||||||
const (
|
const (
|
||||||
baseScore = 100
|
baseScore = 10
|
||||||
goodRating = 0
|
maxScore = 10
|
||||||
warningRating = 10
|
minScore = 0
|
||||||
badRating = 20
|
bonusLow = 15
|
||||||
maxScore = 100
|
bonusMedium = 20
|
||||||
minScore = 0
|
bonusHigh = 25
|
||||||
bonusLow = 15
|
|
||||||
bonusMedium = 20
|
|
||||||
bonusHigh = 25
|
|
||||||
)
|
)
|
||||||
|
|
||||||
grade := float64(baseScore)
|
grade := float64(baseScore)
|
||||||
|
|
||||||
// Attribute Ratings
|
// KYC Level Adjustment
|
||||||
|
switch s.KycLevel {
|
||||||
|
case 0:
|
||||||
|
grade = 8
|
||||||
|
case 1:
|
||||||
|
grade = 7
|
||||||
|
case 2:
|
||||||
|
grade = 6
|
||||||
|
case 3:
|
||||||
|
grade = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes
|
||||||
for _, attr := range s.Expand["attributes"] {
|
for _, attr := range s.Expand["attributes"] {
|
||||||
switch attr.Rating {
|
switch attr.Rating {
|
||||||
|
case "good":
|
||||||
|
grade += 0.1
|
||||||
case "warn":
|
case "warn":
|
||||||
grade -= bonusLow
|
grade -= 0.25
|
||||||
case "bad":
|
case "bad":
|
||||||
grade -= bonusHigh
|
grade -= 0.5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,65 +50,151 @@ func ComputeScore(s *database.Service) string {
|
|||||||
s.TosReviews = []database.TosReview{}
|
s.TosReviews = []database.TosReview{}
|
||||||
}
|
}
|
||||||
|
|
||||||
trPenalty := 0
|
trPenalty := 0.0
|
||||||
for _, tr := range s.TosReviews {
|
for _, tr := range s.TosReviews {
|
||||||
if tr.Warning {
|
if tr.Warning {
|
||||||
trPenalty -= 2
|
trPenalty -= 0.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if trPenalty > bonusHigh {
|
if trPenalty > 3 {
|
||||||
trPenalty = bonusHigh
|
trPenalty = 3
|
||||||
}
|
}
|
||||||
grade += float64(trPenalty)
|
grade += float64(trPenalty)
|
||||||
|
|
||||||
// Cash/Monero Bonus
|
// Cash/Monero Bonus
|
||||||
if s.Cash || s.Xmr {
|
if s.Cash || s.Xmr || s.Btc {
|
||||||
grade += bonusLow
|
grade += 0.5
|
||||||
}
|
if s.Xmr {
|
||||||
|
grade += 0.25
|
||||||
// KYC Level Adjustment
|
}
|
||||||
switch s.KycLevel {
|
|
||||||
case 1:
|
|
||||||
grade -= 5
|
|
||||||
case 2:
|
|
||||||
grade -= 10
|
|
||||||
case 3:
|
|
||||||
grade -= 15
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Manage bonuses
|
// TODO: Manage bonuses
|
||||||
// P2P/OpenSource Bonus
|
// P2P/OpenSource Bonus
|
||||||
/*if strings.Contains(s.Attributes, database.AttributeP2P) || strings.Contains(s.Attributes, database.AttributeOpenSource) {
|
isP2P := false
|
||||||
grade += bonusLow
|
isOpenSource := false
|
||||||
}*/
|
for _, attr := range s.Attributes {
|
||||||
|
if attr == database.AttributeP2P {
|
||||||
|
isP2P = true
|
||||||
|
}
|
||||||
|
if attr == database.AttributeOpenSource {
|
||||||
|
isOpenSource = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tor URL Bonus
|
// Tor URL Bonus
|
||||||
if len(s.OnionUrls) == 0 || s.OnionUrls[0] == "" {
|
if len(s.OnionUrls) > 0 && s.OnionUrls[0] != "" {
|
||||||
grade -= bonusLow
|
grade += 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Verified {
|
||||||
|
if grade < 7.5 {
|
||||||
|
grade += 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isP2P && grade > 9.5 {
|
||||||
|
grade = 9
|
||||||
|
}
|
||||||
|
|
||||||
|
if isP2P || isOpenSource && grade < 8 {
|
||||||
|
grade += 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize the grade to be within 0-10 bounds
|
// Normalize the grade to be within 0-10 bounds
|
||||||
grade = math.Min(maxScore, math.Max(minScore, grade))
|
grade = math.Min(maxScore, math.Max(minScore, grade))
|
||||||
|
|
||||||
switch {
|
log.Debug().Msgf("Computed score for %s: %f", s.Name, math.RoundToEven(grade))
|
||||||
case grade >= 95:
|
|
||||||
return "A"
|
return int(math.RoundToEven(grade))
|
||||||
case grade >= 85:
|
}
|
||||||
return "A"
|
|
||||||
case grade >= 75:
|
func ScoreSummary(s *database.Service) string {
|
||||||
return "B"
|
summary := fmt.Sprintf("SCORE BREAKDOWN - %s:\n", s.Name)
|
||||||
case grade >= 65:
|
const leftPad = 10 // Adjust this based on your longest line
|
||||||
return "B"
|
|
||||||
case grade >= 55:
|
// KYC Level Adjustment
|
||||||
return "C"
|
switch s.KycLevel {
|
||||||
case grade >= 45:
|
case 0:
|
||||||
return "C"
|
summary += fmt.Sprintf("\n%-*s--> base score for KYC Level 0", leftPad, "|| 8")
|
||||||
case grade >= 35:
|
case 1:
|
||||||
return "D"
|
summary += fmt.Sprintf("\n%-*s--> base score for KYC Level 1", leftPad, "|| 7")
|
||||||
default:
|
case 2:
|
||||||
return "F"
|
summary += fmt.Sprintf("\n%-*s--> base score for KYC Level 2", leftPad, "|| 6")
|
||||||
|
case 3:
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> base score for KYC Level 3", leftPad, "|| 5")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
for _, attr := range s.Expand["attributes"] {
|
||||||
|
switch attr.Rating {
|
||||||
|
case "good":
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> good attribute.", leftPad, "|| +0.1")
|
||||||
|
case "warn":
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> warn attribute.", leftPad, "|| -0.25")
|
||||||
|
case "bad":
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> bad attribute.", leftPad, "|| -0.5")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tos Highlights Penalty (Corrected to reflect actual penalty logic)
|
||||||
|
trPenalty := 0.0
|
||||||
|
wrns := 0
|
||||||
|
for _, tr := range s.TosReviews {
|
||||||
|
if tr.Warning {
|
||||||
|
trPenalty -= 0.1
|
||||||
|
wrns++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if trPenalty < -3 {
|
||||||
|
trPenalty = -3
|
||||||
|
}
|
||||||
|
|
||||||
|
if trPenalty != 0 {
|
||||||
|
summary += fmt.Sprintf("\n|| %-*f--> %d terms of service warnings.", leftPad, trPenalty, wrns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cash/Monero Bonus
|
||||||
|
if s.Cash || s.Xmr || s.Btc {
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> accepting Cash/BTC.", leftPad, "|| +0.5")
|
||||||
|
if s.Xmr {
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> monero bonus.", leftPad, "|| +0.25")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tor URL Bonus
|
||||||
|
if len(s.OnionUrls) > 0 && s.OnionUrls[0] != "" {
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> having a Tor URL.", leftPad, "|| +0.5")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verified Bonus
|
||||||
|
if s.Verified {
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> being verified (applies only if score was below 7.5 at this point).", leftPad, "|| +0.5")
|
||||||
|
}
|
||||||
|
|
||||||
|
// P2P/OpenSource Bonus
|
||||||
|
// Note: Since the original ComputeScore doesn't show the exact bonus amount for P2P/OpenSource,
|
||||||
|
// it's assumed to follow the similar logic as in ComputeScore for simplicity.
|
||||||
|
isP2P := false
|
||||||
|
isOpenSource := false
|
||||||
|
for _, attr := range s.Attributes {
|
||||||
|
if attr == database.AttributeP2P {
|
||||||
|
isP2P = true
|
||||||
|
}
|
||||||
|
if attr == database.AttributeOpenSource {
|
||||||
|
isOpenSource = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isP2P || isOpenSource {
|
||||||
|
summary += fmt.Sprintf("\n%-*s--> P2P/OpenSource bonus (applies if score was below 8).", leftPad, "|| +0.5")
|
||||||
|
}
|
||||||
|
|
||||||
|
summary += "\n||"
|
||||||
|
summary += fmt.Sprintf("\n|| Total: %v", ComputeScore(s)) // Call ComputeScore to get the actual score
|
||||||
|
summary += "\n(final score is rounded to even number)"
|
||||||
|
|
||||||
|
return summary
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func UpdateScore(s *ent.Service) error {
|
/*func UpdateScore(s *ent.Service) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user