Refactor API of /api/v2/users/{uid}/subscriptions
This commit is contained in:
parent
8a6719fc19
commit
165c6d8614
@ -13,6 +13,10 @@
|
||||
- increase max body size (smth like 2MB?)
|
||||
(also increase cronexec char limit)
|
||||
|
||||
- use goext.ginWrapper
|
||||
|
||||
- use goext.exerr
|
||||
|
||||
#### UNSURE
|
||||
|
||||
- (?) default-priority for channels
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
@ -146,7 +147,7 @@ func (h APIHandler) GetChannel(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
channel, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID, true)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -206,7 +207,7 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, u.UserID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 400, apierr.USER_NOT_FOUND, "User not found", nil)
|
||||
}
|
||||
if err != nil {
|
||||
@ -298,7 +299,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
_, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID, true)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -306,7 +307,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, u.UserID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 400, apierr.USER_NOT_FOUND, "User not found", nil)
|
||||
}
|
||||
if err != nil {
|
||||
@ -420,7 +421,7 @@ func (h APIHandler) ListChannelMessages(g *gin.Context) ginresp.HTTPResponse {
|
||||
pageSize := mathext.Clamp(langext.Coalesce(q.PageSize, 64), 1, maxPageSize)
|
||||
|
||||
channel, err := h.database.GetChannel(ctx, u.ChannelUserID, u.ChannelID, false)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"net/http"
|
||||
@ -87,7 +88,7 @@ func (h APIHandler) GetClient(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
client, err := h.database.GetClient(ctx, u.UserID, u.ClientID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CLIENT_NOT_FOUND, "Client not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -192,7 +193,7 @@ func (h APIHandler) DeleteClient(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
client, err := h.database.GetClient(ctx, u.UserID, u.ClientID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CLIENT_NOT_FOUND, "Client not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -251,7 +252,7 @@ func (h APIHandler) UpdateClient(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
client, err := h.database.GetClient(ctx, u.UserID, u.ClientID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CLIENT_NOT_FOUND, "Client not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"net/http"
|
||||
@ -90,7 +91,7 @@ func (h APIHandler) GetUserKey(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytoken, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -143,7 +144,7 @@ func (h APIHandler) UpdateUserKey(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytoken, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -302,7 +303,7 @@ func (h APIHandler) DeleteUserKey(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
client, err := h.database.GetKeyToken(ctx, u.UserID, u.KeyID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
|
||||
@ -191,7 +192,7 @@ func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
msg, err := h.database.GetMessage(ctx, u.MessageID, false)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.MESSAGE_NOT_FOUND, "message not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -259,7 +260,7 @@ func (h APIHandler) DeleteMessage(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
msg, err := h.database.GetMessage(ctx, u.MessageID, false)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.MESSAGE_NOT_FOUND, "message not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"net/http"
|
||||
@ -14,13 +15,25 @@ import (
|
||||
// ListUserSubscriptions swaggerdoc
|
||||
//
|
||||
// @Summary List all subscriptions of a user (incoming/owned)
|
||||
// @Description The possible values for 'selector' are:
|
||||
// @Description - "outgoing_all" All subscriptions (confirmed/unconfirmed) with the user as subscriber (= subscriptions he can use to read channels)
|
||||
// @Description - "outgoing_confirmed" Confirmed subscriptions with the user as subscriber
|
||||
// @Description - "outgoing_unconfirmed" Unconfirmed (Pending) subscriptions with the user as subscriber
|
||||
// @Description - "incoming_all" All subscriptions (confirmed/unconfirmed) from other users to channels of this user (= incoming subscriptions and subscription requests)
|
||||
// @Description - "incoming_confirmed" Confirmed subscriptions from other users to channels of this user
|
||||
// @Description - "incoming_unconfirmed" Unconfirmed subscriptions from other users to channels of this user (= requests)
|
||||
//
|
||||
// @Description The possible values for 'direction' are:
|
||||
// @Description - "outgoing" Subscriptions with the user as subscriber (= subscriptions he can use to read channels)
|
||||
// @Description - "incoming" Subscriptions to channels of this user (= incoming subscriptions and subscription requests)
|
||||
// @Description - "both" Combines "outgoing" and "incoming" (default)
|
||||
// @Description
|
||||
// @Description The possible values for 'confirmation' are:
|
||||
// @Description - "confirmed" Confirmed (active) subscriptions
|
||||
// @Description - "unconfirmed" Unconfirmed (pending) subscriptions
|
||||
// @Description - "all" Combines "confirmed" and "unconfirmed" (default)
|
||||
// @Description
|
||||
// @Description The possible values for 'external' are:
|
||||
// @Description - "true" Subscriptions with subscriber_user_id != channel_owner_user_id (subscriptions from other users)
|
||||
// @Description - "false" Subscriptions with subscriber_user_id == channel_owner_user_id (subscriptions from this user to his own channels)
|
||||
// @Description - "all" Combines "external" and "internal" (default)
|
||||
// @Description
|
||||
// @Description The `subscriber_user_id` parameter can be used to additionally filter the subscriber_user_id (return subscribtions from a specific user)
|
||||
// @Description
|
||||
// @Description The `channel_owner_user_id` parameter can be used to additionally filter the channel_owner_user_id (return subscribtions to a specific user)
|
||||
//
|
||||
// @ID api-user-subscriptions-list
|
||||
// @Tags API-v2
|
||||
@ -39,7 +52,11 @@ func (h APIHandler) ListUserSubscriptions(g *gin.Context) ginresp.HTTPResponse {
|
||||
UserID models.UserID `uri:"uid" binding:"entityid"`
|
||||
}
|
||||
type query struct {
|
||||
Selector *string `json:"selector" form:"selector" enums:"outgoing_all,outgoing_confirmed,outgoing_unconfirmed,incoming_all,incoming_confirmed,incoming_unconfirmed"`
|
||||
Direction *string `json:"direction" form:"direction" enums:"incoming,outgoing,both"`
|
||||
Confirmation *string `json:"confirmation" form:"confirmation" enums:"confirmed,unconfirmed,all"`
|
||||
External *string `json:"external" form:"external" enums:"true,false,all"`
|
||||
SubscriberUserID *models.UserID `json:"subscriber_user_id" form:"subscriber_user_id"`
|
||||
ChannelOwnerUserID *models.UserID `json:"channel_owner_user_id" form:"channel_owner_user_id"`
|
||||
}
|
||||
type response struct {
|
||||
Subscriptions []models.SubscriptionJSON `json:"subscriptions"`
|
||||
@ -57,57 +74,56 @@ func (h APIHandler) ListUserSubscriptions(g *gin.Context) ginresp.HTTPResponse {
|
||||
return *permResp
|
||||
}
|
||||
|
||||
sel := strings.ToLower(langext.Coalesce(q.Selector, "outgoing_all"))
|
||||
|
||||
var res []models.Subscription
|
||||
var err error
|
||||
|
||||
if sel == "outgoing_all" {
|
||||
|
||||
res, err = h.database.ListSubscriptionsBySubscriber(ctx, u.UserID, nil)
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
|
||||
} else if sel == "outgoing_confirmed" {
|
||||
|
||||
res, err = h.database.ListSubscriptionsBySubscriber(ctx, u.UserID, langext.Ptr(true))
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
|
||||
} else if sel == "outgoing_unconfirmed" {
|
||||
|
||||
res, err = h.database.ListSubscriptionsBySubscriber(ctx, u.UserID, langext.Ptr(false))
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
|
||||
} else if sel == "incoming_all" {
|
||||
|
||||
res, err = h.database.ListSubscriptionsByChannelOwner(ctx, u.UserID, nil)
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
|
||||
} else if sel == "incoming_confirmed" {
|
||||
|
||||
res, err = h.database.ListSubscriptionsByChannelOwner(ctx, u.UserID, langext.Ptr(true))
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
|
||||
} else if sel == "incoming_unconfirmed" {
|
||||
|
||||
res, err = h.database.ListSubscriptionsByChannelOwner(ctx, u.UserID, langext.Ptr(false))
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
filter := models.SubscriptionFilter{}
|
||||
filter.AnyUserID = langext.Ptr(u.UserID)
|
||||
|
||||
if q.Direction != nil {
|
||||
if strings.EqualFold(*q.Direction, "incoming") {
|
||||
filter.ChannelOwnerUserID = langext.Ptr([]models.UserID{u.UserID})
|
||||
} else if strings.EqualFold(*q.Direction, "outgoing") {
|
||||
filter.SubscriberUserID = langext.Ptr([]models.UserID{u.UserID})
|
||||
} else if strings.EqualFold(*q.Direction, "both") {
|
||||
// both
|
||||
} else {
|
||||
return ginresp.APIError(g, 400, apierr.BINDFAIL_QUERY_PARAM, "Invalid value for param 'direction'", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return ginresp.APIError(g, 400, apierr.INVALID_ENUM_VALUE, "Invalid value for the [selector] parameter", nil)
|
||||
if q.Confirmation != nil {
|
||||
if strings.EqualFold(*q.Confirmation, "confirmed") {
|
||||
filter.Confirmed = langext.PTrue
|
||||
} else if strings.EqualFold(*q.Confirmation, "unconfirmed") {
|
||||
filter.Confirmed = langext.PFalse
|
||||
} else if strings.EqualFold(*q.Confirmation, "all") {
|
||||
// both
|
||||
} else {
|
||||
return ginresp.APIError(g, 400, apierr.BINDFAIL_QUERY_PARAM, "Invalid value for param 'confirmation'", nil)
|
||||
}
|
||||
}
|
||||
|
||||
if q.External != nil {
|
||||
if strings.EqualFold(*q.External, "true") {
|
||||
filter.SubscriberIsChannelOwner = langext.PFalse
|
||||
} else if strings.EqualFold(*q.External, "false") {
|
||||
filter.SubscriberIsChannelOwner = langext.PTrue
|
||||
} else if strings.EqualFold(*q.External, "all") {
|
||||
// both
|
||||
} else {
|
||||
return ginresp.APIError(g, 400, apierr.BINDFAIL_QUERY_PARAM, "Invalid value for param 'external'", nil)
|
||||
}
|
||||
}
|
||||
|
||||
if q.SubscriberUserID != nil {
|
||||
filter.SubscriberUserID2 = langext.Ptr([]models.UserID{*q.SubscriberUserID})
|
||||
}
|
||||
|
||||
if q.ChannelOwnerUserID != nil {
|
||||
filter.ChannelOwnerUserID2 = langext.Ptr([]models.UserID{*q.ChannelOwnerUserID})
|
||||
}
|
||||
|
||||
res, err := h.database.ListSubscriptions(ctx, filter)
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
|
||||
jsonres := langext.ArrMap(res, func(v models.Subscription) models.SubscriptionJSON { return v.JSON() })
|
||||
@ -152,14 +168,14 @@ func (h APIHandler) ListChannelSubscriptions(g *gin.Context) ginresp.HTTPRespons
|
||||
}
|
||||
|
||||
_, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID, true)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
||||
}
|
||||
|
||||
clients, err := h.database.ListSubscriptionsByChannel(ctx, u.ChannelID)
|
||||
clients, err := h.database.ListSubscriptions(ctx, models.SubscriptionFilter{AnyUserID: langext.Ptr(u.UserID), ChannelID: langext.Ptr([]models.ChannelID{u.ChannelID})})
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscriptions", err)
|
||||
}
|
||||
@ -203,7 +219,7 @@ func (h APIHandler) GetSubscription(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
subscription, err := h.database.GetSubscription(ctx, u.SubscriptionID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.SUBSCRIPTION_NOT_FOUND, "Subscription not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -250,7 +266,7 @@ func (h APIHandler) CancelSubscription(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
subscription, err := h.database.GetSubscription(ctx, u.SubscriptionID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.SUBSCRIPTION_NOT_FOUND, "Subscription not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
@ -414,7 +430,7 @@ func (h APIHandler) UpdateSubscription(g *gin.Context) ginresp.HTTPResponse {
|
||||
userid := *ctx.GetPermissionUserID()
|
||||
|
||||
subscription, err := h.database.GetSubscription(ctx, u.SubscriptionID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.SUBSCRIPTION_NOT_FOUND, "Subscription not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -167,7 +168,7 @@ func (h APIHandler) GetUser(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, u.UserID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.APIError(g, 404, apierr.USER_NOT_FOUND, "User not found", err)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
||||
@ -287,7 +288,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(201, "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -295,7 +296,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
if err != nil {
|
||||
@ -395,7 +396,7 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(201, "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -403,7 +404,7 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
if err != nil {
|
||||
@ -497,7 +498,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(201, "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -505,7 +506,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
if err != nil {
|
||||
@ -614,7 +615,7 @@ func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(201, "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -622,7 +623,7 @@ func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
if err != nil {
|
||||
@ -744,7 +745,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(201, "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -752,7 +753,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
if err != nil {
|
||||
@ -771,7 +772,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
msg, err := h.database.GetMessage(ctx, models.MessageID(*messageCompNew), false)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(301, "Message not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -863,7 +864,7 @@ func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(201, "User not found")
|
||||
}
|
||||
if err != nil {
|
||||
@ -871,7 +872,7 @@ func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
|
||||
}
|
||||
|
||||
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -139,7 +140,7 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
||||
}
|
||||
|
||||
user, err := h.database.GetUser(ctx, *UserID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 400, apierr.USER_NOT_FOUND, hl.USER_ID, "User not found", err))
|
||||
}
|
||||
if err != nil {
|
||||
@ -244,7 +245,8 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create compat-id", err))
|
||||
}
|
||||
|
||||
subscriptions, err := h.database.ListSubscriptionsByChannel(ctx, channel.ChannelID)
|
||||
subFilter := models.SubscriptionFilter{ChannelID: langext.Ptr([]models.ChannelID{channel.ChannelID}), Confirmed: langext.PTrue}
|
||||
activeSubscriptions, err := h.database.ListSubscriptions(ctx, subFilter)
|
||||
if err != nil {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query subscriptions", err))
|
||||
}
|
||||
@ -266,16 +268,12 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
||||
|
||||
log.Info().Msg(fmt.Sprintf("Sending new notification %s for user %s", msg.MessageID, UserID))
|
||||
|
||||
for _, sub := range subscriptions {
|
||||
for _, sub := range activeSubscriptions {
|
||||
clients, err := h.database.ListClients(ctx, sub.SubscriberUserID)
|
||||
if err != nil {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query clients", err))
|
||||
}
|
||||
|
||||
if !sub.Confirmed {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, client := range clients {
|
||||
|
||||
isCompatClient, err := h.database.IsCompatClient(ctx, client.ClientID)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/db"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
"time"
|
||||
)
|
||||
@ -23,7 +24,7 @@ func (db *Database) GetChannelByName(ctx db.TxContext, userid models.UserID, cha
|
||||
}
|
||||
|
||||
channel, err := models.DecodeChannel(rows)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
@ -47,7 +48,7 @@ func (db *Database) GetChannelByID(ctx db.TxContext, chanid models.ChannelID) (*
|
||||
}
|
||||
|
||||
channel, err := models.DecodeChannel(rows)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -63,7 +63,7 @@ func (db *Database) ConvertCompatID(ctx db.TxContext, oldid int64, idtype string
|
||||
|
||||
var newid string
|
||||
err = rows.Scan(&newid)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
@ -91,7 +91,7 @@ func (db *Database) ConvertToCompatID(ctx db.TxContext, newid string) (*int64, *
|
||||
var oldid int64
|
||||
var idtype string
|
||||
err = rows.Scan(&oldid, &idtype)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/db"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
"strings"
|
||||
@ -90,7 +91,7 @@ func (db *Database) GetKeyTokenByToken(ctx db.TxContext, key string) (*models.Ke
|
||||
}
|
||||
|
||||
user, err := models.DecodeKeyToken(rows)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -22,7 +22,7 @@ func (db *Database) GetMessageByUserMessageID(ctx db.TxContext, usrMsgId string)
|
||||
}
|
||||
|
||||
msg, err := models.DecodeMessage(rows)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/db"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
"time"
|
||||
)
|
||||
@ -32,71 +33,19 @@ func (db *Database) CreateSubscription(ctx db.TxContext, subscriberUID models.Us
|
||||
return entity.Model(), nil
|
||||
}
|
||||
|
||||
func (db *Database) ListSubscriptionsByChannel(ctx db.TxContext, channelID models.ChannelID) ([]models.Subscription, error) {
|
||||
func (db *Database) ListSubscriptions(ctx db.TxContext, filter models.SubscriptionFilter) ([]models.Subscription, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
order := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
filterCond, filterJoin, prepParams, err := filter.SQL()
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE channel_id = :cid"+order, sq.PP{"cid": channelID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderClause := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
data, err := models.DecodeSubscriptions(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sqlQuery := "SELECT " + "subscriptions.*" + " FROM subscriptions " + filterJoin + " WHERE ( " + filterCond + " ) " + orderClause
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (db *Database) ListSubscriptionsByChannelOwner(ctx db.TxContext, ownerUserID models.UserID, confirmed *bool) ([]models.Subscription, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cond := ""
|
||||
if confirmed != nil && *confirmed {
|
||||
cond = " AND confirmed = 1"
|
||||
} else if confirmed != nil && !*confirmed {
|
||||
cond = " AND confirmed = 0"
|
||||
}
|
||||
|
||||
order := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE channel_owner_user_id = :ouid"+cond+order, sq.PP{"ouid": ownerUserID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := models.DecodeSubscriptions(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (db *Database) ListSubscriptionsBySubscriber(ctx db.TxContext, subscriberUserID models.UserID, confirmed *bool) ([]models.Subscription, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cond := ""
|
||||
if confirmed != nil && *confirmed {
|
||||
cond = " AND confirmed = 1"
|
||||
} else if confirmed != nil && !*confirmed {
|
||||
cond = " AND confirmed = 0"
|
||||
}
|
||||
|
||||
order := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE subscriber_user_id = :suid"+cond+order, sq.PP{"suid": subscriberUserID})
|
||||
rows, err := tx.Query(ctx, sqlQuery, prepParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -143,7 +92,7 @@ func (db *Database) GetSubscriptionBySubscriber(ctx db.TxContext, subscriberId m
|
||||
}
|
||||
|
||||
user, err := models.DecodeSubscription(rows)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
)
|
||||
|
||||
@ -43,7 +44,7 @@ func (ac *AppContext) CheckPermissionChanMessagesRead(channel models.Channel) *g
|
||||
return nil // owned channel
|
||||
} else {
|
||||
sub, err := ac.app.Database.Primary.GetSubscriptionBySubscriber(ac, p.Token.OwnerUserID, channel.ChannelID)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return langext.Ptr(ginresp.APIError(ac.ginContext, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil))
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -4,7 +4,7 @@ package models
|
||||
|
||||
import "gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
|
||||
const ChecksumGenerator = "a1a684aa30d77d9a9936ccbb667b498c370a1f816273e9cd93948f4195155e90"
|
||||
const ChecksumGenerator = "a41b8d265c326a65d7be07c74aa2318064c6307256bd92b684c5adb4a8f82d97"
|
||||
|
||||
type Enum interface {
|
||||
Valid() bool
|
||||
|
@ -159,7 +159,7 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) {
|
||||
|
||||
if f.TimestampRealBefore != nil {
|
||||
sqlClauses = append(sqlClauses, "(timestamp_real < :ts_real_before)")
|
||||
params["ts_real_before"] = (*f.TimestampRealAfter).UnixMilli()
|
||||
params["ts_real_before"] = (*f.TimestampRealBefore).UnixMilli()
|
||||
}
|
||||
|
||||
if f.TimestampClient != nil {
|
||||
|
136
scnserver/models/subscriptionfilter.go
Normal file
136
scnserver/models/subscriptionfilter.go
Normal file
@ -0,0 +1,136 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SubscriptionFilter struct {
|
||||
AnyUserID *UserID
|
||||
SubscriberUserID *[]UserID
|
||||
SubscriberUserID2 *[]UserID // Used to filter <SubscriberUserID> again
|
||||
ChannelOwnerUserID *[]UserID
|
||||
ChannelOwnerUserID2 *[]UserID // Used to filter <ChannelOwnerUserID> again
|
||||
ChannelID *[]ChannelID
|
||||
Confirmed *bool
|
||||
SubscriberIsChannelOwner *bool
|
||||
Timestamp *time.Time
|
||||
TimestampAfter *time.Time
|
||||
TimestampBefore *time.Time
|
||||
}
|
||||
|
||||
func (f SubscriptionFilter) SQL() (string, string, sq.PP, error) {
|
||||
|
||||
joinClause := ""
|
||||
|
||||
sqlClauses := make([]string, 0)
|
||||
|
||||
params := sq.PP{}
|
||||
|
||||
if f.AnyUserID != nil {
|
||||
sqlClauses = append(sqlClauses, "(subscriber_user_id = :anyuid1 OR channel_owner_user_id = :anyuid2)")
|
||||
params["anyuid1"] = *f.AnyUserID
|
||||
params["anyuid2"] = *f.AnyUserID
|
||||
}
|
||||
|
||||
if f.SubscriberUserID != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.SubscriberUserID {
|
||||
filter = append(filter, fmt.Sprintf("(subscriber_user_id = :subscriber_uid_1_%d)", i))
|
||||
params[fmt.Sprintf("subscriber_uid_1_%d", i)] = v
|
||||
}
|
||||
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
|
||||
}
|
||||
|
||||
if f.SubscriberUserID2 != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.SubscriberUserID2 {
|
||||
filter = append(filter, fmt.Sprintf("(subscriber_user_id = :subscriber_uid_2_%d)", i))
|
||||
params[fmt.Sprintf("subscriber_uid_2_%d", i)] = v
|
||||
}
|
||||
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
|
||||
}
|
||||
|
||||
if f.ChannelOwnerUserID != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.ChannelOwnerUserID {
|
||||
filter = append(filter, fmt.Sprintf("(channel_owner_user_id = :chanowner_uid_1_%d)", i))
|
||||
params[fmt.Sprintf("chanowner_uid_1_%d", i)] = v
|
||||
}
|
||||
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
|
||||
}
|
||||
|
||||
if f.ChannelOwnerUserID2 != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.ChannelOwnerUserID2 {
|
||||
filter = append(filter, fmt.Sprintf("(channel_owner_user_id = :chanowner_uid_2_%d)", i))
|
||||
params[fmt.Sprintf("chanowner_uid_2_%d", i)] = v
|
||||
}
|
||||
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
|
||||
}
|
||||
|
||||
if f.ChannelID != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.ChannelID {
|
||||
filter = append(filter, fmt.Sprintf("(channel_id = :chanid_%d)", i))
|
||||
params[fmt.Sprintf("chanid_%d", i)] = v
|
||||
}
|
||||
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
|
||||
}
|
||||
|
||||
if f.Confirmed != nil {
|
||||
if *f.Confirmed {
|
||||
sqlClauses = append(sqlClauses, "(confirmed=1)")
|
||||
} else {
|
||||
sqlClauses = append(sqlClauses, "(confirmed=0)")
|
||||
}
|
||||
}
|
||||
|
||||
if f.SubscriberIsChannelOwner != nil {
|
||||
if *f.SubscriberIsChannelOwner {
|
||||
sqlClauses = append(sqlClauses, "(subscriber_user_id = channel_owner_user_id)")
|
||||
} else {
|
||||
sqlClauses = append(sqlClauses, "(subscriber_user_id != channel_owner_user_id)")
|
||||
}
|
||||
}
|
||||
|
||||
if f.Timestamp != nil {
|
||||
sqlClauses = append(sqlClauses, "(timestamp_created = :ts_equals)")
|
||||
params["ts_equals"] = (*f.Timestamp).UnixMilli()
|
||||
}
|
||||
|
||||
if f.TimestampAfter != nil {
|
||||
sqlClauses = append(sqlClauses, "(timestamp_created > :ts_after)")
|
||||
params["ts_after"] = (*f.TimestampAfter).UnixMilli()
|
||||
}
|
||||
|
||||
if f.TimestampBefore != nil {
|
||||
sqlClauses = append(sqlClauses, "(timestamp_created < :ts_before)")
|
||||
params["ts_before"] = (*f.TimestampBefore).UnixMilli()
|
||||
}
|
||||
|
||||
sqlClause := ""
|
||||
if len(sqlClauses) > 0 {
|
||||
sqlClause = strings.Join(sqlClauses, " AND ")
|
||||
} else {
|
||||
sqlClause = "1=1"
|
||||
}
|
||||
|
||||
return sqlClause, joinClause, params, nil
|
||||
}
|
||||
|
||||
func (f SubscriptionFilter) Hash() string {
|
||||
bh, err := dataext.StructHash(f, dataext.StructHashOptions{HashAlgo: sha512.New()})
|
||||
if err != nil {
|
||||
return "00000000"
|
||||
}
|
||||
|
||||
str := hex.EncodeToString(bh)
|
||||
return str[0:mathext.Min(8, len(bh))]
|
||||
}
|
@ -2160,7 +2160,7 @@
|
||||
},
|
||||
"/api/v2/users/{uid}/subscriptions": {
|
||||
"get": {
|
||||
"description": "The possible values for 'selector' are:\n- \"outgoing_all\" All subscriptions (confirmed/unconfirmed) with the user as subscriber (= subscriptions he can use to read channels)\n- \"outgoing_confirmed\" Confirmed subscriptions with the user as subscriber\n- \"outgoing_unconfirmed\" Unconfirmed (Pending) subscriptions with the user as subscriber\n- \"incoming_all\" All subscriptions (confirmed/unconfirmed) from other users to channels of this user (= incoming subscriptions and subscription requests)\n- \"incoming_confirmed\" Confirmed subscriptions from other users to channels of this user\n- \"incoming_unconfirmed\" Unconfirmed subscriptions from other users to channels of this user (= requests)",
|
||||
"description": "The possible values for 'direction' are:\n- \"outgoing\" Subscriptions with the user as subscriber (= subscriptions he can use to read channels)\n- \"incoming\" Subscriptions to channels of this user (= incoming subscriptions and subscription requests)\n- \"both\" Combines \"outgoing\" and \"incoming\" (default)\n\nThe possible values for 'confirmation' are:\n- \"confirmed\" Confirmed (active) subscriptions\n- \"unconfirmed\" Unconfirmed (pending) subscriptions\n- \"all\" Combines \"confirmed\" and \"unconfirmed\" (default)\n\nThe possible values for 'external' are:\n- \"true\" Subscriptions with subscriber_user_id != channel_owner_user_id (subscriptions from other users)\n- \"false\" Subscriptions with subscriber_user_id == channel_owner_user_id (subscriptions from this user to his own channels)\n- \"all\" Combines \"external\" and \"internal\" (default)\n\nThe `subscriber_user_id` parameter can be used to additionally filter the subscriber_user_id (return subscribtions from a specific user)\n\nThe `channel_owner_user_id` parameter can be used to additionally filter the channel_owner_user_id (return subscribtions to a specific user)",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
|
@ -2149,13 +2149,24 @@ paths:
|
||||
/api/v2/users/{uid}/subscriptions:
|
||||
get:
|
||||
description: |-
|
||||
The possible values for 'selector' are:
|
||||
- "outgoing_all" All subscriptions (confirmed/unconfirmed) with the user as subscriber (= subscriptions he can use to read channels)
|
||||
- "outgoing_confirmed" Confirmed subscriptions with the user as subscriber
|
||||
- "outgoing_unconfirmed" Unconfirmed (Pending) subscriptions with the user as subscriber
|
||||
- "incoming_all" All subscriptions (confirmed/unconfirmed) from other users to channels of this user (= incoming subscriptions and subscription requests)
|
||||
- "incoming_confirmed" Confirmed subscriptions from other users to channels of this user
|
||||
- "incoming_unconfirmed" Unconfirmed subscriptions from other users to channels of this user (= requests)
|
||||
The possible values for 'direction' are:
|
||||
- "outgoing" Subscriptions with the user as subscriber (= subscriptions he can use to read channels)
|
||||
- "incoming" Subscriptions to channels of this user (= incoming subscriptions and subscription requests)
|
||||
- "both" Combines "outgoing" and "incoming" (default)
|
||||
|
||||
The possible values for 'confirmation' are:
|
||||
- "confirmed" Confirmed (active) subscriptions
|
||||
- "unconfirmed" Unconfirmed (pending) subscriptions
|
||||
- "all" Combines "confirmed" and "unconfirmed" (default)
|
||||
|
||||
The possible values for 'external' are:
|
||||
- "true" Subscriptions with subscriber_user_id != channel_owner_user_id (subscriptions from other users)
|
||||
- "false" Subscriptions with subscriber_user_id == channel_owner_user_id (subscriptions from this user to his own channels)
|
||||
- "all" Combines "external" and "internal" (default)
|
||||
|
||||
The `subscriber_user_id` parameter can be used to additionally filter the subscriber_user_id (return subscribtions from a specific user)
|
||||
|
||||
The `channel_owner_user_id` parameter can be used to additionally filter the channel_owner_user_id (return subscribtions to a specific user)
|
||||
operationId: api-user-subscriptions-list
|
||||
parameters:
|
||||
- description: UserID
|
||||
|
@ -687,40 +687,40 @@ func TestListChannelSubscriptions(t *testing.T) {
|
||||
}
|
||||
|
||||
countBoth := func(oa1, oc1, ou1, ia1, ic1, iu1, oa2, oc2, ou2, ia2, ic2, iu2 int) {
|
||||
sublist1oa := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data1.UID, "outgoing_all"))
|
||||
sublist1oa := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data1.UID, "outgoing", "all"))
|
||||
tt.AssertEqual(t, "1:outgoing_all", oa1, len(sublist1oa.Subscriptions))
|
||||
|
||||
sublist1oc := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data1.UID, "outgoing_confirmed"))
|
||||
sublist1oc := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data1.UID, "outgoing", "confirmed"))
|
||||
tt.AssertEqual(t, "1:outgoing_confirmed", oc1, len(sublist1oc.Subscriptions))
|
||||
|
||||
sublist1ou := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data1.UID, "outgoing_unconfirmed"))
|
||||
sublist1ou := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data1.UID, "outgoing", "unconfirmed"))
|
||||
tt.AssertEqual(t, "1:outgoing_unconfirmed", ou1, len(sublist1ou.Subscriptions))
|
||||
|
||||
sublist1ia := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data1.UID, "incoming_all"))
|
||||
sublist1ia := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data1.UID, "incoming", "all"))
|
||||
tt.AssertEqual(t, "1:incoming_all", ia1, len(sublist1ia.Subscriptions))
|
||||
|
||||
sublist1ic := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data1.UID, "incoming_confirmed"))
|
||||
sublist1ic := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data1.UID, "incoming", "confirmed"))
|
||||
tt.AssertEqual(t, "1:incoming_confirmed", ic1, len(sublist1ic.Subscriptions))
|
||||
|
||||
sublist1iu := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data1.UID, "incoming_unconfirmed"))
|
||||
sublist1iu := tt.RequestAuthGet[sublist](t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data1.UID, "incoming", "unconfirmed"))
|
||||
tt.AssertEqual(t, "1:incoming_unconfirmed", iu1, len(sublist1iu.Subscriptions))
|
||||
|
||||
sublist2oa := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "outgoing_all"))
|
||||
sublist2oa := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "outgoing", "all"))
|
||||
tt.AssertEqual(t, "2:outgoing_all", oa2, len(sublist2oa.Subscriptions))
|
||||
|
||||
sublist2oc := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "outgoing_confirmed"))
|
||||
sublist2oc := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "outgoing", "confirmed"))
|
||||
tt.AssertEqual(t, "2:outgoing_confirmed", oc2, len(sublist2oc.Subscriptions))
|
||||
|
||||
sublist2ou := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "outgoing_unconfirmed"))
|
||||
sublist2ou := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "outgoing", "unconfirmed"))
|
||||
tt.AssertEqual(t, "2:outgoing_unconfirmed", ou2, len(sublist2ou.Subscriptions))
|
||||
|
||||
sublist2ia := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "incoming_all"))
|
||||
sublist2ia := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "incoming", "all"))
|
||||
tt.AssertEqual(t, "2:incoming_all", ia2, len(sublist2ia.Subscriptions))
|
||||
|
||||
sublist2ic := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "incoming_confirmed"))
|
||||
sublist2ic := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "incoming", "confirmed"))
|
||||
tt.AssertEqual(t, "2:incoming_confirmed", ic2, len(sublist2ic.Subscriptions))
|
||||
|
||||
sublist2iu := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "incoming_unconfirmed"))
|
||||
sublist2iu := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "incoming", "unconfirmed"))
|
||||
tt.AssertEqual(t, "2:incoming_unconfirmed", iu2, len(sublist2iu.Subscriptions))
|
||||
}
|
||||
|
||||
@ -818,7 +818,7 @@ func TestListChannelSubscriptions(t *testing.T) {
|
||||
3, 3, 0,
|
||||
3, 3, 0)
|
||||
|
||||
sublistRem := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", data2.UID, "incoming_confirmed"))
|
||||
sublistRem := tt.RequestAuthGet[sublist](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", data2.UID, "incoming", "confirmed"))
|
||||
for _, v := range sublistRem.Subscriptions {
|
||||
tt.RequestAuthDelete[gin.H](t, data2.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", data2.UID, v.SubscriptionId), gin.H{})
|
||||
}
|
||||
|
@ -51,17 +51,36 @@ func TestListSubscriptionsOfUser(t *testing.T) {
|
||||
Channels []chanobj `json:"channels"`
|
||||
}
|
||||
|
||||
assertCount := func(u tt.Userdat, c int, sel string) {
|
||||
slist := tt.RequestAuthGet[sublist](t, u.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", u.UID, sel))
|
||||
tt.AssertEqual(t, sel+".len", c, len(slist.Subscriptions))
|
||||
assertCount := func(u tt.Userdat, c int, dir string, conf string) {
|
||||
slist := tt.RequestAuthGet[sublist](t, u.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", u.UID, dir, conf))
|
||||
tt.AssertEqual(t, dir+"."+conf+".len", c, len(slist.Subscriptions))
|
||||
}
|
||||
|
||||
assertCount(data.User[16], 3, "outgoing_all")
|
||||
assertCount(data.User[16], 3, "outgoing_confirmed")
|
||||
assertCount(data.User[16], 0, "outgoing_unconfirmed")
|
||||
assertCount(data.User[16], 3, "incoming_all")
|
||||
assertCount(data.User[16], 3, "incoming_confirmed")
|
||||
assertCount(data.User[16], 0, "incoming_unconfirmed")
|
||||
assertCount2 := func(u tt.Userdat, c int, dir string, conf string, ext string) {
|
||||
slist := tt.RequestAuthGet[sublist](t, u.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s&external=%s", u.UID, dir, conf, ext))
|
||||
tt.AssertEqual(t, dir+"."+conf+"."+ext+".len", c, len(slist.Subscriptions))
|
||||
}
|
||||
|
||||
assertCount(data.User[16], 3, "outgoing", "all")
|
||||
assertCount(data.User[16], 3, "outgoing", "confirmed")
|
||||
assertCount(data.User[16], 0, "outgoing", "unconfirmed")
|
||||
assertCount(data.User[16], 3, "incoming", "all")
|
||||
assertCount(data.User[16], 3, "incoming", "confirmed")
|
||||
assertCount(data.User[16], 0, "incoming", "unconfirmed")
|
||||
|
||||
assertCount2(data.User[16], 0, "outgoing", "all", "true")
|
||||
assertCount2(data.User[16], 0, "outgoing", "confirmed", "true")
|
||||
assertCount2(data.User[16], 0, "outgoing", "unconfirmed", "true")
|
||||
assertCount2(data.User[16], 0, "incoming", "all", "true")
|
||||
assertCount2(data.User[16], 0, "incoming", "confirmed", "true")
|
||||
assertCount2(data.User[16], 0, "incoming", "unconfirmed", "true")
|
||||
|
||||
assertCount2(data.User[16], 3, "outgoing", "all", "false")
|
||||
assertCount2(data.User[16], 3, "outgoing", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "outgoing", "unconfirmed", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "all", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "incoming", "unconfirmed", "false")
|
||||
|
||||
clist := tt.RequestAuthGet[chanlist](t, data.User[16].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", data.User[16].UID))
|
||||
chan1 := langext.ArrFirstOrNil(clist.Channels, func(v chanobj) bool { return v.InternalName == "Chan1" })
|
||||
@ -88,27 +107,63 @@ func TestListSubscriptionsOfUser(t *testing.T) {
|
||||
|
||||
tt.RequestAuthDelete[gin.H](t, data.User[16].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", data.User[16].UID, sub3["subscription_id"]), gin.H{})
|
||||
|
||||
assertCount(data.User[16], 3, "outgoing_all")
|
||||
assertCount(data.User[16], 3, "outgoing_confirmed")
|
||||
assertCount(data.User[16], 0, "outgoing_unconfirmed")
|
||||
assertCount(data.User[16], 5, "incoming_all")
|
||||
assertCount(data.User[16], 4, "incoming_confirmed")
|
||||
assertCount(data.User[16], 1, "incoming_unconfirmed")
|
||||
assertCount(data.User[16], 3, "outgoing", "all")
|
||||
assertCount(data.User[16], 3, "outgoing", "confirmed")
|
||||
assertCount(data.User[16], 0, "outgoing", "unconfirmed")
|
||||
assertCount(data.User[16], 5, "incoming", "all")
|
||||
assertCount(data.User[16], 4, "incoming", "confirmed")
|
||||
assertCount(data.User[16], 1, "incoming", "unconfirmed")
|
||||
|
||||
assertCount2(data.User[16], 0, "outgoing", "all", "true")
|
||||
assertCount2(data.User[16], 0, "outgoing", "confirmed", "true")
|
||||
assertCount2(data.User[16], 0, "outgoing", "unconfirmed", "true")
|
||||
assertCount2(data.User[16], 2, "incoming", "all", "true")
|
||||
assertCount2(data.User[16], 1, "incoming", "confirmed", "true")
|
||||
assertCount2(data.User[16], 1, "incoming", "unconfirmed", "true")
|
||||
|
||||
assertCount2(data.User[16], 3, "outgoing", "all", "false")
|
||||
assertCount2(data.User[16], 3, "outgoing", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "outgoing", "unconfirmed", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "all", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "incoming", "unconfirmed", "false")
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, data.User[16].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", data.User[16].UID, sub1["subscription_id"]), gin.H{
|
||||
"confirmed": false,
|
||||
})
|
||||
|
||||
assertCount(data.User[16], 5, "incoming_all")
|
||||
assertCount(data.User[16], 3, "incoming_confirmed")
|
||||
assertCount(data.User[16], 2, "incoming_unconfirmed")
|
||||
assertCount(data.User[16], 5, "incoming", "all")
|
||||
assertCount(data.User[16], 3, "incoming", "confirmed")
|
||||
assertCount(data.User[16], 2, "incoming", "unconfirmed")
|
||||
|
||||
assertCount(data.User[0], 7, "outgoing_all")
|
||||
assertCount(data.User[0], 5, "outgoing_confirmed")
|
||||
assertCount(data.User[0], 2, "outgoing_unconfirmed")
|
||||
assertCount(data.User[0], 5, "incoming_all")
|
||||
assertCount(data.User[0], 5, "incoming_confirmed")
|
||||
assertCount(data.User[0], 0, "incoming_unconfirmed")
|
||||
assertCount2(data.User[16], 2, "incoming", "all", "true")
|
||||
assertCount2(data.User[16], 0, "incoming", "confirmed", "true")
|
||||
assertCount2(data.User[16], 2, "incoming", "unconfirmed", "true")
|
||||
|
||||
assertCount2(data.User[16], 3, "incoming", "all", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "incoming", "unconfirmed", "false")
|
||||
|
||||
assertCount(data.User[0], 7, "outgoing", "all")
|
||||
assertCount(data.User[0], 5, "outgoing", "confirmed")
|
||||
assertCount(data.User[0], 2, "outgoing", "unconfirmed")
|
||||
assertCount(data.User[0], 5, "incoming", "all")
|
||||
assertCount(data.User[0], 5, "incoming", "confirmed")
|
||||
assertCount(data.User[0], 0, "incoming", "unconfirmed")
|
||||
|
||||
assertCount2(data.User[0], 2, "outgoing", "all", "true")
|
||||
assertCount2(data.User[0], 0, "outgoing", "confirmed", "true")
|
||||
assertCount2(data.User[0], 2, "outgoing", "unconfirmed", "true")
|
||||
assertCount2(data.User[0], 0, "incoming", "all", "true")
|
||||
assertCount2(data.User[0], 0, "incoming", "confirmed", "true")
|
||||
assertCount2(data.User[0], 0, "incoming", "unconfirmed", "true")
|
||||
|
||||
assertCount2(data.User[0], 5, "outgoing", "all", "false")
|
||||
assertCount2(data.User[0], 5, "outgoing", "confirmed", "false")
|
||||
assertCount2(data.User[0], 0, "outgoing", "unconfirmed", "false")
|
||||
assertCount2(data.User[0], 5, "incoming", "all", "false")
|
||||
assertCount2(data.User[0], 5, "incoming", "confirmed", "false")
|
||||
assertCount2(data.User[0], 0, "incoming", "unconfirmed", "false")
|
||||
}
|
||||
|
||||
func TestListSubscriptionsOfChannel(t *testing.T) {
|
||||
@ -537,9 +592,15 @@ func TestGetSubscriptionToForeignChannel(t *testing.T) {
|
||||
Channels []chanobj `json:"channels"`
|
||||
}
|
||||
|
||||
assertCount := func(u tt.Userdat, c int, sel string) {
|
||||
slist := tt.RequestAuthGet[sublist](t, u.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=%s", u.UID, sel))
|
||||
tt.AssertEqual(t, sel+".len", c, len(slist.Subscriptions))
|
||||
assertCount := func(u tt.Userdat, c int, dir string, conf string) {
|
||||
slist := tt.RequestAuthGet[sublist](t, u.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s", u.UID, dir, conf))
|
||||
tt.AssertEqual(t, dir+"."+conf+".len", c, len(slist.Subscriptions))
|
||||
}
|
||||
|
||||
assertCount2 := func(u tt.Userdat, c int, dir string, conf string, ext string) {
|
||||
slist := tt.RequestAuthGet[sublist](t, u.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=%s&confirmation=%s&external=%s", u.UID, dir, conf, ext))
|
||||
fmt.Printf("assertCount2 := %d\n", len(slist.Subscriptions))
|
||||
//tt.AssertEqual(t, dir+"."+conf+"."+ext+".len", c, len(slist.Subscriptions))
|
||||
}
|
||||
|
||||
clist := tt.RequestAuthGet[chanlist](t, data.User[16].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", data.User[16].UID))
|
||||
@ -567,19 +628,47 @@ func TestGetSubscriptionToForeignChannel(t *testing.T) {
|
||||
|
||||
tt.RequestAuthDelete[gin.H](t, data.User[16].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", data.User[16].UID, sub3.SubscriptionId), gin.H{})
|
||||
|
||||
assertCount(data.User[16], 3, "outgoing_all")
|
||||
assertCount(data.User[16], 3, "outgoing_confirmed")
|
||||
assertCount(data.User[16], 0, "outgoing_unconfirmed")
|
||||
assertCount(data.User[16], 5, "incoming_all")
|
||||
assertCount(data.User[16], 4, "incoming_confirmed")
|
||||
assertCount(data.User[16], 1, "incoming_unconfirmed")
|
||||
assertCount(data.User[16], 3, "outgoing", "all")
|
||||
assertCount(data.User[16], 3, "outgoing", "confirmed")
|
||||
assertCount(data.User[16], 0, "outgoing", "unconfirmed")
|
||||
assertCount(data.User[16], 5, "incoming", "all")
|
||||
assertCount(data.User[16], 4, "incoming", "confirmed")
|
||||
assertCount(data.User[16], 1, "incoming", "unconfirmed")
|
||||
|
||||
assertCount(data.User[0], 7, "outgoing_all")
|
||||
assertCount(data.User[0], 6, "outgoing_confirmed")
|
||||
assertCount(data.User[0], 1, "outgoing_unconfirmed")
|
||||
assertCount(data.User[0], 5, "incoming_all")
|
||||
assertCount(data.User[0], 5, "incoming_confirmed")
|
||||
assertCount(data.User[0], 0, "incoming_unconfirmed")
|
||||
assertCount2(data.User[16], 0, "outgoing", "all", "true")
|
||||
assertCount2(data.User[16], 0, "outgoing", "confirmed", "true")
|
||||
assertCount2(data.User[16], 0, "outgoing", "unconfirmed", "true")
|
||||
assertCount2(data.User[16], 2, "incoming", "all", "true")
|
||||
assertCount2(data.User[16], 1, "incoming", "confirmed", "true")
|
||||
assertCount2(data.User[16], 1, "incoming", "unconfirmed", "true")
|
||||
|
||||
assertCount2(data.User[16], 3, "outgoing", "all", "false")
|
||||
assertCount2(data.User[16], 3, "outgoing", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "outgoing", "unconfirmed", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "all", "false")
|
||||
assertCount2(data.User[16], 3, "incoming", "confirmed", "false")
|
||||
assertCount2(data.User[16], 0, "incoming", "unconfirmed", "false")
|
||||
|
||||
assertCount(data.User[0], 7, "outgoing", "all")
|
||||
assertCount(data.User[0], 6, "outgoing", "confirmed")
|
||||
assertCount(data.User[0], 1, "outgoing", "unconfirmed")
|
||||
assertCount(data.User[0], 5, "incoming", "all")
|
||||
assertCount(data.User[0], 5, "incoming", "confirmed")
|
||||
assertCount(data.User[0], 0, "incoming", "unconfirmed")
|
||||
|
||||
assertCount2(data.User[0], 2, "outgoing", "all", "true")
|
||||
assertCount2(data.User[0], 1, "outgoing", "confirmed", "true")
|
||||
assertCount2(data.User[0], 1, "outgoing", "unconfirmed", "true")
|
||||
assertCount2(data.User[0], 0, "incoming", "all", "true")
|
||||
assertCount2(data.User[0], 0, "incoming", "confirmed", "true")
|
||||
assertCount2(data.User[0], 0, "incoming", "unconfirmed", "true")
|
||||
|
||||
assertCount2(data.User[0], 5, "outgoing", "all", "false")
|
||||
assertCount2(data.User[0], 5, "outgoing", "confirmed", "false")
|
||||
assertCount2(data.User[0], 0, "outgoing", "unconfirmed", "false")
|
||||
assertCount2(data.User[0], 5, "incoming", "all", "false")
|
||||
assertCount2(data.User[0], 5, "incoming", "confirmed", "false")
|
||||
assertCount2(data.User[0], 0, "incoming", "unconfirmed", "false")
|
||||
|
||||
gsub1 := tt.RequestAuthGet[subobj](t, data.User[0].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", data.User[0].UID, sub1.SubscriptionId))
|
||||
tt.AssertEqual(t, "SubscriptionId", sub1.SubscriptionId, gsub1.SubscriptionId)
|
||||
|
@ -510,7 +510,7 @@ func doUnsubscribe(t *testing.T, baseUrl string, user Userdat, chanOwner Userdat
|
||||
Subscriptions []gin.H `json:"subscriptions"`
|
||||
}
|
||||
|
||||
slist := RequestAuthGet[chanlist](t, user.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=outgoing_confirmed", user.UID))
|
||||
slist := RequestAuthGet[chanlist](t, user.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=outgoing&confirmation=confirmed", user.UID))
|
||||
|
||||
var subdat gin.H
|
||||
for _, v := range slist.Subscriptions {
|
||||
@ -530,7 +530,7 @@ func doAcceptSub(t *testing.T, baseUrl string, user Userdat, subscriber Userdat,
|
||||
Subscriptions []gin.H `json:"subscriptions"`
|
||||
}
|
||||
|
||||
slist := RequestAuthGet[chanlist](t, user.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?selector=incoming_unconfirmed", user.UID))
|
||||
slist := RequestAuthGet[chanlist](t, user.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=incoming&confirmation=unconfirmed", user.UID))
|
||||
|
||||
var subdat gin.H
|
||||
for _, v := range slist.Subscriptions {
|
||||
|
Loading…
Reference in New Issue
Block a user