Return subscription from channel-preview [skip-tests]
This commit is contained in:
parent
301240b896
commit
c0b8a8a3f4
@ -90,6 +90,8 @@ func (h APIHandler) GetChannelPreview(pctx ginext.PreContext) ginext.HTTPRespons
|
|||||||
return *permResp
|
return *permResp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userid := *ctx.GetPermissionUserID()
|
||||||
|
|
||||||
channel, err := h.database.GetChannelByID(ctx, u.ChannelID)
|
channel, err := h.database.GetChannelByID(ctx, u.ChannelID)
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
||||||
@ -98,7 +100,12 @@ func (h APIHandler) GetChannelPreview(pctx ginext.PreContext) ginext.HTTPRespons
|
|||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return finishSuccess(ginext.JSON(http.StatusOK, channel.Preview()))
|
sub, err := h.database.GetSubscriptionBySubscriber(ctx, userid, channel.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query subscription", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return finishSuccess(ginext.JSON(http.StatusOK, channel.Preview(sub)))
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -155,7 +162,7 @@ func (h APIHandler) GetUserKeyPreview(pctx ginext.PreContext) ginext.HTTPRespons
|
|||||||
// Query by token.token
|
// Query by token.token
|
||||||
|
|
||||||
keytoken, err := h.database.GetKeyTokenByToken(ctx, u.KeyID)
|
keytoken, err := h.database.GetKeyTokenByToken(ctx, u.KeyID)
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if keytoken == nil {
|
||||||
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,6 +24,8 @@ type ChannelPreview struct {
|
|||||||
DisplayName string `json:"display_name"`
|
DisplayName string `json:"display_name"`
|
||||||
DescriptionName *string `json:"description_name"`
|
DescriptionName *string `json:"description_name"`
|
||||||
MessagesSent int `json:"messages_sent"`
|
MessagesSent int `json:"messages_sent"`
|
||||||
|
|
||||||
|
Subscription *Subscription `json:"subscription"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Channel) WithSubscription(sub *Subscription) ChannelWithSubscription {
|
func (c Channel) WithSubscription(sub *Subscription) ChannelWithSubscription {
|
||||||
@ -33,7 +35,7 @@ func (c Channel) WithSubscription(sub *Subscription) ChannelWithSubscription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Channel) Preview() ChannelPreview {
|
func (c Channel) Preview(sub *Subscription) ChannelPreview {
|
||||||
return ChannelPreview{
|
return ChannelPreview{
|
||||||
ChannelID: c.ChannelID,
|
ChannelID: c.ChannelID,
|
||||||
OwnerUserID: c.OwnerUserID,
|
OwnerUserID: c.OwnerUserID,
|
||||||
@ -41,5 +43,6 @@ func (c Channel) Preview() ChannelPreview {
|
|||||||
DisplayName: c.DisplayName,
|
DisplayName: c.DisplayName,
|
||||||
DescriptionName: c.DescriptionName,
|
DescriptionName: c.DescriptionName,
|
||||||
MessagesSent: c.MessagesSent,
|
MessagesSent: c.MessagesSent,
|
||||||
|
Subscription: sub,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||||
"fmt"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetChannelPreview(t *testing.T) {
|
func TestGetChannelPreview(t *testing.T) {
|
||||||
@ -148,7 +149,7 @@ func TestGetUserPreview(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetKeyTokenPreview(t *testing.T) {
|
func TestGetKeyTokenPreviewByID(t *testing.T) {
|
||||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
defer stop()
|
defer stop()
|
||||||
|
|
||||||
@ -248,3 +249,174 @@ func TestGetKeyTokenPreview(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetKeyTokenPreviewByToken(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitDefaultData(t, ws)
|
||||||
|
|
||||||
|
type keyobj struct {
|
||||||
|
AllChannels bool `json:"all_channels"`
|
||||||
|
Channels []string `json:"channels"`
|
||||||
|
KeytokenId string `json:"keytoken_id"`
|
||||||
|
MessagesSent int `json:"messages_sent"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
OwnerUserId string `json:"owner_user_id"`
|
||||||
|
Permissions string `json:"permissions"`
|
||||||
|
}
|
||||||
|
type keylist struct {
|
||||||
|
Keys []keyobj `json:"keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
klist := tt.RequestAuthGet[keylist](t, data.User[0].AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.User[0].UID))
|
||||||
|
|
||||||
|
adminKeyObj := *langext.ArrFirstOrNil(klist.Keys, func(v keyobj) bool { return v.Permissions == "A" })
|
||||||
|
readKeyObj := *langext.ArrFirstOrNil(klist.Keys, func(v keyobj) bool { return v.Permissions == "UR;CR" })
|
||||||
|
sendKeyObj := *langext.ArrFirstOrNil(klist.Keys, func(v keyobj) bool { return v.Permissions == "CS" })
|
||||||
|
|
||||||
|
// Test with User[0]'s keys accessing their own key previews via token value
|
||||||
|
{
|
||||||
|
rqAdmin := tt.RequestAuthGet[gin.H](t, data.User[0].AdminKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].AdminKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", adminKeyObj.KeytokenId, rqAdmin["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", adminKeyObj.Name, rqAdmin["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", adminKeyObj.OwnerUserId, rqAdmin["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", adminKeyObj.Permissions, rqAdmin["permissions"])
|
||||||
|
|
||||||
|
rqRead := tt.RequestAuthGet[gin.H](t, data.User[0].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].ReadKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", readKeyObj.KeytokenId, rqRead["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", readKeyObj.Name, rqRead["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", readKeyObj.OwnerUserId, rqRead["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", readKeyObj.Permissions, rqRead["permissions"])
|
||||||
|
|
||||||
|
rqSend := tt.RequestAuthGet[gin.H](t, data.User[0].SendKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].SendKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", sendKeyObj.KeytokenId, rqSend["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", sendKeyObj.Name, rqSend["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", sendKeyObj.OwnerUserId, rqSend["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", sendKeyObj.Permissions, rqSend["permissions"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with User[1]'s keys accessing User[0]'s key previews via token value (should work as preview is public)
|
||||||
|
{
|
||||||
|
rqAdmin := tt.RequestAuthGet[gin.H](t, data.User[1].AdminKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].AdminKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", adminKeyObj.KeytokenId, rqAdmin["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", adminKeyObj.Name, rqAdmin["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", adminKeyObj.OwnerUserId, rqAdmin["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", adminKeyObj.Permissions, rqAdmin["permissions"])
|
||||||
|
|
||||||
|
rqRead := tt.RequestAuthGet[gin.H](t, data.User[1].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].ReadKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", readKeyObj.KeytokenId, rqRead["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", readKeyObj.Name, rqRead["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", readKeyObj.OwnerUserId, rqRead["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", readKeyObj.Permissions, rqRead["permissions"])
|
||||||
|
|
||||||
|
rqSend := tt.RequestAuthGet[gin.H](t, data.User[1].SendKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].SendKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", sendKeyObj.KeytokenId, rqSend["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", sendKeyObj.Name, rqSend["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", sendKeyObj.OwnerUserId, rqSend["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", sendKeyObj.Permissions, rqSend["permissions"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with User[1]'s keys accessing User[0]'s key previews via token value (should work as preview is public)
|
||||||
|
{
|
||||||
|
rqAdmin := tt.RequestAuthGet[gin.H](t, data.User[1].AdminKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].AdminKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", adminKeyObj.KeytokenId, rqAdmin["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", adminKeyObj.Name, rqAdmin["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", adminKeyObj.OwnerUserId, rqAdmin["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", adminKeyObj.Permissions, rqAdmin["permissions"])
|
||||||
|
|
||||||
|
rqRead := tt.RequestAuthGet[gin.H](t, data.User[1].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].ReadKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", readKeyObj.KeytokenId, rqRead["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", readKeyObj.Name, rqRead["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", readKeyObj.OwnerUserId, rqRead["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", readKeyObj.Permissions, rqRead["permissions"])
|
||||||
|
|
||||||
|
rqSend := tt.RequestAuthGet[gin.H](t, data.User[1].SendKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].SendKey))
|
||||||
|
tt.AssertEqual(t, "keytoken_id", sendKeyObj.KeytokenId, rqSend["keytoken_id"])
|
||||||
|
tt.AssertEqual(t, "name", sendKeyObj.Name, rqSend["name"])
|
||||||
|
tt.AssertEqual(t, "owner_user_id", sendKeyObj.OwnerUserId, rqSend["owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "permissions", sendKeyObj.Permissions, rqSend["permissions"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with invalid token
|
||||||
|
{
|
||||||
|
tt.RequestAuthGetShouldFail(t, data.User[0].AdminKey, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", "invalid-token-string"), 404, apierr.KEY_NOT_FOUND)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test without auth
|
||||||
|
{
|
||||||
|
tt.RequestGetShouldFail(t, baseUrl, fmt.Sprintf("/api/v2/preview/keys/%s", data.User[0].SendKey), 401, apierr.USER_AUTH_FAILED)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetChannelPreviewSubscriptionNone(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitDefaultData(t, ws)
|
||||||
|
|
||||||
|
// User[1] (who is not subscribed) requests preview of User[0]'s channel
|
||||||
|
preview := tt.RequestAuthGet[gin.H](t, data.User[1].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/channels/%s", data.User[0].Channels[0].ChannelID))
|
||||||
|
|
||||||
|
// Assert User[1] sees no subscription
|
||||||
|
tt.AssertNil(t, "subscription", preview["subscription"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetChannelPreviewSubscriptionUnconfirmed(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitDefaultData(t, ws)
|
||||||
|
|
||||||
|
chanReq := *langext.ArrFirstOrNil(data.User[15].Channels, func(v tt.ChanData) bool { return v.InternalName == "chan_other_request" })
|
||||||
|
|
||||||
|
preview := tt.RequestAuthGet[gin.H](t, data.User[14].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/channels/%s", chanReq.ChannelID))
|
||||||
|
|
||||||
|
// Assert User[14] sees their unconfirmed subscription
|
||||||
|
tt.AssertNotNil(t, "subscription", preview["subscription"])
|
||||||
|
subscription, ok := preview["subscription"].(map[string]any)
|
||||||
|
tt.AssertTrue(t, "subscription is map", ok)
|
||||||
|
tt.AssertEqual(t, "subscription.user_id", data.User[14].UID, subscription["subscriber_user_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.user_id", data.User[15].UID, subscription["channel_owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.channel_id", chanReq.ChannelID, subscription["channel_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.confirmed", false, subscription["confirmed"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetChannelPreviewSubscriptionOwnSubscription(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitDefaultData(t, ws)
|
||||||
|
|
||||||
|
preview := tt.RequestAuthGet[gin.H](t, data.User[4].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/channels/%s", data.User[4].Channels[0].ChannelID))
|
||||||
|
|
||||||
|
// Assert User[4] sees their own subscription
|
||||||
|
tt.AssertNotNil(t, "subscription", preview["subscription"])
|
||||||
|
subscription, ok := preview["subscription"].(map[string]any)
|
||||||
|
tt.AssertTrue(t, "subscription is map", ok)
|
||||||
|
tt.AssertEqual(t, "subscription.user_id", data.User[4].UID, subscription["subscriber_user_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.user_id", data.User[4].UID, subscription["channel_owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.channel_id", data.User[4].Channels[0].ChannelID, subscription["channel_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.confirmed", true, subscription["confirmed"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetChannelPreviewSubscriptionForeignSubscription(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitDefaultData(t, ws)
|
||||||
|
|
||||||
|
chanReq := *langext.ArrFirstOrNil(data.User[15].Channels, func(v tt.ChanData) bool { return v.InternalName == "chan_other_accepted" })
|
||||||
|
|
||||||
|
preview := tt.RequestAuthGet[gin.H](t, data.User[14].ReadKey, baseUrl, fmt.Sprintf("/api/v2/preview/channels/%s", chanReq.ChannelID))
|
||||||
|
|
||||||
|
// Assert User[14] sees their confirmed subscription
|
||||||
|
tt.AssertNotNil(t, "subscription", preview["subscription"])
|
||||||
|
subscription, ok := preview["subscription"].(map[string]any)
|
||||||
|
tt.AssertTrue(t, "subscription is map", ok)
|
||||||
|
tt.AssertEqual(t, "subscription.user_id", data.User[14].UID, subscription["subscriber_user_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.user_id", data.User[15].UID, subscription["channel_owner_user_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.channel_id", chanReq.ChannelID, subscription["channel_id"])
|
||||||
|
tt.AssertEqual(t, "subscription.confirmed", true, subscription["confirmed"])
|
||||||
|
}
|
||||||
|
@ -255,6 +255,7 @@ func TestResponseChannelPreview(t *testing.T) {
|
|||||||
"display_name": "string",
|
"display_name": "string",
|
||||||
"description_name": "string|null",
|
"description_name": "string|null",
|
||||||
"messages_sent": "int",
|
"messages_sent": "int",
|
||||||
|
"subscription": "object|null",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +306,22 @@ func AssertAny(v any) {
|
|||||||
// used to prevent golang "unused variable error"
|
// used to prevent golang "unused variable error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AssertNil(t *testing.T, key string, v any) {
|
||||||
|
if v != nil {
|
||||||
|
t.Errorf("AssertNil(%s) failed - actual value:\n%+v", key, v)
|
||||||
|
t.Error(string(debug.Stack()))
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AssertNotNil(t *testing.T, key string, v any) {
|
||||||
|
if v == nil {
|
||||||
|
t.Errorf("AssertNotNil(%s) failed", key)
|
||||||
|
t.Error(string(debug.Stack()))
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func unpointer(v any) any {
|
func unpointer(v any) any {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return v
|
return v
|
||||||
|
@ -125,6 +125,18 @@ func assertjsonStructureMatchSingleValue(t *testing.T, strschema string, realVal
|
|||||||
t.Errorf("Key < %s > is not a int (its actually %T: '%v')", keyPath, realValue, realValue)
|
t.Errorf("Key < %s > is not a int (its actually %T: '%v')", keyPath, realValue, realValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case "object|null":
|
||||||
|
if langext.IsNil(realValue) {
|
||||||
|
return // OK
|
||||||
|
}
|
||||||
|
if _, ok := realValue.(map[string]any); !ok {
|
||||||
|
t.Errorf("Key < %s > is not an object|null (its actually %T: '%v')", keyPath, realValue, realValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := time.Parse(time.RFC3339, realValue.(string)); err != nil {
|
||||||
|
t.Errorf("Key < %s > is not an object|null (its '%v')", keyPath, realValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
t.Errorf("Unknown schema type '%s' for key < %s >", strschema, keyPath)
|
t.Errorf("Unknown schema type '%s' for key < %s >", strschema, keyPath)
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user