package core import ( "net/http" "github.com/gofrs/uuid/v5" "github.com/knadh/listmonk/models" "github.com/labstack/echo/v4" "github.com/lib/pq" ) // GetLists gets all lists optionally filtered by type. func (c *Core) GetLists(typ string) ([]models.List, error) { out := []models.List{} if err := c.q.GetLists.Select(&out, typ, "id"); err != nil { c.log.Printf("error fetching lists: %v", err) return nil, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.lists}", "error", pqErrMsg(err))) } // Replace null tags. for i, l := range out { if l.Tags == nil { out[i].Tags = []string{} } // Total counts. for _, c := range l.SubscriberCounts { out[i].SubscriberCount += c } } return out, nil } // QueryLists gets multiple lists based on multiple query params. Along with the paginated and sliced // results, the total number of lists in the DB is returned. func (c *Core) QueryLists(searchStr, typ, optin string, tags []string, orderBy, order string, offset, limit int) ([]models.List, int, error) { _ = c.refreshCache(matListSubStats, false) if tags == nil { tags = []string{} } var ( out = []models.List{} queryStr, stmt = makeSearchQuery(searchStr, orderBy, order, c.q.QueryLists, listQuerySortFields) ) if err := c.db.Select(&out, stmt, 0, "", queryStr, typ, optin, pq.StringArray(tags), offset, limit); err != nil { c.log.Printf("error fetching lists: %v", err) return nil, 0, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.lists}", "error", pqErrMsg(err))) } total := 0 if len(out) > 0 { total = out[0].Total // Replace null tags. for i, l := range out { if l.Tags == nil { out[i].Tags = []string{} } // Total counts. for _, c := range l.SubscriberCounts { out[i].SubscriberCount += c } } } return out, total, nil } // GetList gets a list by its ID or UUID. func (c *Core) GetList(id int, uuid string) (models.List, error) { var uu interface{} if uuid != "" { uu = uuid } var res []models.List queryStr, stmt := makeSearchQuery("", "", "", c.q.QueryLists, nil) if err := c.db.Select(&res, stmt, id, uu, queryStr, "", "", pq.StringArray{}, 0, 1); err != nil { c.log.Printf("error fetching lists: %v", err) return models.List{}, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.lists}", "error", pqErrMsg(err))) } if len(res) == 0 { return models.List{}, echo.NewHTTPError(http.StatusBadRequest, c.i18n.Ts("globals.messages.notFound", "name", "{globals.terms.list}")) } out := res[0] if out.Tags == nil { out.Tags = []string{} } // Total counts. for _, c := range out.SubscriberCounts { out.SubscriberCount += c } return out, nil } // GetListsByOptin returns lists by optin type. func (c *Core) GetListsByOptin(ids []int, optinType string) ([]models.List, error) { out := []models.List{} if err := c.q.GetListsByOptin.Select(&out, optinType, pq.Array(ids), nil); err != nil { c.log.Printf("error fetching lists for opt-in: %s", pqErrMsg(err)) return nil, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.list}", "error", pqErrMsg(err))) } return out, nil } // CreateList creates a new list. func (c *Core) CreateList(l models.List) (models.List, error) { uu, err := uuid.NewV4() if err != nil { c.log.Printf("error generating UUID: %v", err) return models.List{}, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorUUID", "error", err.Error())) } if l.Type == "" { l.Type = models.ListTypePrivate } if l.Optin == "" { l.Optin = models.ListOptinSingle } // Insert and read ID. var newID int l.UUID = uu.String() if err := c.q.CreateList.Get(&newID, l.UUID, l.Name, l.Type, l.Optin, pq.StringArray(normalizeTags(l.Tags)), l.Description); err != nil { c.log.Printf("error creating list: %v", err) return models.List{}, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorCreating", "name", "{globals.terms.list}", "error", pqErrMsg(err))) } return c.GetList(newID, "") } // UpdateList updates a given list. func (c *Core) UpdateList(id int, l models.List) (models.List, error) { res, err := c.q.UpdateList.Exec(id, l.Name, l.Type, l.Optin, pq.StringArray(normalizeTags(l.Tags)), l.Description) if err != nil { c.log.Printf("error updating list: %v", err) return models.List{}, echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorUpdating", "name", "{globals.terms.list}", "error", pqErrMsg(err))) } if n, _ := res.RowsAffected(); n == 0 { return models.List{}, echo.NewHTTPError(http.StatusBadRequest, c.i18n.Ts("globals.messages.notFound", "name", "{globals.terms.list}")) } return c.GetList(id, "") } // DeleteList deletes a list. func (c *Core) DeleteList(id int) error { return c.DeleteLists([]int{id}) } // DeleteLists deletes multiple lists. func (c *Core) DeleteLists(ids []int) error { if _, err := c.q.DeleteLists.Exec(pq.Array(ids)); err != nil { c.log.Printf("error deleting lists: %v", err) return echo.NewHTTPError(http.StatusInternalServerError, c.i18n.Ts("globals.messages.errorDeleting", "name", "{globals.terms.list}", "error", pqErrMsg(err))) } return nil }