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 }