package repository import ( "context" "github.com/google/uuid" "github.com/oapi-codegen/nullable" "github.com/phishingclub/phishingclub/database" "github.com/phishingclub/phishingclub/errs" "github.com/phishingclub/phishingclub/model" "github.com/phishingclub/phishingclub/vo" "gorm.io/gorm" ) var apiSenderAllowedColumns = assignTableToColumns(database.API_SENDER_TABLE, []string{ "created_at", "updated_at", "name", }) // APISenderOption is options for preloading type APISenderOption struct { *vo.QueryArgs WithRequestHeaders bool WithResponseHeaders bool WithOAuthProvider bool } // APISender is a API sender repository type APISender struct { DB *gorm.DB } // preload applies the preloading options func (a *APISender) preload(o *APISenderOption, db *gorm.DB) *gorm.DB { if o == nil { return db } if o.WithOAuthProvider { db = db.Preload("OAuthProvider") } return db } // Insert inserts a new API sender func (a *APISender) Insert( ctx context.Context, apiSender *model.APISender, ) (*uuid.UUID, error) { id := uuid.New() row := apiSender.ToDBMap() row["id"] = id AddTimestamps(row) res := a.DB. Model(&database.APISender{}). Create(row) if res.Error != nil { return nil, res.Error } return &id, nil } // GetByID gets a API sender by ID func (a *APISender) GetByID( ctx context.Context, id *uuid.UUID, option *APISenderOption, ) (*model.APISender, error) { db := a.preload(option, a.DB) dbAPISender := &database.APISender{} res := db. Where("id = ?", id). First(&dbAPISender) if res.Error != nil { return nil, res.Error } return ToAPISender(dbAPISender) } // GetAll gets API senders func (a *APISender) GetAll( ctx context.Context, companyID *uuid.UUID, option *APISenderOption, ) (*model.Result[model.APISender], error) { result := model.NewEmptyResult[model.APISender]() db := a.preload(option, a.DB) db = withCompanyIncludingNullContext(db, companyID, database.API_SENDER_TABLE) db, err := useQuery( db, database.API_SENDER_TABLE, option.QueryArgs, apiSenderAllowedColumns..., ) if err != nil { return result, errs.Wrap(err) } dbAPISenders := []*database.APISender{} res := db.Find(&dbAPISenders) if res.Error != nil { return result, res.Error } hasNextPage, err := useHasNextPage( db, database.API_SENDER_TABLE, option.QueryArgs, apiSenderAllowedColumns..., ) if err != nil { return result, errs.Wrap(err) } result.HasNextPage = hasNextPage for _, dbAPISender := range dbAPISenders { apiSender, err := ToAPISender(dbAPISender) if err != nil { return nil, errs.Wrap(err) } result.Rows = append(result.Rows, apiSender) } return result, nil } // GetAllOverview gets API senders with limited data func (a *APISender) GetAllOverview( ctx context.Context, companyID *uuid.UUID, option *APISenderOption, ) (*model.Result[model.APISender], error) { result := model.NewEmptyResult[model.APISender]() db := a.preload(option, a.DB) db = withCompanyIncludingNullContext(db, companyID, database.API_SENDER_TABLE) db, err := useQuery( db, database.API_SENDER_TABLE, option.QueryArgs, apiSenderAllowedColumns..., ) if err != nil { return result, errs.Wrap(err) } dbAPISenders := []*database.APISender{} res := db. Select( TableColumn(database.API_SENDER_TABLE, "id"), TableColumn(database.API_SENDER_TABLE, "name"), ). Find(&dbAPISenders) if res.Error != nil { return result, res.Error } hasNextPage, err := useHasNextPage( db, database.API_SENDER_TABLE, option.QueryArgs, apiSenderAllowedColumns..., ) if err != nil { return result, errs.Wrap(err) } result.HasNextPage = hasNextPage for _, dbAPISender := range dbAPISenders { apiSender, err := ToAPISenderOverview(dbAPISender) if err != nil { return result, errs.Wrap(err) } result.Rows = append(result.Rows, apiSender) } return result, nil } // GetAllByCompanyID gets API senders by company id func (a *APISender) GetAllByCompanyID( ctx context.Context, companyID *uuid.UUID, option *APISenderOption, ) (*model.Result[model.APISender], error) { result := model.NewEmptyResult[model.APISender]() db := a.preload(option, a.DB) db = whereCompany(db, database.API_SENDER_TABLE, companyID) db, err := useQuery( db, database.API_SENDER_TABLE, option.QueryArgs, apiSenderAllowedColumns..., ) if err != nil { return result, errs.Wrap(err) } dbAPISenders := []*database.APISender{} res := db.Find(&dbAPISenders) if res.Error != nil { return result, res.Error } for _, dbAPISender := range dbAPISenders { apiSender, err := ToAPISender(dbAPISender) if err != nil { return result, errs.Wrap(err) } result.Rows = append(result.Rows, apiSender) } return result, nil } // GetByName gets a API sender by name func (a *APISender) GetByName( ctx context.Context, name *vo.String64, companyID *uuid.UUID, option *APISenderOption, ) (*model.APISender, error) { db := a.preload(option, a.DB) db = withCompanyIncludingNullContext(db, companyID, "api_senders") dbAPISender := &database.APISender{} res := db.Where("name = ?", name.String()).First(&dbAPISender) if res.Error != nil { return nil, res.Error } return ToAPISender(dbAPISender) } // UpdateByID updates a API sender by ID func (a *APISender) UpdateByID( ctx context.Context, id *uuid.UUID, ent *model.APISender, ) error { row := ent.ToDBMap() AddUpdatedAt(row) res := a.DB. Model(&database.APISender{}). Where("id = ?", id). Updates(row) if res.Error != nil { return res.Error } return nil } // DeleteByID deletes a API sender by ID func (a *APISender) DeleteByID( ctx context.Context, id *uuid.UUID, ) error { res := a.DB.Where("id = ?", id).Delete(&database.APISender{}) if res.Error != nil { return res.Error } return nil } // ToAPISender converts a API sender database to a model func ToAPISender(row *database.APISender) (*model.APISender, error) { id := nullable.NewNullableWithValue(*row.ID) companyID := nullable.NewNullNullable[uuid.UUID]() if row.CompanyID != nil { companyID.Set(*row.CompanyID) } name := nullable.NewNullableWithValue(*vo.NewString64Must(row.Name)) apiKey := nullable.NewNullNullable[vo.OptionalString255]() if row.APIKey != "" { apiKey.Set(*vo.NewOptionalString255Must(row.APIKey)) } else { apiKey.SetUnspecified() } customField1 := nullable.NewNullableWithValue( *vo.NewOptionalString255Must(row.CustomField1), ) customField2 := nullable.NewNullableWithValue( *vo.NewOptionalString255Must(row.CustomField2), ) customField3 := nullable.NewNullableWithValue( *vo.NewOptionalString255Must(row.CustomField3), ) customField4 := nullable.NewNullableWithValue( *vo.NewOptionalString255Must(row.CustomField4), ) requestMethod := nullable.NewNullableWithValue( *vo.NewHTTPMethodMust(row.RequestMethod), ) requestURL := nullable.NewNullableWithValue( *vo.NewString255Must(row.RequestURL), ) requestHeaders := nullable.NewNullNullable[model.APISenderHeaders]() if row.RequestHeaders != "" { a, err := model.NewAPISenderHeader(row.RequestHeaders) if err != nil { return nil, errs.Wrap(err) } requestHeaders.Set(*a) } else { requestHeaders.SetUnspecified() } requestBody := nullable.NewNullableWithValue(*vo.NewOptionalString1MBMust(row.RequestBody)) expectedResponseStatusCode := nullable.NewNullNullable[int]() if row.ExpectedResponseStatusCode != 0 { expectedResponseStatusCode.Set(row.ExpectedResponseStatusCode) } else { expectedResponseStatusCode.SetNull() } expectedResponseBody := nullable.NewNullableWithValue(*vo.NewOptionalString1MBMust( row.ExpectedResponseBody, )) expectedResponseHeaders := nullable.NewNullNullable[model.APISenderHeaders]() if row.ExpectedResponseHeaders != "" { a, err := model.NewAPISenderHeader(row.ExpectedResponseHeaders) if err != nil { return nil, errs.Wrap(err) } expectedResponseHeaders.Set(*a) } else { expectedResponseHeaders.SetUnspecified() } oauthProviderID := nullable.NewNullNullable[uuid.UUID]() if row.OAuthProviderID != nil { oauthProviderID.Set(*row.OAuthProviderID) } var oauthProvider *model.OAuthProvider if row.OAuthProvider != nil { oauthProvider = ToOAuthProvider(row.OAuthProvider) } return &model.APISender{ ID: id, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt, CompanyID: companyID, Name: name, APIKey: apiKey, CustomField1: customField1, CustomField2: customField2, CustomField3: customField3, CustomField4: customField4, OAuthProviderID: oauthProviderID, OAuthProvider: oauthProvider, RequestMethod: requestMethod, RequestURL: requestURL, RequestHeaders: requestHeaders, RequestBody: requestBody, ExpectedResponseStatusCode: expectedResponseStatusCode, ExpectedResponseBody: expectedResponseBody, ExpectedResponseHeaders: expectedResponseHeaders, }, nil } // ToAPISenderOverview converts a API sender database to a overview model func ToAPISenderOverview(row *database.APISender) (*model.APISender, error) { id := nullable.NewNullableWithValue(*row.ID) companyID := nullable.NewNullNullable[uuid.UUID]() if row.CompanyID != nil { companyID.Set(*row.CompanyID) } name := nullable.NewNullableWithValue(*vo.NewString64Must(row.Name)) return &model.APISender{ ID: id, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt, CompanyID: companyID, Name: name, }, nil }