heruvym/dal/mongo/dal.go

1070 lines
22 KiB
Go
Raw Normal View History

2021-09-05 15:24:13 +00:00
package mongo
2021-04-10 18:46:51 +00:00
import (
"context"
"errors"
2021-05-15 20:10:07 +00:00
"fmt"
2022-11-02 18:52:02 +00:00
"heruvym/model"
"time"
2021-04-10 18:46:51 +00:00
"github.com/rs/xid"
"gitea.pena/PenaSide/hlog"
2021-05-01 12:36:22 +00:00
"go.mongodb.org/mongo-driver/bson"
2021-09-05 15:24:13 +00:00
"go.mongodb.org/mongo-driver/bson/primitive"
2021-04-10 18:46:51 +00:00
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
2021-04-11 09:48:15 +00:00
const (
collMessages = "messages"
collTickets = "tickets"
collAccount = "account"
2021-04-11 09:48:15 +00:00
)
2021-04-10 18:46:51 +00:00
type DAL struct {
logger hlog.Logger
colMsg, colTck, colAcc *mongo.Collection
client *mongo.Client
2021-04-10 18:46:51 +00:00
}
type ErrorConnectToDB struct {
Err error
MongoURI string
}
type ErrorPingDB struct {
Err error
MongoURI string
}
type InfoPing struct {
MongoURI string
2021-04-11 09:48:15 +00:00
Nanoseconds int64
2021-04-10 18:46:51 +00:00
}
func New(
ctx context.Context,
mongoURI, database string,
log hlog.Logger,
) (*DAL, error) {
client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoURI))
if err != nil {
log.Emit(ErrorConnectToDB{
Err: err,
MongoURI: mongoURI,
})
return nil, err
}
2021-04-11 09:48:15 +00:00
before := time.Now().Unix()
2021-04-10 18:46:51 +00:00
if err := client.Ping(ctx, readpref.PrimaryPreferred()); err != nil {
log.Emit(ErrorPingDB{
Err: err,
MongoURI: mongoURI,
})
return nil, err
}
log.Emit(InfoPing{
MongoURI: mongoURI,
2021-04-11 09:48:15 +00:00
Nanoseconds: time.Now().Unix() - before,
2021-04-10 18:46:51 +00:00
})
2022-11-02 18:52:02 +00:00
fmt.Println("dal0")
dal := &DAL{
2021-04-10 18:46:51 +00:00
client: client,
2021-04-11 09:48:15 +00:00
colMsg: client.Database(database).Collection(collMessages),
colTck: client.Database(database).Collection(collTickets),
colAcc: client.Database(database).Collection(collAccount),
2021-04-10 18:46:51 +00:00
logger: log.Module("DAL"),
}
2022-11-02 18:52:02 +00:00
fmt.Println("dal1")
// Будет ошибка создания индексов только если эти индексы изменить и предварительно не удалить старые
err = dal.CreateTicketIndex(ctx)
if err != nil {
return nil, err
}
2022-11-02 18:52:02 +00:00
fmt.Println("dal2")
err = dal.CreateMessageIndex(ctx)
if err != nil {
return nil, err
}
err = dal.CreateAccountIndex(ctx)
if err != nil {
return nil, err
}
2022-11-02 18:52:02 +00:00
fmt.Println("dal3")
return dal, nil
2021-04-10 18:46:51 +00:00
}
type ErrorInsert struct {
2021-04-11 09:48:15 +00:00
Err error
2021-04-10 18:46:51 +00:00
UserID, SessionID string
}
type ErrorCreateIndex struct {
Err error
}
func (d *DAL) CreateMessageIndex(ctx context.Context) error {
keys := bson.D{{"$**", "text"}}
opts := options.Index().SetDefaultLanguage("russian")
_, err := d.colMsg.Indexes().CreateOne(ctx, mongo.IndexModel{Keys: keys, Options: opts})
if err != nil {
d.logger.Emit(ErrorCreateIndex{err})
}
return err
}
func (d *DAL) CreateTicketIndex(ctx context.Context) error {
keys := bson.D{{"$**", "text"}}
opts := options.Index().SetDefaultLanguage("russian")
_, err := d.colTck.Indexes().CreateOne(ctx, mongo.IndexModel{Keys: keys, Options: opts})
if err != nil {
d.logger.Emit(ErrorCreateIndex{err})
}
return err
}
func (d *DAL) CreateAccountIndex(ctx context.Context) error {
keys := bson.D{{"$**", "text"}}
opts := options.Index().SetDefaultLanguage("russian")
_, err := d.colAcc.Indexes().CreateOne(ctx, mongo.IndexModel{Keys: keys, Options: opts})
if err != nil {
d.logger.Emit(ErrorCreateIndex{err})
}
return err
}
2021-04-10 18:46:51 +00:00
func (d *DAL) PutMessage(
ctx context.Context,
2021-04-11 09:48:15 +00:00
message, userID, sessionID, ticketID string,
2021-04-10 18:46:51 +00:00
files []string,
2021-05-02 22:25:12 +00:00
) (*model.Message, error) {
insertable := model.Message{
2021-04-10 18:46:51 +00:00
ID: xid.New().String(),
UserID: userID,
SessionID: sessionID,
2021-04-11 09:48:15 +00:00
TicketID: ticketID,
2021-04-10 18:46:51 +00:00
Message: message,
2022-02-27 15:27:44 +00:00
Files: files,
Shown: map[string]int{},
CreatedAt: time.Now(),
}
if _, err := d.colMsg.InsertOne(ctx, &insertable); err != nil {
d.logger.Emit(ErrorInsert{
Err: err,
UserID: userID,
SessionID: sessionID,
})
return nil, err
}
return &insertable, nil
}
func (d *DAL) PutSCResponse(
ctx context.Context,
message, userID, sessionID, ticketID string,
files []string,
) (*model.Message, error) {
insertable := model.Message{
ID: xid.New().String(),
UserID: userID,
SessionID: sessionID,
TicketID: ticketID,
Message: message,
Files: files,
2022-02-27 15:27:44 +00:00
RequestScreenshot: "response",
Shown: map[string]int{},
CreatedAt: time.Now(),
2022-02-27 15:27:44 +00:00
}
if _, err := d.colMsg.InsertOne(ctx, &insertable); err != nil {
d.logger.Emit(ErrorInsert{
Err: err,
UserID: userID,
SessionID: sessionID,
})
return nil, err
}
return &insertable, nil
}
func (d *DAL) PutSCRequest(
ctx context.Context,
userID, sessionID, ticketID string,
) (*model.Message, error) {
insertable := model.Message{
ID: xid.New().String(),
UserID: userID,
SessionID: sessionID,
TicketID: ticketID,
Message: "",
Files: []string{},
Shown: map[string]int{},
2022-02-27 15:27:44 +00:00
RequestScreenshot: "acquisition",
CreatedAt: time.Now(),
2021-05-02 22:25:12 +00:00
}
if _, err := d.colMsg.InsertOne(ctx, &insertable); err != nil {
2021-04-10 18:46:51 +00:00
d.logger.Emit(ErrorInsert{
Err: err,
UserID: userID,
SessionID: sessionID,
})
2021-05-02 22:25:12 +00:00
return nil, err
2021-04-10 18:46:51 +00:00
}
2021-05-02 22:25:12 +00:00
return &insertable, nil
2021-04-10 18:46:51 +00:00
}
2021-04-11 09:48:15 +00:00
func (d *DAL) CreateTicket(
ctx context.Context,
userID,
sessionID,
2024-03-07 18:58:59 +00:00
origin,
2021-05-02 22:25:12 +00:00
title, message string,
files []string,
2021-04-11 09:48:15 +00:00
) (string, error) {
2021-05-02 22:25:12 +00:00
ticketID := xid.New().String()
2021-04-11 09:48:15 +00:00
if _, err := d.colTck.InsertOne(ctx, &model.Ticket{
2021-05-02 22:25:12 +00:00
ID: ticketID,
2021-04-11 09:48:15 +00:00
UserID: userID,
SessionID: sessionID,
Title: title,
2021-05-02 22:25:12 +00:00
State: model.StateOpen,
2021-04-11 09:53:26 +00:00
CreatedAt: time.Now(),
2022-04-14 17:43:13 +00:00
UpdatedAt: time.Now(),
2021-05-11 10:57:58 +00:00
Rate: -1,
2024-03-07 18:58:59 +00:00
Origin: origin,
2021-05-02 22:25:12 +00:00
TopMessage: model.Message{
ID: xid.New().String(),
UserID: userID,
SessionID: sessionID,
TicketID: ticketID,
Message: message,
2021-09-05 15:24:13 +00:00
Files: []string{},
Shown: map[string]int{},
2021-05-02 22:25:12 +00:00
CreatedAt: time.Now(),
},
2021-04-11 09:48:15 +00:00
}); err != nil {
d.logger.Emit(ErrorInsert{
Err: err,
UserID: userID,
SessionID: sessionID,
})
return "", err
}
2021-05-02 22:25:12 +00:00
return ticketID, nil
2021-04-11 09:48:15 +00:00
}
2021-05-01 12:36:22 +00:00
func (d *DAL) GetTickets4Sess(ctx context.Context, sessID string) ([]model.Ticket, int64, error) {
sort := bson.M{"State": -1, "UpdatedAt": 1}
opts := options.Find().SetSort(sort)
query := bson.M{
2021-05-01 12:36:22 +00:00
"SessionID": sessID,
}
cur, err := d.colTck.Find(ctx, query, opts)
2021-05-01 12:36:22 +00:00
if err != nil {
return nil, 0, err
2021-05-01 12:36:22 +00:00
}
var result []model.Ticket
if err := cur.All(ctx, &result); err != nil {
return nil, 0, err
2021-05-01 12:36:22 +00:00
}
col, err := d.colTck.CountDocuments(ctx, query)
if err != nil {
return nil, 0, err
}
return result, col, nil
2021-05-01 12:36:22 +00:00
}
2021-05-02 22:25:12 +00:00
func (d *DAL) GetTicket4Sess(
ctx context.Context,
ticketID,
sessID string) (*model.Ticket, error) {
var result model.Ticket
if err := d.colTck.FindOne(ctx, bson.M{
"_id": ticketID,
"SessionID": sessID,
}).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
func (d *DAL) GetTicket4User(
ctx context.Context,
ticketID,
userID string) (*model.Ticket, error) {
var result model.Ticket
if err := d.colTck.FindOne(ctx, bson.M{
"_id": ticketID,
"UserID": userID,
}).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
func (d *DAL) WatchTickets(
ctx context.Context,
userID string,
yield func(ticket model.Ticket) error) error {
operationTypes := []bson.D{{{"operationType", "insert"}},
{{"operationType", "update"}}}
2021-05-15 20:10:07 +00:00
matchStage := bson.M{
"$and": bson.A{
bson.M{"$or": operationTypes},
bson.M{"fullDocument.UserID": userID},
},
2021-05-02 22:25:12 +00:00
}
2021-05-15 20:10:07 +00:00
matchPipeline := mongo.Pipeline{
bson.D{{"$match", matchStage}},
2021-05-02 22:25:12 +00:00
}
cs, err := d.colTck.Watch(ctx, matchPipeline,
2021-09-05 15:24:13 +00:00
options.ChangeStream().SetFullDocument(options.UpdateLookup))
2021-05-02 22:25:12 +00:00
if err != nil {
fmt.Println("111", err, matchPipeline)
2021-05-02 22:25:12 +00:00
return err
}
for cs.Next(ctx) {
var (
2024-02-20 18:43:12 +00:00
piece model.Ticket
change Change
)
2021-09-05 15:24:13 +00:00
if err := cs.Decode(&change); err != nil {
return err
}
if err := bson.Unmarshal(change.FullDocument, &piece); err != nil {
2021-09-05 15:24:13 +00:00
return err
}
if err := yield(piece); err != nil {
return err
}
}
return nil
}
func (d *DAL) YieldActiveTickets(
ctx context.Context,
yield func(ticket model.Ticket) error) error {
cursor, err := d.colTck.Find(ctx, bson.M{
"State": model.StateOpen,
2022-02-27 15:27:44 +00:00
}, options.Find().SetLimit(20))
2021-09-05 15:24:13 +00:00
if err != nil {
return err
}
var piece model.Ticket
for cursor.Next(ctx) {
if err := cursor.Decode(&piece); err != nil {
2021-05-02 22:25:12 +00:00
return err
}
if err := yield(piece); err != nil {
return err
}
}
return nil
}
func (d *DAL) YieldTickets(ctx context.Context, limit int64) ([]model.Ticket, int64, error) {
2022-04-14 17:43:13 +00:00
sort := bson.D{{"State", -1}, {"UpdatedAt", 1}}
cursor, err := d.colTck.Find(ctx, bson.M{}, options.Find().SetLimit(limit).SetSort(sort))
if err != nil {
return nil, 0, err
}
var result []model.Ticket
err = cursor.All(ctx, &result)
if err != nil {
return nil, 0, err
}
col, err := d.colTck.CountDocuments(ctx, bson.M{})
if err != nil {
return nil, 0, err
}
return result, col, nil
}
func (d *DAL) YieldUserTickets(ctx context.Context, userID string, limit, offset int64) ([]model.Ticket, int64, error) {
query := bson.M{
2021-05-02 22:25:12 +00:00
"UserID": userID,
}
2024-02-20 18:43:12 +00:00
fmt.Println("UserID", userID)
sort := bson.D{{"State", -1}, {"UpdatedAt", -1}}
cursor, err := d.colTck.Find(ctx, query, options.Find().SetSort(sort).SetLimit(limit).SetSkip(offset))
2021-05-02 22:25:12 +00:00
if err != nil {
return nil, 0, err
2021-05-02 22:25:12 +00:00
}
var result []model.Ticket
2021-05-02 22:25:12 +00:00
err = cursor.All(ctx, &result)
if err != nil {
return nil, 0, err
2021-05-02 22:25:12 +00:00
}
col, err := d.colTck.CountDocuments(ctx, query)
if err != nil {
return nil, 0, err
}
return result, col, nil
2021-05-02 22:25:12 +00:00
}
func (d *DAL) WatchAllTickets(ctx context.Context, yield func(ticket model.Ticket) error) error {
2022-02-27 15:27:44 +00:00
operationTypes := []bson.D{
{{"operationType", "insert"}},
{{"operationType", "update"}},
}
2021-05-02 22:25:12 +00:00
matchStage := bson.D{{"$or", operationTypes}}
2021-05-02 22:25:12 +00:00
2021-09-05 15:24:13 +00:00
matchPipeline := mongo.Pipeline{
bson.D{
{"$match", matchStage},
},
2021-05-02 22:25:12 +00:00
}
cs, err := d.colTck.Watch(ctx, matchPipeline,
2021-09-05 15:24:13 +00:00
options.ChangeStream().SetFullDocument(options.UpdateLookup))
2021-05-02 22:25:12 +00:00
if err != nil {
return err
}
for cs.Next(ctx) {
var (
2024-02-20 18:43:12 +00:00
piece model.Ticket
change Change
)
2021-09-05 15:24:13 +00:00
if err := cs.Decode(&change); err != nil {
return err
}
if err := bson.Unmarshal(change.FullDocument, &piece); err != nil {
2021-05-02 22:25:12 +00:00
return err
}
if err := yield(piece); err != nil {
return err
}
}
return nil
}
func (d *DAL) UpdateTopMessage(ctx context.Context, ticketID string, msg *model.Message) error {
if err := d.colTck.FindOneAndUpdate(ctx, bson.M{
"_id": ticketID,
}, bson.M{
"$set": bson.M{
"UpdatedAt": time.Now(),
"TopMessage": msg,
},
}).Decode(&model.Ticket{}); err != nil {
return err
}
return nil
}
func (d *DAL) YieldMessages(
ctx context.Context,
ticketID string,
yield func(ticket model.Message) error) error {
2021-05-15 20:10:07 +00:00
cursor, err := d.colMsg.Find(ctx, bson.M{
2021-05-02 22:25:12 +00:00
"TicketID": ticketID,
2023-04-06 10:43:15 +00:00
}, options.Find().SetLimit(20).SetSort(bson.D{{"CreatedAt", -1}}))
2021-05-02 22:25:12 +00:00
if err != nil {
return err
}
var piece model.Message
for cursor.Next(ctx) {
if err := cursor.Decode(&piece); err != nil {
return err
}
if err := yield(piece); err != nil {
return err
}
}
return nil
}
2021-09-05 15:24:13 +00:00
type OpType string
const (
OpInsert OpType = "insert"
OpDelete OpType = "delete"
OpReplace OpType = "replace"
OpUpdate OpType = "update"
)
type Change struct {
ID struct {
Data string `bson:"_data"`
} `bson:"_id"`
OperationType OpType `bson:"operationType"`
FullDocument bson.Raw `bson:"fullDocument"`
NS struct {
DB string `bson:"db"`
Coll string `bson:"coll"`
} `bson:"ns"`
To *struct {
DB string `bson:"db"`
Coll string `bson:"coll"`
} `bson:"to"`
DocumentKey bson.Raw `bson:"documentKey"`
UpdateDescription *struct {
UpdatedFields bson.Raw `bson:"updatedFields"`
RemovedFields []string `bson:"removedFields"`
} `bson:"updateDescription"`
ClusterTime primitive.Timestamp `bson:"clusterTime"`
TxnNumber int64 `bson:"txnNumber"`
LSID bson.Raw `bson:"lsid"`
//LSID *struct {
// ID primitive.ObjectID `bson:"id"`
// UID primitive.Binary `bson:"uid"`
//} `bson:"lsid"`
}
2021-05-02 22:25:12 +00:00
func (d *DAL) WatchMessages(
ctx context.Context, ticketID string, yield func(ticket model.Message) error) error {
operationTypes := []bson.D{{{"operationType", "insert"}},
{{"operationType", "update"}}}
matchStage := bson.D{{"$and", []bson.D{
{
{"$or", operationTypes},
},
{
{
"fullDocument.TicketID", ticketID,
},
},
}}}
2021-05-15 20:10:07 +00:00
matchPipeline := mongo.Pipeline{
bson.D{{"$match", matchStage}},
2021-05-02 22:25:12 +00:00
}
cs, err := d.colMsg.Watch(ctx, matchPipeline,
2021-09-05 15:24:13 +00:00
options.ChangeStream().SetFullDocument(options.UpdateLookup))
2021-05-02 22:25:12 +00:00
if err != nil {
return err
}
for cs.Next(ctx) {
2023-09-01 20:01:20 +00:00
var (
2024-02-20 18:43:12 +00:00
piece model.Message
2023-09-01 20:01:20 +00:00
change Change
)
2024-02-20 18:43:12 +00:00
2021-09-05 15:24:13 +00:00
if err := cs.Decode(&change); err != nil {
2021-05-02 22:25:12 +00:00
return err
}
2021-09-05 15:24:13 +00:00
bson.Unmarshal(change.FullDocument, &piece)
2021-05-02 22:25:12 +00:00
if err := yield(piece); err != nil {
return err
}
}
return nil
}
func (d *DAL) SetShown(ctx context.Context, messageID, userID string) error {
if err := d.colMsg.FindOneAndUpdate(ctx, bson.M{
"_id": messageID,
}, bson.M{
"$set": bson.M{
fmt.Sprintf("Shown.%s", userID): 1,
2021-05-02 22:25:12 +00:00
},
}).Decode(&model.Message{}); err != nil {
return err
}
2023-08-16 21:15:49 +00:00
if err := d.colTck.FindOneAndUpdate(ctx, bson.M{
"TopMessage._id": messageID,
}, bson.M{
"$set": bson.M{
fmt.Sprintf("TopMessage.Shown.%s", userID): 1,
},
}).Decode(&model.Message{}); err != nil {
return err
}
2021-05-02 22:25:12 +00:00
return nil
}
2021-05-11 10:57:58 +00:00
func (d *DAL) GetTicketPage(
ctx context.Context,
state, srch string,
limit, skip int64,
2022-02-27 15:27:44 +00:00
) (*[]model.Ticket, int64, error) {
2021-05-11 10:57:58 +00:00
query := bson.M{}
if state != "" {
query["State"] = state
}
if srch != "" {
query["$text"] = bson.M{
2021-05-11 10:57:58 +00:00
"$search": srch,
}
}
2022-04-14 17:43:13 +00:00
sort := bson.D{{"State", -1}, {"UpdatedAt", -1}}
2022-04-14 17:43:13 +00:00
cur, err := d.colTck.Find(ctx, query, options.Find().SetSort(sort).SetLimit(limit).SetSkip(skip*limit))
2021-05-11 10:57:58 +00:00
if err != nil {
return nil, 0, err
2021-05-11 10:57:58 +00:00
}
var result []model.Ticket
if err := cur.All(ctx, &result); err != nil {
return nil, 0, err
2021-05-11 10:57:58 +00:00
}
2022-02-27 15:27:44 +00:00
col, err := d.colTck.CountDocuments(ctx, query)
if err != nil {
return nil, 0, err
}
return &result, col, nil
2021-05-11 10:57:58 +00:00
}
func (d *DAL) GetMessagesPage(ctx context.Context,
search, ticketID string,
limit, offset int64) ([]model.Message, error) {
var (
query bson.M
result []model.Message
)
if ticketID != "" {
query = bson.M{
"TicketID": ticketID,
}
}
2021-05-11 10:57:58 +00:00
if search != "" {
query = bson.M{
"TicketID": ticketID,
"$text": bson.M{
"$search": search,
},
}
}
2023-04-06 10:12:40 +00:00
sort := bson.D{{"CreatedAt", -1}}
cur, err := d.colMsg.Find(ctx, query, options.Find().SetLimit(limit).SetSkip(limit*offset).SetSort(sort))
2021-05-11 10:57:58 +00:00
if err != nil {
return nil, err
}
if err := cur.All(ctx, &result); err != nil {
return nil, err
}
return result, nil
2021-05-11 10:57:58 +00:00
}
func (d *DAL) SetTicketStatus(ctx context.Context,
ticket, status string) error {
if _, err := d.colTck.UpdateByID(ctx, ticket, bson.M{
2022-02-27 15:27:44 +00:00
"$set": bson.M{
"State": status,
"UpdatedAt": time.Now(),
},
2021-05-11 10:57:58 +00:00
}); err != nil {
return err
}
return nil
}
func (d *DAL) SetRate(ctx context.Context, ticket string, rate int) error {
if _, err := d.colTck.UpdateByID(ctx, ticket, bson.M{"$set": bson.M{
"Rate": rate,
"UpdatedAt": time.Now(),
}}); err != nil {
return err
}
return nil
}
func (d *DAL) SetAnswerer(ctx context.Context, ticket, answerer string) error {
if _, err := d.colTck.UpdateByID(ctx, ticket, bson.M{"$set": bson.M{
"AnswererID": answerer,
"UpdatedAt": time.Now(),
}}); err != nil {
return err
}
return nil
}
2022-11-02 18:52:02 +00:00
2022-04-14 17:43:13 +00:00
type Additional struct {
Email string
2022-11-02 18:52:02 +00:00
Uid int64
2022-04-14 17:43:13 +00:00
}
type Identites struct {
2022-11-02 18:52:02 +00:00
ID string `bson:"_id"`
2022-04-14 17:43:13 +00:00
Identites []Identity `bson:"Identities"`
}
type Identity struct {
2022-11-02 18:52:02 +00:00
Name string `bson:"Name"`
2022-04-14 17:43:13 +00:00
Identity string `bson:"Identity"`
}
type UidTechs struct {
2022-11-02 18:52:02 +00:00
DisplayID int64 `bson:"display_id"`
ID string `bson:"_id"`
2022-04-14 17:43:13 +00:00
}
2022-11-02 18:52:02 +00:00
2022-04-14 17:43:13 +00:00
func (d *DAL) GetAdditionalData(ctx context.Context, id string) (*Additional, error) {
result := Additional{}
idens := Identites{}
if err := d.client.Database("bb-identity").Collection("tp-users").FindOne(ctx, bson.M{
"_id": id,
}, options.FindOne().SetProjection(bson.D{{
2022-11-02 18:52:02 +00:00
"Identities", 1,
2022-04-14 17:43:13 +00:00
}})).Decode(&idens); err != nil {
return nil, err
}
for _, iden := range idens.Identites {
2022-11-02 18:52:02 +00:00
fmt.Println(iden.Name, iden)
2022-04-14 17:43:13 +00:00
if iden.Name == "email" {
result.Email = iden.Identity
}
}
u := UidTechs{}
if err := d.client.Database("profile").Collection("profile").FindOne(ctx, bson.M{
"_id": id,
2022-11-02 18:52:02 +00:00
}, options.FindOne().SetProjection(bson.D{{
"display_id", 1,
2022-04-14 17:43:13 +00:00
}})).Decode(&u); err != nil {
return nil, err
}
result.Uid = u.DisplayID
return &result, nil
}
func (d *DAL) InsertAccount(ctx context.Context, record *model.Account) (*model.Account, error) {
now := time.Now()
record.CreatedAt, record.UpdatedAt = now, now
record.ID = xid.New().String()
if record.Avatar == "" {
record.Avatar = "/media/avatar/default-avatar.jpg"
}
if record.Nickname == "" {
record.Nickname = "Unknown"
}
if record.Role == "" {
record.Role = "user"
}
_, err := d.colAcc.InsertOne(ctx, record)
if err != nil {
d.logger.Emit(ErrorInsertAccount{err, record})
return nil, err
}
return record, nil
}
type ErrorInsertAccount struct {
Err error
Account *model.Account
}
func (d *DAL) GetAccount(ctx context.Context, id string) (*model.Account, error) {
if id == "" {
err := errors.New("id cannot be empty")
d.logger.Emit(ErrorGetAccount{err, id})
return nil, err
}
var result model.Account
err := d.colAcc.FindOne(ctx, bson.M{"_id": id}).Decode(&result)
if err != nil {
d.logger.Emit(ErrorGetAccount{err, id})
return nil, err
}
return &result, nil
}
type ErrorGetAccount struct {
Err error
ID string
}
func (d *DAL) GetAccountByUserID(ctx context.Context, userId string) (*model.Account, error) {
if userId == "" {
err := errors.New("userId cannot be empty")
d.logger.Emit(ErrorGetAccount{err, userId})
return nil, err
}
var result model.Account
err := d.colAcc.FindOne(ctx, bson.M{"userId": userId}).Decode(&result)
if err != nil {
d.logger.Emit(ErrorGetAccount{err, userId})
return nil, err
}
return &result, nil
}
func (d *DAL) GetAccountPage(ctx context.Context, search string, offset, limit int64) (*model.AccountPage, error) {
var query bson.M
if search != "" {
query = bson.M{
"$text": bson.M{
"$search": search,
},
}
}
count, err := d.colAcc.CountDocuments(ctx, query)
sort := bson.D{{"CreatedAt", -1}}
cur, err := d.colAcc.Find(ctx, query, options.Find().SetLimit(limit).SetSkip(limit*offset).SetSort(sort))
if err != nil {
return nil, err
}
var items []model.Account
if err := cur.All(ctx, &items); err != nil {
return nil, err
}
return &model.AccountPage{Count: count, Items: items}, nil
}
func (d *DAL) SetAccountRole(ctx context.Context, userId, role string) (*model.Account, error) {
if userId == "" {
err := errors.New("userId cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
if role == "" {
err := errors.New("role cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
filter := bson.M{"userId": userId}
update := bson.M{"role": role, "updatedAt": time.Now()}
var result model.Account
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
err := d.colAcc.FindOneAndUpdate(ctx, filter, bson.M{"$set": update}, opts).Decode(&result)
if err != nil {
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
return &result, nil
}
func (d *DAL) SetAccountNickname(ctx context.Context, userId, nickname string) (*model.Account, error) {
if userId == "" {
err := errors.New("userId cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
if nickname == "" {
err := errors.New("nickname cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
filter := bson.M{"userId": userId}
update := bson.M{"nickname": nickname, "updatedAt": time.Now()}
var result model.Account
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
err := d.colAcc.FindOneAndUpdate(ctx, filter, bson.M{"$set": update}, opts).Decode(&result)
if err != nil {
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
return &result, nil
}
func (d *DAL) SetAccountAvatar(ctx context.Context, userId, avatar string) (*model.Account, error) {
if userId == "" {
err := errors.New("userId cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
if avatar == "" {
err := errors.New("avatar cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
filter := bson.M{"userId": userId}
update := bson.M{"avatar": avatar, "updatedAt": time.Now()}
var result model.Account
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
err := d.colAcc.FindOneAndUpdate(ctx, filter, bson.M{"$set": update}, opts).Decode(&result)
if err != nil {
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
return &result, nil
}
func (d *DAL) SetAccountDelete(ctx context.Context, userId string, isDeleted bool) (*model.Account, error) {
if userId == "" {
err := errors.New("userId cannot be empty")
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
filter := bson.M{"userId": userId}
update := bson.M{"isDeleted": isDeleted, "updatedAt": time.Now()}
var result model.Account
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
err := d.colAcc.FindOneAndUpdate(ctx, filter, bson.M{"$set": update}, opts).Decode(&result)
if err != nil {
d.logger.Emit(ErrorSetAccount{err, userId})
return nil, err
}
return &result, nil
}
type ErrorSetAccount struct {
Err error
UserID string
}
func (d *DAL) DeleteAccount(ctx context.Context, userId string) (*model.Account, error) {
if userId == "" {
err := errors.New("userId cannot be empty")
d.logger.Emit(ErrorDeleteAccount{err, userId})
return nil, err
}
filter := bson.M{"userId": userId}
var acc model.Account
err := d.colAcc.FindOne(ctx, filter).Decode(&acc)
if err != nil {
d.logger.Emit(ErrorDeleteAccount{err, userId})
return nil, err
}
_, err = d.colAcc.DeleteOne(ctx, filter)
if err != nil {
d.logger.Emit(ErrorDeleteAccount{err, userId})
return nil, err
}
return &acc, err
}
type ErrorDeleteAccount struct {
Err error
UserID string
}