9d6181260a
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m49s
Backend CI / Backend (push) Failing after 7m10s
Desktop Client Build / Build Desktop Client (push) Successful in 23m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
Introduce an end-to-end media-supply feature: tenant-side resource sync service/worker backed by a Meijiequan supplier client, ops-side management APIs, and admin/ops web views for resources, orders, favorites and submission. Adds a shared digitocr helper, MediaSupply config blocks for tenant and ops, shared types, and migrations for supplier media resources, price overrides, customer visibility and order refunds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
40 lines
1.4 KiB
Go
40 lines
1.4 KiB
Go
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
// image/png is registered by the digitocr package; jpeg/gif are registered
|
|
// here so a future change of the captcha format still decodes.
|
|
_ "image/gif"
|
|
_ "image/jpeg"
|
|
|
|
"github.com/geo-platform/tenant-api/internal/shared/digitocr"
|
|
)
|
|
|
|
// meijiequanChallengeDigits is the fixed length of the meijiequan login captcha.
|
|
const meijiequanChallengeDigits = 4
|
|
|
|
var errMeijiequanChallengeEmpty = errors.New("meijiequan challenge image is empty")
|
|
|
|
// DigitOCRMeijiequanChallengeCodeResolver decodes the meijiequan numeric login
|
|
// captcha locally via the digitocr template matcher, enabling unattended login
|
|
// without an external OCR service.
|
|
type DigitOCRMeijiequanChallengeCodeResolver struct{}
|
|
|
|
// ResolveCode recognizes the digits in the captcha image. A decode failure is
|
|
// returned as a non-challenge error so the login flow retries with a fresh
|
|
// captcha rather than giving up immediately (as the manual resolver does).
|
|
func (DigitOCRMeijiequanChallengeCodeResolver) ResolveCode(_ context.Context, challenge MeijiequanChallenge) (string, error) {
|
|
if len(challenge.Image) == 0 {
|
|
return "", errMeijiequanChallengeEmpty
|
|
}
|
|
code, err := digitocr.RecognizeReader(bytes.NewReader(challenge.Image), digitocr.Options{Digits: meijiequanChallengeDigits})
|
|
if err != nil {
|
|
return "", fmt.Errorf("digitocr resolve meijiequan challenge: %w", err)
|
|
}
|
|
return code, nil
|
|
}
|