github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/publisher/publisher.go (about)

     1  package publisher
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	confid "github.com/machinefi/w3bstream/pkg/depends/conf/id"
     8  	"github.com/machinefi/w3bstream/pkg/depends/kit/logr"
     9  	"github.com/machinefi/w3bstream/pkg/depends/kit/sqlx"
    10  	"github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/builder"
    11  	"github.com/machinefi/w3bstream/pkg/depends/x/contextx"
    12  	"github.com/machinefi/w3bstream/pkg/enums"
    13  	"github.com/machinefi/w3bstream/pkg/errors/status"
    14  	"github.com/machinefi/w3bstream/pkg/models"
    15  	"github.com/machinefi/w3bstream/pkg/modules/access_key"
    16  	"github.com/machinefi/w3bstream/pkg/modules/metrics"
    17  	"github.com/machinefi/w3bstream/pkg/types"
    18  )
    19  
    20  func GetBySFID(ctx context.Context, id types.SFID) (*models.Publisher, error) {
    21  	ctx, l := logr.Start(ctx, "publisher.GetBySFID")
    22  	defer l.End()
    23  
    24  	d := types.MustMgrDBExecutorFromContext(ctx)
    25  	m := &models.Publisher{RelPublisher: models.RelPublisher{PublisherID: id}}
    26  
    27  	if err := m.FetchByPublisherID(d); err != nil {
    28  		if sqlx.DBErr(err).IsNotFound() {
    29  			return nil, status.PublisherNotFound
    30  		}
    31  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
    32  	}
    33  	return m, nil
    34  }
    35  
    36  func GetByProjectAndKey(ctx context.Context, prj types.SFID, key string) (*models.Publisher, error) {
    37  	ctx, l := logr.Start(ctx, "publisher.GetByProjectAndKey")
    38  	defer l.End()
    39  
    40  	d := types.MustMgrDBExecutorFromContext(ctx)
    41  	m := &models.Publisher{
    42  		RelProject:    models.RelProject{ProjectID: prj},
    43  		PublisherInfo: models.PublisherInfo{Key: key},
    44  	}
    45  
    46  	if err := m.FetchByProjectIDAndKey(d); err != nil {
    47  		if sqlx.DBErr(err).IsNotFound() {
    48  			return nil, status.PublisherNotFound
    49  		}
    50  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
    51  	}
    52  	return m, nil
    53  }
    54  
    55  func ListByCond(ctx context.Context, r *CondArgs) (data []models.Publisher, err error) {
    56  	ctx, l := logr.Start(ctx, "publisher.ListByCond")
    57  	defer l.End()
    58  
    59  	var (
    60  		d = types.MustMgrDBExecutorFromContext(ctx)
    61  		m = &models.Publisher{}
    62  	)
    63  	data, err = m.List(d, r.Condition())
    64  	if err != nil {
    65  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
    66  	}
    67  	return data, nil
    68  }
    69  
    70  func List(ctx context.Context, r *ListReq) (*ListRsp, error) {
    71  	ctx, l := logr.Start(ctx, "publisher.List")
    72  	defer l.End()
    73  
    74  	var (
    75  		d = types.MustMgrDBExecutorFromContext(ctx)
    76  		m = &models.Publisher{}
    77  
    78  		ret = &ListRsp{}
    79  		err error
    80  
    81  		cond = r.Condition()
    82  		adds = r.Additions()
    83  	)
    84  
    85  	ret.Data, err = m.List(d, cond, adds...)
    86  	if err != nil {
    87  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
    88  	}
    89  	ret.Total, err = m.Count(d, cond)
    90  	if err != nil {
    91  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
    92  	}
    93  	return ret, nil
    94  }
    95  
    96  func ListDetail(ctx context.Context, r *ListReq) (*ListDetailRsp, error) {
    97  	ctx, l := logr.Start(ctx, "publisher.ListDetail")
    98  	defer l.End()
    99  
   100  	var (
   101  		d = types.MustMgrDBExecutorFromContext(ctx)
   102  
   103  		pub = &models.Publisher{}
   104  		prj = types.MustProjectFromContext(ctx)
   105  		ret = &ListDetailRsp{}
   106  		err error
   107  
   108  		cond = r.Condition()
   109  		adds = r.Additions()
   110  	)
   111  
   112  	expr := builder.Select(builder.MultiWith(",",
   113  		builder.Alias(prj.ColName(), "f_project_name"),
   114  		pub.ColProjectID(),
   115  		pub.ColPublisherID(),
   116  		pub.ColName(),
   117  		pub.ColKey(),
   118  		pub.ColCreatedAt(),
   119  		pub.ColUpdatedAt(),
   120  	)).From(
   121  		d.T(pub),
   122  		append([]builder.Addition{
   123  			builder.LeftJoin(d.T(prj)).On(pub.ColProjectID().Eq(prj.ColProjectID())),
   124  			builder.Where(builder.And(cond, prj.ColDeletedAt().Neq(0))),
   125  		}, adds...)...,
   126  	)
   127  	err = d.QueryAndScan(expr, ret.Data)
   128  	if err != nil {
   129  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
   130  	}
   131  	ret.Total, err = pub.Count(d, cond)
   132  	if err != nil {
   133  		return nil, status.DatabaseError.StatusErr().WithDesc(err.Error())
   134  	}
   135  	return ret, nil
   136  }
   137  
   138  func RemoveBySFID(ctx context.Context, acc *models.Account, prj *models.Project, id types.SFID) error {
   139  	ctx, l := logr.Start(ctx, "publisher.RemoveBySFID")
   140  	defer l.End()
   141  
   142  	d := types.MustMgrDBExecutorFromContext(ctx)
   143  	m := &models.Publisher{}
   144  
   145  	if err := sqlx.NewTasks(d).With(
   146  		func(d sqlx.DBExecutor) error {
   147  			ctx := types.WithMgrDBExecutor(ctx, d)
   148  			var err error
   149  			m, err = GetBySFID(ctx, id)
   150  			return err
   151  		},
   152  		func(d sqlx.DBExecutor) error {
   153  			if err := m.DeleteByPublisherID(d); err != nil {
   154  				return status.DatabaseError.StatusErr().WithDesc(err.Error())
   155  			}
   156  			return nil
   157  		},
   158  		func(d sqlx.DBExecutor) error {
   159  			ctx := contextx.WithContextCompose(
   160  				types.WithMgrDBExecutorContext(d),
   161  				types.WithAccountContext(acc),
   162  			)(ctx)
   163  			return access_key.DeleteByName(ctx, "pub_"+id.String())
   164  		},
   165  	).Do(); err != nil {
   166  		return err
   167  	}
   168  	metrics.PublisherMetricsDec(ctx, acc.AccountID.String(), prj.Name)
   169  	return nil
   170  }
   171  
   172  func RemoveByProjectAndKey(ctx context.Context, prj types.SFID, key string) error {
   173  	ctx, l := logr.Start(ctx, "publisher.RemoveByProjectAndKey")
   174  	defer l.End()
   175  
   176  	d := types.MustMgrDBExecutorFromContext(ctx)
   177  	m := &models.Publisher{}
   178  
   179  	return sqlx.NewTasks(d).With(
   180  		func(d sqlx.DBExecutor) error {
   181  			ctx := types.WithMgrDBExecutor(ctx, d)
   182  			var err error
   183  			m, err = GetByProjectAndKey(ctx, prj, key)
   184  			return err
   185  		},
   186  		func(d sqlx.DBExecutor) error {
   187  			if err := m.DeleteByProjectIDAndKey(d); err != nil {
   188  				return status.DatabaseError.StatusErr().WithDesc(err.Error())
   189  			}
   190  			return nil
   191  		},
   192  	).Do()
   193  }
   194  
   195  func Remove(ctx context.Context, acc *models.Account, r *CondArgs) error {
   196  	ctx, l := logr.Start(ctx, "publisher.Remove")
   197  	defer l.End()
   198  
   199  	d := types.MustMgrDBExecutorFromContext(ctx)
   200  	m := &models.Publisher{}
   201  	prj := types.MustProjectFromContext(ctx)
   202  
   203  	expr := builder.Delete().From(d.T(m), builder.Where(r.Condition()))
   204  
   205  	res, err := d.Exec(expr)
   206  	if err != nil {
   207  		return status.DatabaseError.StatusErr().WithDesc(err.Error())
   208  	}
   209  	numDeleted, err := res.RowsAffected()
   210  	if err != nil {
   211  		return err
   212  	}
   213  	for i := 0; i < int(numDeleted); i++ {
   214  		metrics.PublisherMetricsDec(ctx, acc.AccountID.String(), prj.Name)
   215  	}
   216  	return nil
   217  }
   218  
   219  func Create(ctx context.Context, r *CreateReq) (*models.Publisher, error) {
   220  	ctx, l := logr.Start(ctx, "publisher.Create")
   221  	defer l.End()
   222  
   223  	var (
   224  		d   = types.MustMgrDBExecutorFromContext(ctx)
   225  		prj = types.MustProjectFromContext(ctx)
   226  		acc = types.MustAccountFromContext(ctx)
   227  		idg = confid.MustSFIDGeneratorFromContext(ctx)
   228  		pub *models.Publisher
   229  		tok *access_key.CreateRsp
   230  	)
   231  
   232  	err := sqlx.NewTasks(d).With(
   233  		func(d sqlx.DBExecutor) (err error) {
   234  			id := idg.MustGenSFID()
   235  			tok, err = access_key.Create(types.WithMgrDBExecutor(ctx, d), &access_key.CreateReq{
   236  				IdentityID:   id,
   237  				IdentityType: enums.ACCESS_KEY_IDENTITY_TYPE__PUBLISHER,
   238  				CreateReqBase: access_key.CreateReqBase{
   239  					Name: "pub_" + id.String(),
   240  					Desc: "pub_" + id.String(),
   241  					Privileges: access_key.GroupAccessPrivileges{{
   242  						Name: enums.ApiGroupEvent,
   243  						Perm: enums.ACCESS_PERMISSION__READ_WRITE,
   244  					}},
   245  				},
   246  			})
   247  			if err != nil {
   248  				return err
   249  			}
   250  			return nil
   251  		},
   252  		func(d sqlx.DBExecutor) error {
   253  			pub = &models.Publisher{
   254  				RelProject:   models.RelProject{ProjectID: prj.ProjectID},
   255  				RelPublisher: models.RelPublisher{PublisherID: tok.IdentityID},
   256  				PublisherInfo: models.PublisherInfo{
   257  					Name:  r.Name,
   258  					Key:   r.Key,
   259  					Token: tok.AccessKey,
   260  				},
   261  			}
   262  			if err := pub.Create(d); err != nil {
   263  				if sqlx.DBErr(err).IsConflict() {
   264  					return status.PublisherConflict
   265  				}
   266  				return status.DatabaseError.StatusErr().WithDesc(err.Error())
   267  			}
   268  			return nil
   269  		},
   270  	).Do()
   271  
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  	metrics.PublisherMetricsInc(ctx, acc.AccountID.String(), prj.Name)
   276  	return pub, nil
   277  }
   278  
   279  func CreateIfNotExist(ctx context.Context, r *CreateReq) (*models.Publisher, error) {
   280  	var (
   281  		prj = types.MustProjectFromContext(ctx)
   282  		idg = confid.MustSFIDGeneratorFromContext(ctx)
   283  		d   = types.MustMgrDBExecutorFromContext(ctx)
   284  		m   = &models.Publisher{}
   285  	)
   286  
   287  	m.PublisherID = idg.MustGenSFID()
   288  	m.ProjectID = prj.ProjectID
   289  	m.Key = r.Key
   290  	m.Name = r.Name
   291  	if err := m.Create(d); err != nil {
   292  		if !sqlx.DBErr(err).IsConflict() {
   293  			return nil, status.DatabaseError.StatusErr().
   294  				WithDesc(fmt.Sprintf("create publisher failed: %v", err))
   295  		}
   296  	} else {
   297  		return m, nil
   298  	}
   299  	if err := m.FetchByProjectIDAndKey(d); err != nil {
   300  		return nil, status.DatabaseError.StatusErr().
   301  			WithDesc(fmt.Sprintf("fetch publisher failed: %v", err))
   302  	}
   303  	return m, nil
   304  }
   305  
   306  func Upsert(ctx context.Context, r *CreateReq) (*models.Publisher, error) {
   307  	ctx, l := logr.Start(ctx, "publisher.Upsert")
   308  	defer l.End()
   309  
   310  	var (
   311  		d      = types.MustMgrDBExecutorFromContext(ctx)
   312  		prj    = types.MustProjectFromContext(ctx)
   313  		acc    = types.MustAccountFromContext(ctx)
   314  		idg    = confid.MustSFIDGeneratorFromContext(ctx)
   315  		pub    *models.Publisher
   316  		tok    *access_key.CreateRsp
   317  		exists = false
   318  	)
   319  
   320  	err := sqlx.NewTasks(d).With(
   321  		func(d sqlx.DBExecutor) error {
   322  			pub = &models.Publisher{
   323  				PublisherInfo: models.PublisherInfo{
   324  					Name: r.Name,
   325  					Key:  r.Key,
   326  				},
   327  				RelProject: models.RelProject{ProjectID: prj.ProjectID},
   328  			}
   329  			if err := pub.FetchByProjectIDAndKey(d); err != nil {
   330  				if sqlx.DBErr(err).IsNotFound() {
   331  					return nil
   332  				} else {
   333  					return status.DatabaseError.StatusErr().WithDesc(err.Error())
   334  				}
   335  			}
   336  			exists = true
   337  			return nil
   338  		},
   339  		func(d sqlx.DBExecutor) (err error) {
   340  			if exists {
   341  				return nil
   342  			}
   343  			id := idg.MustGenSFID()
   344  			tok, err = access_key.Create(types.WithMgrDBExecutor(ctx, d), &access_key.CreateReq{
   345  				IdentityID:   id,
   346  				IdentityType: enums.ACCESS_KEY_IDENTITY_TYPE__PUBLISHER,
   347  				CreateReqBase: access_key.CreateReqBase{
   348  					Name: "pub_" + id.String(),
   349  					Desc: "pub_" + id.String(),
   350  					Privileges: access_key.GroupAccessPrivileges{{
   351  						Name: enums.ApiGroupEvent,
   352  						Perm: enums.ACCESS_PERMISSION__READ_WRITE,
   353  					}},
   354  				},
   355  			})
   356  			if err != nil {
   357  				return err
   358  			}
   359  			return nil
   360  		},
   361  		func(d sqlx.DBExecutor) error {
   362  			if exists {
   363  				return nil
   364  			}
   365  			pub = &models.Publisher{
   366  				RelProject:   models.RelProject{ProjectID: prj.ProjectID},
   367  				RelPublisher: models.RelPublisher{PublisherID: tok.IdentityID},
   368  				PublisherInfo: models.PublisherInfo{
   369  					Name:  r.Name,
   370  					Key:   r.Key,
   371  					Token: tok.AccessKey,
   372  				},
   373  			}
   374  			if err := pub.Create(d); err != nil {
   375  				if sqlx.DBErr(err).IsConflict() {
   376  					return status.PublisherConflict
   377  				}
   378  				return status.DatabaseError.StatusErr().WithDesc(err.Error())
   379  			}
   380  			return nil
   381  		},
   382  	).Do()
   383  
   384  	if err != nil {
   385  		return nil, err
   386  	}
   387  	metrics.PublisherMetricsInc(ctx, acc.AccountID.String(), prj.Name)
   388  	return pub, nil
   389  }
   390  
   391  func Update(ctx context.Context, r *UpdateReq) error {
   392  	var (
   393  		d = types.MustMgrDBExecutorFromContext(ctx)
   394  		m *models.Publisher
   395  	)
   396  
   397  	// TODO gen publisher token m.Token = "", or not ?
   398  
   399  	return sqlx.NewTasks(d).With(
   400  		func(d sqlx.DBExecutor) error {
   401  			ctx := types.WithMgrDBExecutor(ctx, d)
   402  			var err error
   403  			m, err = GetBySFID(ctx, r.PublisherID)
   404  			return err
   405  		},
   406  		func(d sqlx.DBExecutor) error {
   407  			m.Key = r.Key
   408  			m.Name = r.Name
   409  			if err := m.UpdateByPublisherID(d); err != nil {
   410  				if sqlx.DBErr(err).IsConflict() {
   411  					return status.PublisherConflict
   412  				}
   413  				return status.DatabaseError.StatusErr().WithDesc(err.Error())
   414  			}
   415  			return nil
   416  		},
   417  	).Do()
   418  }