feat: support basic user system
This commit is contained in:
44
internal/service/auth.go
Normal file
44
internal/service/auth.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/jwtauth/v5"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func (s *Service) VerifyUser(ctx context.Context, input VerifyUserInput) (VerifyUserResult, error) {
|
||||
u, err := s.queries.GetUserByUsername(ctx, input.Username)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return VerifyUserResult{}, notFound("user does not exist or password is wrong")
|
||||
}
|
||||
return VerifyUserResult{}, internalError("auth error", nil)
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(input.Password)); err != nil {
|
||||
return VerifyUserResult{}, notFound("user does not exist or password is wrong")
|
||||
}
|
||||
|
||||
// jwt
|
||||
claims := make(map[string]any)
|
||||
claims["userid"] = u.ID.String()
|
||||
claims["username"] = u.Username
|
||||
claims["role"] = u.Role
|
||||
claims["account_status"] = u.AccountStatus
|
||||
jwtauth.SetExpiryIn(claims, 24*time.Hour)
|
||||
jwtauth.SetIssuedNow(claims)
|
||||
|
||||
_, token, _ := s.config.JWTAuth.Encode(claims)
|
||||
|
||||
return VerifyUserResult{
|
||||
Token: token,
|
||||
UserId: u.ID.String(),
|
||||
UserName: u.Username,
|
||||
DisplayName: u.DisplayName,
|
||||
Role: u.Role,
|
||||
}, nil
|
||||
}
|
||||
13
internal/service/auth_test.go
Normal file
13
internal/service/auth_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func TestGenerateHashedPassword(t *testing.T) {
|
||||
e, _ := bcrypt.GenerateFromPassword([]byte("1145141919810"), bcrypt.DefaultCost)
|
||||
log.Println(string(e))
|
||||
}
|
||||
1
internal/service/jwt_utils.go
Normal file
1
internal/service/jwt_utils.go
Normal file
@@ -0,0 +1 @@
|
||||
package service
|
||||
@@ -2,13 +2,16 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.starryskymeow.cn/B309/datamarket/internal/config"
|
||||
"gitea.starryskymeow.cn/B309/datamarket/internal/repository"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
@@ -37,12 +40,14 @@ var (
|
||||
|
||||
type Service struct {
|
||||
queries *repository.Queries
|
||||
config *config.Config
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func New(queries *repository.Queries) *Service {
|
||||
func New(queries *repository.Queries, cfg *config.Config) *Service {
|
||||
return &Service{
|
||||
queries: queries,
|
||||
config: cfg,
|
||||
now: time.Now,
|
||||
}
|
||||
}
|
||||
@@ -884,29 +889,33 @@ func timestamptzValue(value time.Time) pgtype.Timestamptz {
|
||||
|
||||
func toAsset(asset repository.DataAsset) Asset {
|
||||
return Asset{
|
||||
ID: asset.ID.String(),
|
||||
AssetName: asset.AssetName,
|
||||
AssetType: asset.AssetType,
|
||||
Domain: asset.Domain,
|
||||
ApplicationScene: toTextPointer(asset.ApplicationScene),
|
||||
DataDescription: asset.DataDescription,
|
||||
DataScale: asset.DataScale,
|
||||
CollectionMethod: asset.CollectionMethod,
|
||||
LabelingStatus: toTextPointer(asset.LabelingStatus),
|
||||
UpdateFrequency: toTextPointer(asset.UpdateFrequency),
|
||||
PrivacyLevel: asset.PrivacyLevel,
|
||||
PermissionMode: asset.PermissionMode,
|
||||
SupportsValidation: asset.SupportsValidation,
|
||||
SellerExpectedPriceMin: toNumericPointer(asset.SellerExpectedPriceMin),
|
||||
SellerExpectedPriceMax: toNumericPointer(asset.SellerExpectedPriceMax),
|
||||
QualityLevel: toTextPointer(asset.QualityLevel),
|
||||
ScarcityLevel: toTextPointer(asset.ScarcityLevel),
|
||||
BaseValueScore: toNumericPointer(asset.BaseValueScore),
|
||||
BasePriceMin: toNumericPointer(asset.BasePriceMin),
|
||||
BasePriceMax: toNumericPointer(asset.BasePriceMax),
|
||||
AssetStatus: asset.AssetStatus,
|
||||
CreatedAt: toTimePointer(asset.CreatedAt),
|
||||
UpdatedAt: toTimePointer(asset.UpdatedAt),
|
||||
ID: asset.ID.String(),
|
||||
AssetName: asset.AssetName,
|
||||
AssetType: asset.AssetType,
|
||||
Domain: asset.Domain,
|
||||
ApplicationScene: toTextPointer(asset.ApplicationScene),
|
||||
DataDescription: asset.DataDescription,
|
||||
DataScale: asset.DataScale,
|
||||
CollectionMethod: asset.CollectionMethod,
|
||||
LabelingStatus: toTextPointer(asset.LabelingStatus),
|
||||
UpdateFrequency: toTextPointer(asset.UpdateFrequency),
|
||||
PrivacyLevel: asset.PrivacyLevel,
|
||||
PermissionMode: asset.PermissionMode,
|
||||
SupportsValidation: asset.SupportsValidation,
|
||||
SellerExpectedPriceMin: toNumericPointer(asset.SellerExpectedPriceMin),
|
||||
SellerExpectedPriceMax: toNumericPointer(asset.SellerExpectedPriceMax),
|
||||
QualityLevel: toTextPointer(asset.QualityLevel),
|
||||
ScarcityLevel: toTextPointer(asset.ScarcityLevel),
|
||||
BaseValueScore: toNumericPointer(asset.BaseValueScore),
|
||||
BasePriceMin: toNumericPointer(asset.BasePriceMin),
|
||||
BasePriceMax: toNumericPointer(asset.BasePriceMax),
|
||||
AssetStatus: asset.AssetStatus,
|
||||
CreatedAt: toTimePointer(asset.CreatedAt),
|
||||
UpdatedAt: toTimePointer(asset.UpdatedAt),
|
||||
AgentAssetSummary: toTextPointer(asset.AgentAssetSummary),
|
||||
AgentRecommendedTasks: toStringArray(asset.AgentRecommendedTasks),
|
||||
AgentRiskPerMissionAdvice: toTextPointer(asset.AgentRiskPerMissionAdvice),
|
||||
AgentAssetExplanation: toTextPointer(asset.AgentAssetExplanation),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,6 +988,14 @@ func toTextPointer(value pgtype.Text) *string {
|
||||
return new(value.String)
|
||||
}
|
||||
|
||||
func toStringArray(value []byte) []string {
|
||||
var result []string
|
||||
if err := json.Unmarshal(value, &result); err != nil {
|
||||
slog.Warn(err.Error(), "value", string(value))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toNumericPointer(value pgtype.Numeric) *float64 {
|
||||
if !value.Valid {
|
||||
return nil
|
||||
|
||||
@@ -36,6 +36,14 @@ type Asset struct {
|
||||
AssetStatus string `json:"asset_status"`
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"`
|
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||
// 智能助手对当前资产的简短画像总结
|
||||
AgentAssetSummary *string `json:"agent_asset_summary"`
|
||||
// 推荐的适用任务列表
|
||||
AgentRecommendedTasks []string `json:"agent_recommended_tasks"`
|
||||
// 当前资产更适合的权限与风险建议
|
||||
AgentRiskPerMissionAdvice *string `json:"agent_risk_per_mission_advice"`
|
||||
// 为什么该资产当前基础价值较高/中/低
|
||||
AgentAssetExplanation *string `json:"agent_asset_explanation"`
|
||||
}
|
||||
|
||||
type AssetCreateInput struct {
|
||||
@@ -176,17 +184,20 @@ type AssetService interface {
|
||||
GetAsset(context.Context, string) (Asset, error)
|
||||
ListAssets(context.Context, AssetListInput) (ListResult[Asset], error)
|
||||
UpdateAssetStatus(context.Context, string, StatusUpdate) (AssetStatusResult, error)
|
||||
//DeleteAsset(context.Context, string) (AssetStatusResult, error)
|
||||
}
|
||||
|
||||
type PricingService interface {
|
||||
CreatePricing(context.Context, PricingCreateInput) (Pricing, error)
|
||||
GetPricing(context.Context, string) (Pricing, error)
|
||||
//DeletePricing(context.Context, string) (Pricing, error)
|
||||
}
|
||||
|
||||
type ValidationService interface {
|
||||
CreateValidation(context.Context, ValidationCreateInput) (ValidationCreateResult, error)
|
||||
GetValidation(context.Context, string) (Validation, error)
|
||||
ListValidations(context.Context, ValidationListInput) (ListResult[Validation], error)
|
||||
//DeleteValidation(context.Context, string) (Validation, error)
|
||||
}
|
||||
|
||||
type OrderService interface {
|
||||
@@ -194,4 +205,22 @@ type OrderService interface {
|
||||
GetOrder(context.Context, string) (Order, error)
|
||||
ListOrders(context.Context, OrderListInput) (ListResult[Order], error)
|
||||
UpdateOrderStatus(context.Context, string, StatusUpdate) (OrderCreateResult, error)
|
||||
//DeleteOrder(context.Context, string) (Order, error)
|
||||
}
|
||||
|
||||
type VerifyUserInput struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type VerifyUserResult struct {
|
||||
Token string `json:"token"`
|
||||
UserId string `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type AuthService interface {
|
||||
VerifyUser(context.Context, VerifyUserInput) (VerifyUserResult, error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user