feat(worked): fold portable callsigns into the worked-before history
Typing RK3DWA found nothing while RK3DWA/3 found 21 QSOs, so a station's history was only visible if you happened to type the exact form it had been logged under — and an operator who worked it as /0, /P or /MM saw none of it. The other RDA tools and Log4OM fold these together; this does too. The predicate strips the suffix from what was typed and matches "call = base OR call LIKE base/%", so it works from either end: the base call finds the portable QSOs and a portable call finds the plain ones. Deliberately not a bare prefix LIKE 'RK3DWA%', which would also match RK3DWAB — a different station. The '/' is what makes it the same operator. Settings -> General to turn it off. Default ON, hence the inverted storage: an existing install has no key, and reading that as OFF would leave everyone with the behaviour we were asked to change. Contest dupe checking is untouched — it runs through ContestDupe, a separate binding, and stays an exact match as a contest requires.
This commit is contained in:
@@ -293,6 +293,12 @@ const (
|
||||
|
||||
keyScpEnabled = "scp.enabled" // Super Check Partial / N+1 suggestions on
|
||||
|
||||
// Worked-before: fold an operator's portable forms (X, X/3, X/P) together.
|
||||
// Stored inverted — "0" means OFF — so the feature is ON for an existing
|
||||
// install that has never seen the key, which is the behaviour operators asked
|
||||
// for. See GetWorkedCallVariants.
|
||||
keyWorkedCallVariants = "worked.call_variants"
|
||||
|
||||
keyBackupEnabled = "backup.enabled"
|
||||
keyBackupFolder = "backup.folder"
|
||||
keyBackupRotation = "backup.rotation"
|
||||
@@ -6091,6 +6097,31 @@ func (a *App) bulkSetFrequency(ids []int64, value string) (int64, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// GetWorkedCallVariants reports whether "worked before" folds an operator's
|
||||
// portable forms together (RK3DWA ↔ RK3DWA/3 ↔ RK3DWA/P).
|
||||
//
|
||||
// Defaults to ON, hence the inverted storage: an install that predates the
|
||||
// setting has no key at all, and reading that as OFF would leave every existing
|
||||
// operator with the old narrow behaviour they asked us to change.
|
||||
func (a *App) GetWorkedCallVariants() (bool, error) {
|
||||
if a.settings == nil {
|
||||
return true, fmt.Errorf("db not initialized")
|
||||
}
|
||||
v, err := a.settings.Get(a.ctx, keyWorkedCallVariants)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return v != "0", nil
|
||||
}
|
||||
|
||||
// SetWorkedCallVariants persists the toggle.
|
||||
func (a *App) SetWorkedCallVariants(on bool) error {
|
||||
if a.settings == nil {
|
||||
return fmt.Errorf("db not initialized")
|
||||
}
|
||||
return a.settings.Set(a.ctx, keyWorkedCallVariants, boolStr(on))
|
||||
}
|
||||
|
||||
// WorkedBefore returns prior contacts with the given callsign at both
|
||||
// call and DXCC granularity. Pass dxccHint=0 when unknown — the function
|
||||
// will infer it from past QSOs with the same call when possible.
|
||||
@@ -6107,7 +6138,8 @@ func (a *App) WorkedBefore(callsign string, dxccHint int) (qso.WorkedBefore, err
|
||||
dxccHint = dxcc.EntityDXCC(m.Entity.Name)
|
||||
}
|
||||
}
|
||||
wb, err := a.qso.WorkedBefore(a.ctx, callsign, dxccHint)
|
||||
variants, _ := a.GetWorkedCallVariants()
|
||||
wb, err := a.qso.WorkedBefore(a.ctx, callsign, dxccHint, variants)
|
||||
// Attach the ClubLog Most Wanted rank for this entity (opt-in) so the entry
|
||||
// matrix can show it next to the country name.
|
||||
if err == nil && wb.DXCC > 0 && a.clublogMW != nil && a.clublogMostWantedEnabled() {
|
||||
|
||||
Reference in New Issue
Block a user