re-implement ack behaviour from version 1.0 for compat
This commit is contained in:
parent
01934e29b1
commit
16f6ab4861
@ -82,3 +82,6 @@
|
||||
- cannot open sqlite in dbbrowsr (cannot parse schema?)
|
||||
-> https://github.com/sqlitebrowser/sqlitebrowser/issues/292 -> https://github.com/sqlitebrowser/sqlitebrowser/issues/29266
|
||||
|
||||
#### FUTURE
|
||||
|
||||
- Remove compat, especially do not create compat id for every new message...
|
@ -3,7 +3,7 @@ package handler
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
"blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
primarydb "blackforestbytes.com/simplecloudnotifier/db/impl/primary"
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
@ -930,7 +930,7 @@ func (h APIHandler) ListChannelMessages(g *gin.Context) ginresp.HTTPResponse {
|
||||
return ginresp.APIError(g, 401, apierr.USER_AUTH_FAILED, "You are not authorized for this action", nil)
|
||||
}
|
||||
|
||||
tok, err := cursortoken.Decode(langext.Coalesce(q.NextPageToken, ""))
|
||||
tok, err := ct.Decode(langext.Coalesce(q.NextPageToken, ""))
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.PAGETOKEN_ERROR, "Failed to decode next_page_token", err)
|
||||
}
|
||||
@ -1419,7 +1419,7 @@ func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
|
||||
|
||||
userid := *ctx.GetPermissionUserID()
|
||||
|
||||
tok, err := cursortoken.Decode(langext.Coalesce(q.NextPageToken, ""))
|
||||
tok, err := ct.Decode(langext.Coalesce(q.NextPageToken, ""))
|
||||
if err != nil {
|
||||
return ginresp.APIError(g, 500, apierr.PAGETOKEN_ERROR, "Failed to decode next_page_token", err)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
hl "blackforestbytes.com/simplecloudnotifier/api/apihighlight"
|
||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
primarydb "blackforestbytes.com/simplecloudnotifier/db/impl/primary"
|
||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
@ -90,19 +91,6 @@ func (h MessageHandler) SendMessageCompat(g *gin.Context) ginresp.HTTPResponse {
|
||||
return *errResp
|
||||
} else {
|
||||
if okResp.MessageIsOld {
|
||||
|
||||
compatMessageID, _, err := h.database.ConvertToCompatID(ctx, okResp.Message.MessageID.String())
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query compat-id", err)
|
||||
}
|
||||
if compatMessageID == nil {
|
||||
v, err := h.database.CreateCompatID(ctx, "messageid", okResp.Message.MessageID.String())
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create compat-id", err)
|
||||
}
|
||||
compatMessageID = &v
|
||||
}
|
||||
|
||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
||||
Success: true,
|
||||
ErrorID: apierr.NO_ERROR,
|
||||
@ -113,15 +101,9 @@ func (h MessageHandler) SendMessageCompat(g *gin.Context) ginresp.HTTPResponse {
|
||||
Quota: okResp.User.QuotaUsedToday(),
|
||||
IsPro: okResp.User.IsPro,
|
||||
QuotaMax: okResp.User.QuotaPerDay(),
|
||||
SCNMessageID: *compatMessageID,
|
||||
SCNMessageID: okResp.CompatMessageID,
|
||||
}))
|
||||
} else {
|
||||
|
||||
compatMessageID, err := h.database.CreateCompatID(ctx, "messageid", okResp.Message.MessageID.String())
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create compat-id", err)
|
||||
}
|
||||
|
||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
||||
Success: true,
|
||||
ErrorID: apierr.NO_ERROR,
|
||||
@ -132,7 +114,7 @@ func (h MessageHandler) SendMessageCompat(g *gin.Context) ginresp.HTTPResponse {
|
||||
Quota: okResp.User.QuotaUsedToday() + 1,
|
||||
IsPro: okResp.User.IsPro,
|
||||
QuotaMax: okResp.User.QuotaPerDay(),
|
||||
SCNMessageID: compatMessageID,
|
||||
SCNMessageID: okResp.CompatMessageID,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -420,12 +402,30 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
|
||||
// we no longer ack messages - this is a no-op
|
||||
messageIdComp, err := h.database.ConvertCompatID(ctx, *data.MessageID, "messageid")
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query messageid<old>", err)
|
||||
}
|
||||
if useridCompNew == nil {
|
||||
return ginresp.SendAPIError(g, 400, apierr.MESSAGE_NOT_FOUND, hl.USER_ID, "Message not found (compat)", nil)
|
||||
}
|
||||
|
||||
ackBefore, err := h.database.GetAck(ctx, models.MessageID(*messageIdComp))
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query ack", err)
|
||||
}
|
||||
|
||||
if !ackBefore {
|
||||
err = h.database.SetAck(ctx, user.UserID, models.MessageID(*messageIdComp))
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to set ack", err)
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
||||
Success: true,
|
||||
Message: "ok",
|
||||
PrevAckValue: 0,
|
||||
PrevAckValue: langext.Conditional(ackBefore, 1, 0),
|
||||
NewAckValue: 1,
|
||||
}))
|
||||
}
|
||||
@ -497,11 +497,40 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
||||
return ginresp.CompatAPIError(204, "Authentification failed")
|
||||
}
|
||||
|
||||
filter := models.MessageFilter{
|
||||
Owner: langext.Ptr([]models.UserID{user.UserID}),
|
||||
CompatAcknowledged: langext.Ptr(false),
|
||||
}
|
||||
|
||||
msgs, _, err := h.database.ListMessages(ctx, filter, 16, ct.Start())
|
||||
if err != nil {
|
||||
return ginresp.CompatAPIError(0, "Failed to query user")
|
||||
}
|
||||
|
||||
compMsgs := make([]models.CompatMessage, 0, len(msgs))
|
||||
for _, v := range msgs {
|
||||
|
||||
messageIdComp, err := h.database.ConvertToCompatIDOrCreate(ctx, v.MessageID.String(), "messageid")
|
||||
if err != nil {
|
||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query/create messageid<old>", err)
|
||||
}
|
||||
|
||||
compMsgs = append(compMsgs, models.CompatMessage{
|
||||
Title: v.Title,
|
||||
Body: v.Content,
|
||||
Priority: v.Priority,
|
||||
Timestamp: v.Timestamp().Unix(),
|
||||
UserMessageID: v.UserMessageID,
|
||||
SCNMessageID: messageIdComp,
|
||||
Trimmed: nil,
|
||||
})
|
||||
}
|
||||
|
||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
||||
Success: true,
|
||||
Message: "ok",
|
||||
Count: 0,
|
||||
Data: make([]models.CompatMessage, 0),
|
||||
Count: len(compMsgs),
|
||||
Data: compMsgs,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,10 @@ import (
|
||||
)
|
||||
|
||||
type SendMessageResponse struct {
|
||||
User models.User
|
||||
Message models.Message
|
||||
MessageIsOld bool
|
||||
User models.User
|
||||
Message models.Message
|
||||
MessageIsOld bool
|
||||
CompatMessageID int64
|
||||
}
|
||||
|
||||
type MessageHandler struct {
|
||||
@ -195,11 +196,26 @@ 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 query existing message", err))
|
||||
}
|
||||
if msg != nil {
|
||||
|
||||
existingCompID, _, err := h.database.ConvertToCompatID(ctx, msg.MessageID.String())
|
||||
if err != nil {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query compat-id", err))
|
||||
}
|
||||
|
||||
if existingCompID == nil {
|
||||
v, err := h.database.CreateCompatID(ctx, "messageid", msg.MessageID.String())
|
||||
if err != nil {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create compat-id", err))
|
||||
}
|
||||
existingCompID = &v
|
||||
}
|
||||
|
||||
//the found message can be deleted (!), but we still return NO_ERROR here...
|
||||
return &SendMessageResponse{
|
||||
User: user,
|
||||
Message: *msg,
|
||||
MessageIsOld: true,
|
||||
User: user,
|
||||
Message: *msg,
|
||||
MessageIsOld: true,
|
||||
CompatMessageID: *existingCompID,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@ -251,6 +267,11 @@ 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 message in db", err))
|
||||
}
|
||||
|
||||
cid, err := h.database.CreateCompatID(ctx, "messageid", msg.MessageID.String())
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query subscriptions", err))
|
||||
@ -295,8 +316,9 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
||||
}
|
||||
|
||||
return &SendMessageResponse{
|
||||
User: user,
|
||||
Message: msg,
|
||||
MessageIsOld: false,
|
||||
User: user,
|
||||
Message: msg,
|
||||
MessageIsOld: false,
|
||||
CompatMessageID: cid,
|
||||
}, nil
|
||||
}
|
||||
|
@ -455,6 +455,14 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
||||
}
|
||||
}
|
||||
|
||||
_, err = dbnew.Exec(ctx, "INSERT INTO compat_acks (user_id, message_id) VALUES (:uid, :mid)", sq.PP{
|
||||
"uid": userid,
|
||||
"mid": messageid,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
} else if len(oldmessage.Ack) == 1 && oldmessage.Ack[0] == 0 {
|
||||
|
||||
if clientid != nil {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
@ -98,3 +99,59 @@ func (db *Database) ConvertToCompatID(ctx TxContext, newid string) (*int64, *str
|
||||
|
||||
return &oldid, &idtype, nil
|
||||
}
|
||||
|
||||
func (db *Database) ConvertToCompatIDOrCreate(ctx TxContext, idtype string, newid string) (int64, error) {
|
||||
id1, _, err := db.ConvertToCompatID(ctx, newid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if id1 != nil {
|
||||
return *id1, nil
|
||||
}
|
||||
|
||||
id2, err := db.CreateCompatID(ctx, idtype, newid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id2, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAck(ctx TxContext, msgid models.MessageID) (bool, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM compat_acks WHERE message_id = :msgid LIMIT 1", sq.PP{
|
||||
"msgid": msgid,
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
res := rows.Next()
|
||||
|
||||
err = rows.Close()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) SetAck(ctx TxContext, userid models.UserID, msgid models.MessageID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO compat_acks (user_id, message_id) VALUES (:uid, :mid)", sq.PP{
|
||||
"uid": userid,
|
||||
"mid": msgid,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
"database/sql"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
@ -116,18 +116,18 @@ func (db *Database) DeleteMessage(ctx TxContext, messageID models.MessageID) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pageSize int, inTok cursortoken.CursorToken) ([]models.Message, cursortoken.CursorToken, error) {
|
||||
func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pageSize int, inTok ct.CursorToken) ([]models.Message, ct.CursorToken, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, cursortoken.CursorToken{}, err
|
||||
return nil, ct.CursorToken{}, err
|
||||
}
|
||||
|
||||
if inTok.Mode == cursortoken.CTMEnd {
|
||||
return make([]models.Message, 0), cursortoken.End(), nil
|
||||
if inTok.Mode == ct.CTMEnd {
|
||||
return make([]models.Message, 0), ct.End(), nil
|
||||
}
|
||||
|
||||
pageCond := "1=1"
|
||||
if inTok.Mode == cursortoken.CTMNormal {
|
||||
if inTok.Mode == ct.CTMNormal {
|
||||
pageCond = "timestamp_real < :tokts OR (timestamp_real = :tokts AND message_id < :tokid )"
|
||||
}
|
||||
|
||||
@ -143,18 +143,18 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
|
||||
|
||||
rows, err := tx.Query(ctx, sqlQuery, prepParams)
|
||||
if err != nil {
|
||||
return nil, cursortoken.CursorToken{}, err
|
||||
return nil, ct.CursorToken{}, err
|
||||
}
|
||||
|
||||
data, err := models.DecodeMessages(rows)
|
||||
if err != nil {
|
||||
return nil, cursortoken.CursorToken{}, err
|
||||
return nil, ct.CursorToken{}, err
|
||||
}
|
||||
|
||||
if len(data) <= pageSize {
|
||||
return data, cursortoken.End(), nil
|
||||
return data, ct.End(), nil
|
||||
} else {
|
||||
outToken := cursortoken.Normal(data[pageSize-1].Timestamp(), data[pageSize-1].MessageID.String(), "DESC", filter.Hash())
|
||||
outToken := ct.Normal(data[pageSize-1].Timestamp(), data[pageSize-1].MessageID.String(), "DESC", filter.Hash())
|
||||
return data[0:pageSize], outToken, nil
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +183,16 @@ CREATE UNIQUE INDEX "idx_compatids_new" ON compat_ids (new);
|
||||
CREATE UNIQUE INDEX "idx_compatids_old" ON compat_ids (old, type);
|
||||
|
||||
|
||||
CREATE TABLE compat_acks
|
||||
(
|
||||
user_id TEXT NOT NULL,
|
||||
message_id TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_compatacks_userid" ON compat_acks (user_id);
|
||||
CREATE UNIQUE INDEX "idx_compatacks_messageid" ON compat_acks (message_id);
|
||||
CREATE UNIQUE INDEX "idx_compatacks_userid_messageid" ON compat_acks (user_id, message_id);
|
||||
|
||||
|
||||
CREATE TABLE `meta`
|
||||
(
|
||||
meta_key TEXT NOT NULL,
|
||||
|
@ -14,8 +14,8 @@ const (
|
||||
|
||||
type Message struct {
|
||||
MessageID MessageID
|
||||
SenderUserID UserID
|
||||
OwnerUserID UserID
|
||||
SenderUserID UserID // user that sent the message
|
||||
OwnerUserID UserID // oner of the message (= owner of the channel that contains it)
|
||||
ChannelInternalName string
|
||||
ChannelID ChannelID
|
||||
SenderName *string
|
||||
|
@ -39,6 +39,7 @@ type MessageFilter struct {
|
||||
UserMessageID *[]string
|
||||
OnlyDeleted bool
|
||||
IncludeDeleted bool
|
||||
CompatAcknowledged *bool
|
||||
}
|
||||
|
||||
func (f MessageFilter) SQL() (string, string, sq.PP, error) {
|
||||
@ -79,7 +80,7 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) {
|
||||
|
||||
if f.Owner != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.Sender {
|
||||
for i, v := range *f.Owner {
|
||||
filter = append(filter, fmt.Sprintf("(owner_user_id = :owner_%d)", i))
|
||||
params[fmt.Sprintf("owner_%d", i)] = v
|
||||
}
|
||||
@ -209,6 +210,16 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) {
|
||||
sqlClauses = append(sqlClauses, "(usr_message_id IS NOT NULL AND ("+strings.Join(filter, " OR ")+"))")
|
||||
}
|
||||
|
||||
if f.CompatAcknowledged != nil {
|
||||
joinClause += " LEFT JOIN compat_acks AS filter_compatack_compat_acks on messages.message_id = filter_compatack_compat_acks.message_id "
|
||||
|
||||
if *f.CompatAcknowledged {
|
||||
sqlClauses = append(sqlClauses, "(filter_compatack_compat_acks.message_id IS NOT NULL)")
|
||||
} else {
|
||||
sqlClauses = append(sqlClauses, "(filter_compatack_compat_acks.message_id IS NULL)")
|
||||
}
|
||||
}
|
||||
|
||||
if f.SearchString != nil {
|
||||
filter := make([]string, 0)
|
||||
for i, v := range *f.SearchString {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -426,165 +426,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/messages": {
|
||||
"get": {
|
||||
"description": "The next_page_token is an opaque token, the special value \"@start\" (or empty-string) is the beginning and \"@end\" is the end\nSimply start the pagination without a next_page_token and get the next page by calling this endpoint with the returned next_page_token of the last query\nIf there are no more entries the token \"@end\" will be returned\nBy default we return long messages with a trimmed body, if trimmed=false is supplied we return full messages (this reduces the max page_size)",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
"summary": "List all (subscribed) messages",
|
||||
"operationId": "api-messages-list",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "filter",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "next_page_token",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "TODO more filter (sender-name, channel, timestamps, prio, )",
|
||||
"name": "trimmed",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.ListMessages.response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "supplied values/parameters cannot be parsed / are invalid",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "user is not authorized / has missing permissions",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/messages/{mid}": {
|
||||
"delete": {
|
||||
"description": "The user must own the message and request the resource with the ADMIN Key",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
"summary": "Delete a single message",
|
||||
"operationId": "api-messages-delete",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "MessageID",
|
||||
"name": "mid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.MessageJSON"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "supplied values/parameters cannot be parsed / are invalid",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "user is not authorized / has missing permissions",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "message not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "The user must either own the message and request the resource with the READ or ADMIN Key\nOr the user must subscribe to the corresponding channel (and be confirmed) and request the resource with the READ or ADMIN Key\nThe returned message is never trimmed",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
"summary": "Get a single message (untrimmed)",
|
||||
"operationId": "api-messages-get",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "MessageID",
|
||||
"name": "mid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.MessageJSON"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "supplied values/parameters cannot be parsed / are invalid",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "user is not authorized / has missing permissions",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "message not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/ping": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@ -1013,7 +854,166 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users": {
|
||||
"/api/v2/messages": {
|
||||
"get": {
|
||||
"description": "The next_page_token is an opaque token, the special value \"@start\" (or empty-string) is the beginning and \"@end\" is the end\nSimply start the pagination without a next_page_token and get the next page by calling this endpoint with the returned next_page_token of the last query\nIf there are no more entries the token \"@end\" will be returned\nBy default we return long messages with a trimmed body, if trimmed=false is supplied we return full messages (this reduces the max page_size)",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
"summary": "List all (subscribed) messages",
|
||||
"operationId": "api-messages-list",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "filter",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "next_page_token",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "TODO more filter (sender-name, channel, timestamps, prio, )",
|
||||
"name": "trimmed",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.ListMessages.response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "supplied values/parameters cannot be parsed / are invalid",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "user is not authorized / has missing permissions",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/messages/{mid}": {
|
||||
"delete": {
|
||||
"description": "The user must own the message and request the resource with the ADMIN Key",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
"summary": "Delete a single message",
|
||||
"operationId": "api-messages-delete",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "MessageID",
|
||||
"name": "mid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.MessageJSON"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "supplied values/parameters cannot be parsed / are invalid",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "user is not authorized / has missing permissions",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "message not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "The user must either own the message and request the resource with the READ or ADMIN Key\nOr the user must subscribe to the corresponding channel (and be confirmed) and request the resource with the READ or ADMIN Key\nThe returned message is never trimmed",
|
||||
"tags": [
|
||||
"API-v2"
|
||||
],
|
||||
"summary": "Get a single message (untrimmed)",
|
||||
"operationId": "api-messages-get",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "MessageID",
|
||||
"name": "mid",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.MessageJSON"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "supplied values/parameters cannot be parsed / are invalid",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "user is not authorized / has missing permissions",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "message not found",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/ginresp.apiError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v2/users": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -1052,7 +1052,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}": {
|
||||
"/api/v2/users/{uid}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -1191,7 +1191,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/channels": {
|
||||
"/api/v2/users/{uid}/channels": {
|
||||
"get": {
|
||||
"description": "The possible values for 'selector' are:\n- \"owned\" Return all channels of the user\n- \"subscribed\" Return all channels that the user is subscribing to\n- \"all\" Return channels that the user owns or is subscribing\n- \"subscribed_any\" Return all channels that the user is subscribing to (even unconfirmed)\n- \"all_any\" Return channels that the user owns or is subscribing (even unconfirmed)",
|
||||
"tags": [
|
||||
@ -1305,7 +1305,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/channels/{cid}": {
|
||||
"/api/v2/users/{uid}/channels/{cid}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -1441,7 +1441,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/channels/{cid}/messages": {
|
||||
"/api/v2/users/{uid}/channels/{cid}/messages": {
|
||||
"get": {
|
||||
"description": "The next_page_token is an opaque token, the special value \"@start\" (or empty-string) is the beginning and \"@end\" is the end\nSimply start the pagination without a next_page_token and get the next page by calling this endpoint with the returned next_page_token of the last query\nIf there are no more entries the token \"@end\" will be returned\nBy default we return long messages with a trimmed body, if trimmed=false is supplied we return full messages (this reduces the max page_size)",
|
||||
"tags": [
|
||||
@ -1519,7 +1519,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/channels/{cid}/subscriptions": {
|
||||
"/api/v2/users/{uid}/channels/{cid}/subscriptions": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -1576,7 +1576,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/clients": {
|
||||
"/api/v2/users/{uid}/clients": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -1670,7 +1670,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/clients/{cid}": {
|
||||
"/api/v2/users/{uid}/clients/{cid}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -1782,7 +1782,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/subscriptions": {
|
||||
"/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)",
|
||||
"tags": [
|
||||
@ -1898,7 +1898,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/users/{uid}/subscriptions/{sid}": {
|
||||
"/api/v2/users/{uid}/subscriptions/{sid}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"API-v2"
|
||||
@ -2645,7 +2645,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"is_pro": {
|
||||
"type": "integer"
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
|
@ -179,7 +179,7 @@ definitions:
|
||||
handler.Register.response:
|
||||
properties:
|
||||
is_pro:
|
||||
type: integer
|
||||
type: boolean
|
||||
message:
|
||||
type: string
|
||||
quota:
|
||||
@ -823,119 +823,6 @@ paths:
|
||||
summary: Get information about the current user
|
||||
tags:
|
||||
- API-v1
|
||||
/api/messages:
|
||||
get:
|
||||
description: |-
|
||||
The next_page_token is an opaque token, the special value "@start" (or empty-string) is the beginning and "@end" is the end
|
||||
Simply start the pagination without a next_page_token and get the next page by calling this endpoint with the returned next_page_token of the last query
|
||||
If there are no more entries the token "@end" will be returned
|
||||
By default we return long messages with a trimmed body, if trimmed=false is supplied we return full messages (this reduces the max page_size)
|
||||
operationId: api-messages-list
|
||||
parameters:
|
||||
- in: query
|
||||
name: filter
|
||||
type: string
|
||||
- in: query
|
||||
name: next_page_token
|
||||
type: string
|
||||
- in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: TODO more filter (sender-name, channel, timestamps, prio, )
|
||||
in: query
|
||||
name: trimmed
|
||||
type: boolean
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.ListMessages.response'
|
||||
"400":
|
||||
description: supplied values/parameters cannot be parsed / are invalid
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"401":
|
||||
description: user is not authorized / has missing permissions
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
summary: List all (subscribed) messages
|
||||
tags:
|
||||
- API-v2
|
||||
/api/messages/{mid}:
|
||||
delete:
|
||||
description: The user must own the message and request the resource with the
|
||||
ADMIN Key
|
||||
operationId: api-messages-delete
|
||||
parameters:
|
||||
- description: MessageID
|
||||
in: path
|
||||
name: mid
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/models.MessageJSON'
|
||||
"400":
|
||||
description: supplied values/parameters cannot be parsed / are invalid
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"401":
|
||||
description: user is not authorized / has missing permissions
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"404":
|
||||
description: message not found
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
summary: Delete a single message
|
||||
tags:
|
||||
- API-v2
|
||||
patch:
|
||||
description: |-
|
||||
The user must either own the message and request the resource with the READ or ADMIN Key
|
||||
Or the user must subscribe to the corresponding channel (and be confirmed) and request the resource with the READ or ADMIN Key
|
||||
The returned message is never trimmed
|
||||
operationId: api-messages-get
|
||||
parameters:
|
||||
- description: MessageID
|
||||
in: path
|
||||
name: mid
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/models.MessageJSON'
|
||||
"400":
|
||||
description: supplied values/parameters cannot be parsed / are invalid
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"401":
|
||||
description: user is not authorized / has missing permissions
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"404":
|
||||
description: message not found
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
summary: Get a single message (untrimmed)
|
||||
tags:
|
||||
- API-v2
|
||||
/api/ping:
|
||||
delete:
|
||||
responses:
|
||||
@ -1227,7 +1114,120 @@ paths:
|
||||
summary: Upgrade a free account to a paid account
|
||||
tags:
|
||||
- API-v1
|
||||
/api/users:
|
||||
/api/v2/messages:
|
||||
get:
|
||||
description: |-
|
||||
The next_page_token is an opaque token, the special value "@start" (or empty-string) is the beginning and "@end" is the end
|
||||
Simply start the pagination without a next_page_token and get the next page by calling this endpoint with the returned next_page_token of the last query
|
||||
If there are no more entries the token "@end" will be returned
|
||||
By default we return long messages with a trimmed body, if trimmed=false is supplied we return full messages (this reduces the max page_size)
|
||||
operationId: api-messages-list
|
||||
parameters:
|
||||
- in: query
|
||||
name: filter
|
||||
type: string
|
||||
- in: query
|
||||
name: next_page_token
|
||||
type: string
|
||||
- in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: TODO more filter (sender-name, channel, timestamps, prio, )
|
||||
in: query
|
||||
name: trimmed
|
||||
type: boolean
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.ListMessages.response'
|
||||
"400":
|
||||
description: supplied values/parameters cannot be parsed / are invalid
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"401":
|
||||
description: user is not authorized / has missing permissions
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
summary: List all (subscribed) messages
|
||||
tags:
|
||||
- API-v2
|
||||
/api/v2/messages/{mid}:
|
||||
delete:
|
||||
description: The user must own the message and request the resource with the
|
||||
ADMIN Key
|
||||
operationId: api-messages-delete
|
||||
parameters:
|
||||
- description: MessageID
|
||||
in: path
|
||||
name: mid
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/models.MessageJSON'
|
||||
"400":
|
||||
description: supplied values/parameters cannot be parsed / are invalid
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"401":
|
||||
description: user is not authorized / has missing permissions
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"404":
|
||||
description: message not found
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
summary: Delete a single message
|
||||
tags:
|
||||
- API-v2
|
||||
patch:
|
||||
description: |-
|
||||
The user must either own the message and request the resource with the READ or ADMIN Key
|
||||
Or the user must subscribe to the corresponding channel (and be confirmed) and request the resource with the READ or ADMIN Key
|
||||
The returned message is never trimmed
|
||||
operationId: api-messages-get
|
||||
parameters:
|
||||
- description: MessageID
|
||||
in: path
|
||||
name: mid
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/models.MessageJSON'
|
||||
"400":
|
||||
description: supplied values/parameters cannot be parsed / are invalid
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"401":
|
||||
description: user is not authorized / has missing permissions
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"404":
|
||||
description: message not found
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
$ref: '#/definitions/ginresp.apiError'
|
||||
summary: Get a single message (untrimmed)
|
||||
tags:
|
||||
- API-v2
|
||||
/api/v2/users:
|
||||
post:
|
||||
operationId: api-user-create
|
||||
parameters:
|
||||
@ -1252,7 +1252,7 @@ paths:
|
||||
summary: Create a new user
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}:
|
||||
/api/v2/users/{uid}:
|
||||
get:
|
||||
operationId: api-user-get
|
||||
parameters:
|
||||
@ -1343,7 +1343,7 @@ paths:
|
||||
summary: (Partially) update a user
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/channels:
|
||||
/api/v2/users/{uid}/channels:
|
||||
get:
|
||||
description: |-
|
||||
The possible values for 'selector' are:
|
||||
@ -1426,7 +1426,7 @@ paths:
|
||||
summary: Create a new (empty) channel
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/channels/{cid}:
|
||||
/api/v2/users/{uid}/channels/{cid}:
|
||||
get:
|
||||
operationId: api-channels-get
|
||||
parameters:
|
||||
@ -1517,7 +1517,7 @@ paths:
|
||||
summary: (Partially) update a channel
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/channels/{cid}/messages:
|
||||
/api/v2/users/{uid}/channels/{cid}/messages:
|
||||
get:
|
||||
description: |-
|
||||
The next_page_token is an opaque token, the special value "@start" (or empty-string) is the beginning and "@end" is the end
|
||||
@ -1572,7 +1572,7 @@ paths:
|
||||
summary: List messages of a channel
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/channels/{cid}/subscriptions:
|
||||
/api/v2/users/{uid}/channels/{cid}/subscriptions:
|
||||
get:
|
||||
operationId: api-chan-subscriptions-list
|
||||
parameters:
|
||||
@ -1610,7 +1610,7 @@ paths:
|
||||
summary: List all subscriptions of a channel
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/clients:
|
||||
/api/v2/users/{uid}/clients:
|
||||
get:
|
||||
operationId: api-clients-list
|
||||
parameters:
|
||||
@ -1672,7 +1672,7 @@ paths:
|
||||
summary: Add a new clients
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/clients/{cid}:
|
||||
/api/v2/users/{uid}/clients/{cid}:
|
||||
delete:
|
||||
operationId: api-clients-delete
|
||||
parameters:
|
||||
@ -1747,7 +1747,7 @@ paths:
|
||||
summary: Get a single client
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/subscriptions:
|
||||
/api/v2/users/{uid}/subscriptions:
|
||||
get:
|
||||
description: |-
|
||||
The possible values for 'selector' are:
|
||||
@ -1834,7 +1834,7 @@ paths:
|
||||
summary: Create/Request a subscription
|
||||
tags:
|
||||
- API-v2
|
||||
/api/users/{uid}/subscriptions/{sid}:
|
||||
/api/v2/users/{uid}/subscriptions/{sid}:
|
||||
delete:
|
||||
operationId: api-subscriptions-delete
|
||||
parameters:
|
||||
|
@ -463,35 +463,6 @@ func TestCompatExpand(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCompatRequery(t *testing.T) {
|
||||
_, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
r0 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/register.php?fcm_token=%s&pro=%s&pro_token=%s", "DUMMY_FCM", "0", ""))
|
||||
tt.AssertEqual(t, "success", true, r0["success"])
|
||||
|
||||
userid := int64(r0["user_id"].(float64))
|
||||
userkey := r0["user_key"].(string)
|
||||
|
||||
rq1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq1["success"])
|
||||
tt.AssertEqual(t, "count", 0, rq1["count"])
|
||||
tt.AssertStrRepEqual(t, "data", make([]any, 0), rq1["data"])
|
||||
|
||||
r1 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||
"user_id": fmt.Sprintf("%d", userid),
|
||||
"user_key": userkey,
|
||||
"title": "_title_",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r1["success"])
|
||||
|
||||
rq2 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq2["success"])
|
||||
tt.AssertEqual(t, "count", 0, rq2["count"])
|
||||
tt.AssertStrRepEqual(t, "data", make([]any, 0), rq2["data"])
|
||||
|
||||
}
|
||||
|
||||
func TestCompatUpdateUserKey(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
@ -587,3 +558,139 @@ func TestCompatUpgrade(t *testing.T) {
|
||||
tt.AssertEqual(t, "quota_max", 1000, r1["quota_max"])
|
||||
tt.AssertEqual(t, "is_pro", true, r1["is_pro"])
|
||||
}
|
||||
|
||||
func TestCompatRequery(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
r0 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/register.php?fcm_token=%s&pro=%s&pro_token=%s", "DUMMY_FCM", "0", ""))
|
||||
tt.AssertEqual(t, "success", true, r0["success"])
|
||||
|
||||
userid := int64(r0["user_id"].(float64))
|
||||
userkey := r0["user_key"].(string)
|
||||
useridnew := tt.ConvertCompatID(t, ws, userid, "userid")
|
||||
|
||||
rq1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq1["success"])
|
||||
tt.AssertEqual(t, "count", 0, rq1["count"])
|
||||
tt.AssertStrRepEqual(t, "data", make([]any, 0), rq1["data"])
|
||||
|
||||
r1 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||
"user_id": fmt.Sprintf("%d", userid),
|
||||
"user_key": userkey,
|
||||
"title": "_title_",
|
||||
"msg_id": "r1",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r1["success"])
|
||||
|
||||
type respRequery struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
Count int `json:"count"`
|
||||
Data []gin.H `json:"data"`
|
||||
}
|
||||
|
||||
rq2 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq2.Success)
|
||||
tt.AssertEqual(t, "count", 1, rq2.Count)
|
||||
tt.AssertMappedSet(t, "data", []string{"r1"}, rq2.Data, "usr_msg_id")
|
||||
|
||||
rq3 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq3.Success)
|
||||
tt.AssertEqual(t, "count", 1, rq3.Count)
|
||||
tt.AssertMappedSet(t, "data", []string{"r1"}, rq3.Data, "usr_msg_id")
|
||||
|
||||
a2 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, int(r1["scn_msg_id"].(float64))))
|
||||
tt.AssertEqual(t, "success", true, a2["success"])
|
||||
|
||||
rq31 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq31.Success)
|
||||
tt.AssertEqual(t, "count", 0, rq31.Count)
|
||||
|
||||
r2 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||
"user_id": fmt.Sprintf("%d", userid),
|
||||
"user_key": userkey,
|
||||
"title": "_title_",
|
||||
"msg_id": "r2",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r2["success"])
|
||||
|
||||
rq4 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq4.Success)
|
||||
tt.AssertEqual(t, "count", 1, rq4.Count)
|
||||
tt.AssertMappedSet(t, "data", []string{"r2"}, rq4.Data, "usr_msg_id")
|
||||
|
||||
r3 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||
"user_id": fmt.Sprintf("%d", userid),
|
||||
"user_key": userkey,
|
||||
"title": "_title_",
|
||||
"msg_id": "r3",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r3["success"])
|
||||
|
||||
r4 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||
"user_id": fmt.Sprintf("%d", userid),
|
||||
"user_key": userkey,
|
||||
"title": "_title_",
|
||||
"msg_id": "r4",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r4["success"])
|
||||
|
||||
r5 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||
"user_id": fmt.Sprintf("%d", userid),
|
||||
"user_key": userkey,
|
||||
"title": "_title_",
|
||||
"msg_id": "r5",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r5["success"])
|
||||
|
||||
a1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, int(r4["scn_msg_id"].(float64))))
|
||||
tt.AssertEqual(t, "success", true, a1["success"])
|
||||
|
||||
rq5 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq5.Success)
|
||||
tt.AssertEqual(t, "count", 3, rq5.Count)
|
||||
tt.AssertMappedSet(t, "data", []string{"r2", "r3", "r5"}, rq5.Data, "usr_msg_id")
|
||||
|
||||
a7 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, int(r2["scn_msg_id"].(float64))))
|
||||
tt.AssertEqual(t, "success", true, a7["success"])
|
||||
|
||||
a3 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, int(r3["scn_msg_id"].(float64))))
|
||||
tt.AssertEqual(t, "success", true, a3["success"])
|
||||
tt.AssertEqual(t, "prev_ack", 0, a3["prev_ack"])
|
||||
tt.AssertEqual(t, "new_ack", 1, a3["new_ack"])
|
||||
|
||||
a4 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, int(r3["scn_msg_id"].(float64))))
|
||||
tt.AssertEqual(t, "success", true, a4["success"])
|
||||
tt.AssertEqual(t, "prev_ack", 1, a4["prev_ack"])
|
||||
tt.AssertEqual(t, "new_ack", 1, a4["new_ack"])
|
||||
|
||||
a5 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, int(r5["scn_msg_id"].(float64))))
|
||||
tt.AssertEqual(t, "success", true, a5["success"])
|
||||
tt.AssertEqual(t, "prev_ack", 0, a5["prev_ack"])
|
||||
tt.AssertEqual(t, "new_ack", 1, a5["new_ack"])
|
||||
|
||||
r6 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"user_id": useridnew,
|
||||
"user_key": userkey,
|
||||
"title": "HelloWorld_001",
|
||||
"msg_id": "r6",
|
||||
})
|
||||
tt.AssertEqual(t, "success", true, r6["success"])
|
||||
|
||||
rq6 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq6.Success)
|
||||
tt.AssertEqual(t, "count", 1, rq6.Count)
|
||||
tt.AssertMappedSet(t, "data", []string{"r6"}, rq6.Data, "usr_msg_id")
|
||||
|
||||
a6 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, tt.ConvertToCompatID(t, ws, r6["scn_msg_id"].(string))))
|
||||
tt.AssertEqual(t, "success", true, a6["success"])
|
||||
tt.AssertEqual(t, "prev_ack", 0, a6["prev_ack"])
|
||||
tt.AssertEqual(t, "new_ack", 1, a6["new_ack"])
|
||||
tt.AssertEqual(t, "message", "ok", a6["message"])
|
||||
|
||||
rq7 := tt.RequestGet[respRequery](t, baseUrl, fmt.Sprintf("/api/requery.php?user_id=%d&user_key=%s", userid, userkey))
|
||||
tt.AssertEqual(t, "success", true, rq7.Success)
|
||||
tt.AssertEqual(t, "count", 0, rq7.Count)
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,27 @@ func ConvertToCompatID(t *testing.T, ws *logic.Application, newid string) int64
|
||||
return *uidold
|
||||
}
|
||||
|
||||
func ConvertCompatID(t *testing.T, ws *logic.Application, oldid int64, idtype string) string {
|
||||
|
||||
ctx := ws.NewSimpleTransactionContext(5 * time.Second)
|
||||
defer ctx.Cancel()
|
||||
|
||||
idnew, err := ws.Database.Primary.ConvertCompatID(ctx, oldid, idtype)
|
||||
TestFailIfErr(t, err)
|
||||
|
||||
if idnew == nil {
|
||||
TestFail(t, "faile to convert oldid to newid (compat)")
|
||||
}
|
||||
|
||||
err = ctx.CommitTransaction()
|
||||
if err != nil {
|
||||
TestFail(t, "failed to commit")
|
||||
return ""
|
||||
}
|
||||
|
||||
return *idnew
|
||||
}
|
||||
|
||||
func CreateCompatID(t *testing.T, ws *logic.Application, idtype string, newid string) int64 {
|
||||
|
||||
ctx := ws.NewSimpleTransactionContext(5 * time.Second)
|
||||
|
Loading…
Reference in New Issue
Block a user