package resource import ( "context" "net/http" "time" "github.com/Gleipnir-Technology/bob" "github.com/Gleipnir-Technology/bob/dialect/psql" "github.com/Gleipnir-Technology/bob/dialect/psql/sm" "github.com/Gleipnir-Technology/nidus-sync/db" nhttp "github.com/Gleipnir-Technology/nidus-sync/http" "github.com/Gleipnir-Technology/nidus-sync/platform" "github.com/Gleipnir-Technology/nidus-sync/platform/types" //"github.com/aarondl/opt/null" "github.com/gorilla/mux" "github.com/stephenafamo/scan" ) type reviewTaskR struct { router *mux.Router } func ReviewTask(r *mux.Router) *reviewTaskR { return &reviewTaskR{ router: r, } } type reviewTask struct { Address types.Address `json:"address"` Created time.Time `json:"created"` Creator platform.User `json:"creator"` ID int32 `json:"id"` Pool reviewTaskPool `json:"pool"` Reviewed *time.Time `json:"addressed"` Reviewer *platform.User `json:"addressor"` } type reviewTaskPool struct { Condition string `json:"condition"` Location types.Location `json:"location"` Site types.Site `json:"site"` } type contentListReviewTask struct { Tasks []reviewTask `json:"tasks"` Total int32 `json:"total"` } func (res *reviewTaskR) List(ctx context.Context, r *http.Request, user platform.User, query QueryParams) (*contentListReviewTask, *nhttp.ErrorWithStatus) { limit := 20 if query.Limit != nil { limit = *query.Limit } type _RowTotal struct { Total int32 `db:"total"` } row_total, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select( sm.Columns( "COUNT(*) AS total", ), sm.From("review_task"), sm.Where(psql.Quote("review_task", "organization_id").EQ(psql.Arg(user.Organization.ID))), sm.Where(psql.Quote("review_task", "reviewed").IsNull()), ), scan.StructMapper[_RowTotal]()) if err != nil { return nil, nhttp.NewError("failed to total count: %w", err) } type _Row struct { Address types.Address `db:"address"` Condition string `db:"condition"` Created time.Time `db:"created"` CreatorID int32 `db:"creator_id"` ID int32 `db:"id"` Latitude float64 `db:"latitude"` Longitude float64 `db:"longitude"` Reviewed *time.Time `db:"reviewed"` ReviewerID *int32 `db:"reviewer_id"` SiteID int32 `db:"site_id"` Title string `db:"title"` Type string `db:"type"` } rows, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select( sm.Columns( "feature_pool.condition AS condition", "review_task.created AS created", "review_task.creator_id AS creator_id", "review_task.id AS id", "review_task.reviewed AS reviewed", "review_task.reviewer_id AS reviewer_id", "address.country AS \"address.country\"", "address.locality AS \"address.locality\"", "address.number_ AS \"address.number_\"", "address.postal_code AS \"address.postal_code\"", "address.region AS \"address.region\"", "address.street AS \"address.street\"", "address.unit AS \"address.unit\"", "ST_Y(address.location) AS latitude", "ST_X(address.location) AS longitude", "site.id AS site_id", ), sm.From("review_task_pool"), sm.InnerJoin("feature_pool").OnEQ( psql.Quote("review_task_pool", "feature_pool_id"), psql.Quote("feature_pool", "feature_id"), ), sm.InnerJoin("review_task").OnEQ( psql.Quote("review_task_pool", "review_task_id"), psql.Quote("review_task", "id"), ), sm.InnerJoin("feature").OnEQ( psql.Quote("feature_pool", "feature_id"), psql.Quote("feature", "id"), ), sm.InnerJoin("site").On( psql.Quote("feature", "site_id").EQ(psql.Quote("site", "id")), ), sm.InnerJoin("address").OnEQ( psql.Quote("site", "address_id"), psql.Quote("address", "id"), ), sm.Where(psql.Quote("review_task", "organization_id").EQ(psql.Arg(user.Organization.ID))), sm.Where(psql.Quote("review_task", "reviewed").IsNull()), sm.Limit(limit), ), scan.StructMapper[_Row]()) if err != nil { return nil, nhttp.NewError("failed to get review tasks: %w", err) } users_by_id, err := platform.UsersByOrg(ctx, user.Organization) if err != nil { return nil, nhttp.NewError("users by id: %w", err) } site_ids := make([]int32, len(rows)) for i, row := range rows { site_ids[i] = row.SiteID } sites_by_id, err := platform.SitesByID(ctx, site_ids) if err != nil { return nil, nhttp.NewError("sites by id: %w", err) } tasks := make([]reviewTask, len(rows)) for i, row := range rows { site, ok := sites_by_id[row.SiteID] if !ok { return nil, nhttp.NewError("no site %d", row.SiteID) } tasks[i] = reviewTask{ Address: row.Address, Created: row.Created, Creator: *users_by_id[row.CreatorID], ID: row.ID, Pool: reviewTaskPool{ Condition: row.Condition, Location: types.Location{ Latitude: row.Latitude, Longitude: row.Longitude, }, Site: types.SiteFromModel(site), }, Reviewed: row.Reviewed, Reviewer: userOrNil(users_by_id, row.ReviewerID), } } return &contentListReviewTask{ Tasks: tasks, Total: row_total.Total, }, nil } func userOrNil(usersByID map[int32]*platform.User, id *int32) *platform.User { if id == nil { return nil } u, ok := usersByID[*id] if !ok { return nil } return u }