ListMessages()
This commit is contained in:
parent
0d641b727f
commit
80f3b982d2
2
server/.idea/sqldialects.xml
generated
2
server/.idea/sqldialects.xml
generated
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="SqlDialectMappings">
|
<component name="SqlDialectMappings">
|
||||||
<file url="file://$PROJECT_DIR$/db/schema_3.ddl" dialect="SQLite" />
|
<file url="file://$PROJECT_DIR$/db/schema/schema_3.ddl" dialect="SQLite" />
|
||||||
<file url="PROJECT" dialect="SQLite" />
|
<file url="PROJECT" dialect="SQLite" />
|
||||||
</component>
|
</component>
|
||||||
<component name="SqlResolveMappings">
|
<component name="SqlResolveMappings">
|
||||||
|
@ -11,4 +11,5 @@
|
|||||||
- List subscriptions on owned channels /RESTful?)
|
- List subscriptions on owned channels /RESTful?)
|
||||||
- deploy
|
- deploy
|
||||||
- Dockerfile
|
- Dockerfile
|
||||||
- php in html
|
- php in html
|
||||||
|
- full-text-search: https://www.sqlite.org/fts5.html#contentless_tables
|
@ -12,6 +12,7 @@ const (
|
|||||||
INVALID_PRIO APIError = 1104
|
INVALID_PRIO APIError = 1104
|
||||||
REQ_METHOD APIError = 1105
|
REQ_METHOD APIError = 1105
|
||||||
INVALID_CLIENTTYPE APIError = 1106
|
INVALID_CLIENTTYPE APIError = 1106
|
||||||
|
PAGETOKEN_ERROR APIError = 1120
|
||||||
BINDFAIL_QUERY_PARAM APIError = 1151
|
BINDFAIL_QUERY_PARAM APIError = 1151
|
||||||
BINDFAIL_BODY_PARAM APIError = 1152
|
BINDFAIL_BODY_PARAM APIError = 1152
|
||||||
BINDFAIL_URI_PARAM APIError = 1153
|
BINDFAIL_URI_PARAM APIError = 1153
|
||||||
|
@ -4,11 +4,13 @@ import (
|
|||||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||||
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
|
||||||
"blackforestbytes.com/simplecloudnotifier/db"
|
"blackforestbytes.com/simplecloudnotifier/db"
|
||||||
|
"blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||||
"blackforestbytes.com/simplecloudnotifier/logic"
|
"blackforestbytes.com/simplecloudnotifier/logic"
|
||||||
"blackforestbytes.com/simplecloudnotifier/models"
|
"blackforestbytes.com/simplecloudnotifier/models"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -705,15 +707,15 @@ func (h APIHandler) CancelSubscription(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
// @Summary Creare/Request a subscription
|
// @Summary Creare/Request a subscription
|
||||||
// @ID api-subscriptions-create
|
// @ID api-subscriptions-create
|
||||||
//
|
//
|
||||||
// @Param uid path int true "UserID"
|
// @Param uid path int true "UserID"
|
||||||
// @Param query_data query handler.CreateSubscription.query false " "
|
// @Param query_data query handler.CreateSubscription.query false " "
|
||||||
// @Param post_data body handler.CreateSubscription.body false " "
|
// @Param post_data body handler.CreateSubscription.body false " "
|
||||||
//
|
//
|
||||||
// @Success 200 {object} models.SubscriptionJSON
|
// @Success 200 {object} models.SubscriptionJSON
|
||||||
// @Failure 400 {object} ginresp.apiError
|
// @Failure 400 {object} ginresp.apiError
|
||||||
// @Failure 401 {object} ginresp.apiError
|
// @Failure 401 {object} ginresp.apiError
|
||||||
// @Failure 404 {object} ginresp.apiError
|
// @Failure 404 {object} ginresp.apiError
|
||||||
// @Failure 500 {object} ginresp.apiError
|
// @Failure 500 {object} ginresp.apiError
|
||||||
//
|
//
|
||||||
// @Router /api-v2/users/{uid}/subscriptions [POST]
|
// @Router /api-v2/users/{uid}/subscriptions [POST]
|
||||||
func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
|
func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
|
||||||
@ -820,28 +822,98 @@ func (h APIHandler) UpdateSubscription(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, subscription.JSON()))
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, subscription.JSON()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListMessages swaggerdoc
|
||||||
|
//
|
||||||
|
// @Summary List all (subscribed) messages
|
||||||
|
// @Description The next_page_token is an opaque token, the special value "@start" (or empty-string) is the beginning and "@end" is the end
|
||||||
|
// @Description 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
|
||||||
|
// @Description If there are no more entries the token "@end" will be returned
|
||||||
|
// @Description 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)
|
||||||
|
// @ID api-messages-list
|
||||||
|
//
|
||||||
|
// @Param query_data query handler.ListMessages.query false " "
|
||||||
|
//
|
||||||
|
// @Success 200 {object} handler.ListMessages.response
|
||||||
|
// @Failure 400 {object} ginresp.apiError
|
||||||
|
// @Failure 401 {object} ginresp.apiError
|
||||||
|
// @Failure 404 {object} ginresp.apiError
|
||||||
|
// @Failure 500 {object} ginresp.apiError
|
||||||
|
//
|
||||||
|
// @Router /api-v2/messages [GET]
|
||||||
func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
|
func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
|
||||||
//also update last_read
|
type query struct {
|
||||||
return ginresp.NotImplemented() //TODO
|
PageSize *int `form:"page_size"`
|
||||||
|
NextPageToken *string `form:"next_page_token"`
|
||||||
|
Filter *string `form:"filter"`
|
||||||
|
Trimmed *bool `form:"trimmed"`
|
||||||
|
}
|
||||||
|
type response struct {
|
||||||
|
Messages []models.MessageJSON `json:"messages"`
|
||||||
|
NextPageToken string `json:"next_page_token"`
|
||||||
|
PageSize int `json:"page_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var q query
|
||||||
|
ctx, errResp := h.app.StartRequest(g, nil, &q, nil)
|
||||||
|
if errResp != nil {
|
||||||
|
return *errResp
|
||||||
|
}
|
||||||
|
defer ctx.Cancel()
|
||||||
|
|
||||||
|
trimmed := langext.Coalesce(q.Trimmed, true)
|
||||||
|
|
||||||
|
maxPageSize := langext.Conditional(trimmed, 16, 256)
|
||||||
|
|
||||||
|
pageSize := mathext.Clamp(langext.Coalesce(q.PageSize, 64), 1, maxPageSize)
|
||||||
|
|
||||||
|
if permResp := ctx.CheckPermissionRead(); permResp != nil {
|
||||||
|
return *permResp
|
||||||
|
}
|
||||||
|
|
||||||
|
userid := *ctx.GetPermissionUserID()
|
||||||
|
|
||||||
|
tok, err := cursortoken.Decode(langext.Coalesce(q.NextPageToken, ""))
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.InternAPIError(500, apierr.PAGETOKEN_ERROR, "Failed to decode next_page_token", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.database.UpdateUserLastRead(ctx, userid)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.InternAPIError(500, apierr.DATABASE_ERROR, "Failed to update last-read", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
messages, npt, err := h.database.ListMessages(ctx, userid, pageSize, tok)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.InternAPIError(500, apierr.DATABASE_ERROR, "Failed to query messages", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []models.MessageJSON
|
||||||
|
if trimmed {
|
||||||
|
res = langext.ArrMap(messages, func(v models.Message) models.MessageJSON { return v.TrimmedJSON() })
|
||||||
|
} else {
|
||||||
|
res = langext.ArrMap(messages, func(v models.Message) models.MessageJSON { return v.FullJSON() })
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Messages: res, NextPageToken: npt.Token(), PageSize: pageSize}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMessage swaggerdoc
|
// GetMessage swaggerdoc
|
||||||
//
|
//
|
||||||
// @Summary Get a single message (untrimmed)
|
// @Summary Get a single message (untrimmed)
|
||||||
// @Description The user must either own the message and request the resource with the READ or ADMIN Key
|
// @Description The user must either own the message and request the resource with the READ or ADMIN Key
|
||||||
// @Description Or the user must subscribe to the corresponding channel (and be confirmed) and request the resource with the READ or ADMIN Key
|
// @Description Or the user must subscribe to the corresponding channel (and be confirmed) and request the resource with the READ or ADMIN Key
|
||||||
// @Description The returned message is never trimmed
|
// @Description The returned message is never trimmed
|
||||||
// @ID api-message-get
|
// @ID api-messages-get
|
||||||
//
|
//
|
||||||
// @Param mid path int true "SCNMessageID"
|
// @Param mid path int true "SCNMessageID"
|
||||||
//
|
//
|
||||||
// @Success 200 {object} models.MessageJSON
|
// @Success 200 {object} models.MessageJSON
|
||||||
// @Failure 400 {object} ginresp.apiError
|
// @Failure 400 {object} ginresp.apiError
|
||||||
// @Failure 401 {object} ginresp.apiError
|
// @Failure 401 {object} ginresp.apiError
|
||||||
// @Failure 404 {object} ginresp.apiError
|
// @Failure 404 {object} ginresp.apiError
|
||||||
// @Failure 500 {object} ginresp.apiError
|
// @Failure 500 {object} ginresp.apiError
|
||||||
//
|
//
|
||||||
// @Router /api-v2/messages/{mid} [PATCH]
|
// @Router /api-v2/messages/{mid} [PATCH]
|
||||||
func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
|
func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
|
||||||
type uri struct {
|
type uri struct {
|
||||||
MessageID int64 `uri:"mid"`
|
MessageID int64 `uri:"mid"`
|
||||||
@ -898,19 +970,19 @@ func (h APIHandler) GetMessage(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
|
|
||||||
// DeleteMessage swaggerdoc
|
// DeleteMessage swaggerdoc
|
||||||
//
|
//
|
||||||
// @Summary Delete a single message
|
// @Summary Delete a single message
|
||||||
// @Description The user must own the message and request the resource with the ADMIN Key
|
// @Description The user must own the message and request the resource with the ADMIN Key
|
||||||
// @ID api-message-delete
|
// @ID api-messages-delete
|
||||||
//
|
//
|
||||||
// @Param mid path int true "SCNMessageID"
|
// @Param mid path int true "SCNMessageID"
|
||||||
//
|
//
|
||||||
// @Success 200 {object} models.MessageJSON
|
// @Success 200 {object} models.MessageJSON
|
||||||
// @Failure 400 {object} ginresp.apiError
|
// @Failure 400 {object} ginresp.apiError
|
||||||
// @Failure 401 {object} ginresp.apiError
|
// @Failure 401 {object} ginresp.apiError
|
||||||
// @Failure 404 {object} ginresp.apiError
|
// @Failure 404 {object} ginresp.apiError
|
||||||
// @Failure 500 {object} ginresp.apiError
|
// @Failure 500 {object} ginresp.apiError
|
||||||
//
|
//
|
||||||
// @Router /api-v2/messages/{mid} [PATCH]
|
// @Router /api-v2/messages/{mid} [PATCH]
|
||||||
func (h APIHandler) DeleteMessage(g *gin.Context) ginresp.HTTPResponse {
|
func (h APIHandler) DeleteMessage(g *gin.Context) ginresp.HTTPResponse {
|
||||||
type uri struct {
|
type uri struct {
|
||||||
MessageID int64 `uri:"mid"`
|
MessageID int64 `uri:"mid"`
|
||||||
|
133
server/db/cursortoken/token.go
Normal file
133
server/db/cursortoken/token.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package cursortoken
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base32"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CTMStart = "START"
|
||||||
|
CTMNormal = "NORMAL"
|
||||||
|
CTMEnd = "END"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CursorToken struct {
|
||||||
|
Mode Mode
|
||||||
|
Timestamp int64
|
||||||
|
Id int64
|
||||||
|
Direction string
|
||||||
|
}
|
||||||
|
|
||||||
|
type cursorTokenSerialize struct {
|
||||||
|
Timestamp *int64 `json:"ts,omitempty"`
|
||||||
|
Id *int64 `json:"id,omitempty"`
|
||||||
|
Direction *string `json:"dir,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Start() CursorToken {
|
||||||
|
return CursorToken{
|
||||||
|
Mode: CTMStart,
|
||||||
|
Timestamp: 0,
|
||||||
|
Id: 0,
|
||||||
|
Direction: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func End() CursorToken {
|
||||||
|
return CursorToken{
|
||||||
|
Mode: CTMEnd,
|
||||||
|
Timestamp: 0,
|
||||||
|
Id: 0,
|
||||||
|
Direction: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Normal(ts time.Time, id int64, dir string) CursorToken {
|
||||||
|
return CursorToken{
|
||||||
|
Mode: CTMNormal,
|
||||||
|
Timestamp: ts.UnixMilli(),
|
||||||
|
Id: id,
|
||||||
|
Direction: dir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CursorToken) Token() string {
|
||||||
|
if c.Mode == CTMStart {
|
||||||
|
return "@start"
|
||||||
|
}
|
||||||
|
if c.Mode == CTMEnd {
|
||||||
|
return "@end"
|
||||||
|
}
|
||||||
|
|
||||||
|
// We kinda manually implement omitempty for the CursorToken here
|
||||||
|
// because omitempty does not work for time.Time and otherwise we would always
|
||||||
|
// get weird time values when decoding a token that initially didn't have an Timestamp set
|
||||||
|
// For this usecase we treat Unix=0 as an empty timestamp
|
||||||
|
|
||||||
|
sertok := cursorTokenSerialize{}
|
||||||
|
|
||||||
|
if c.Id != 0 {
|
||||||
|
sertok.Id = &c.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Timestamp != 0 {
|
||||||
|
sertok.Timestamp = &c.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Direction != "" {
|
||||||
|
sertok.Direction = &c.Direction
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := json.Marshal(sertok)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "tok_" + base32.StdEncoding.EncodeToString(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decode(tok string) (CursorToken, error) {
|
||||||
|
if tok == "" {
|
||||||
|
return Start(), nil
|
||||||
|
}
|
||||||
|
if strings.ToLower(tok) == "@start" {
|
||||||
|
return Start(), nil
|
||||||
|
}
|
||||||
|
if strings.ToLower(tok) == "@end" {
|
||||||
|
return End(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(tok, "tok_") {
|
||||||
|
return CursorToken{}, errors.New("could not decode token, missing prefix")
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := base32.StdEncoding.DecodeString(tok[len("tok_"):])
|
||||||
|
if err != nil {
|
||||||
|
return CursorToken{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenDeserialize cursorTokenSerialize
|
||||||
|
err = json.Unmarshal(body, &tokenDeserialize)
|
||||||
|
if err != nil {
|
||||||
|
return CursorToken{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := CursorToken{Mode: CTMNormal}
|
||||||
|
|
||||||
|
if tokenDeserialize.Timestamp != nil {
|
||||||
|
token.Timestamp = *tokenDeserialize.Timestamp
|
||||||
|
}
|
||||||
|
if tokenDeserialize.Id != nil {
|
||||||
|
token.Id = *tokenDeserialize.Id
|
||||||
|
}
|
||||||
|
if tokenDeserialize.Direction != nil {
|
||||||
|
token.Direction = *tokenDeserialize.Direction
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
@ -2,24 +2,15 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
scn "blackforestbytes.com/simplecloudnotifier"
|
scn "blackforestbytes.com/simplecloudnotifier"
|
||||||
|
"blackforestbytes.com/simplecloudnotifier/db/schema"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
_ "embed"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed schema_1.ddl
|
|
||||||
var schema1 string
|
|
||||||
|
|
||||||
//go:embed schema_2.ddl
|
|
||||||
var schema2 string
|
|
||||||
|
|
||||||
//go:embed schema_3.ddl
|
|
||||||
var schema3 string
|
|
||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
}
|
}
|
||||||
@ -37,24 +28,24 @@ func (db *Database) Migrate(ctx context.Context) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 24*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 24*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
schema, err := db.ReadSchema(ctx)
|
currschema, err := db.ReadSchema(ctx)
|
||||||
if schema == 0 {
|
if currschema == 0 {
|
||||||
|
|
||||||
_, err = db.db.ExecContext(ctx, schema3)
|
_, err = db.db.ExecContext(ctx, schema.Schema3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
} else if schema == 1 {
|
} else if currschema == 1 {
|
||||||
return errors.New("cannot autom. upgrade schema 1")
|
return errors.New("cannot autom. upgrade schema 1")
|
||||||
} else if schema == 2 {
|
} else if currschema == 2 {
|
||||||
return errors.New("cannot autom. upgrade schema 2") //TODO
|
return errors.New("cannot autom. upgrade schema 2") //TODO
|
||||||
} else if schema == 3 {
|
} else if currschema == 3 {
|
||||||
return nil // current
|
return nil // current
|
||||||
} else {
|
} else {
|
||||||
return errors.New(fmt.Sprintf("Unknown DB schema: %d", schema))
|
return errors.New(fmt.Sprintf("Unknown DB schema: %d", currschema))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||||
"blackforestbytes.com/simplecloudnotifier/models"
|
"blackforestbytes.com/simplecloudnotifier/models"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -103,3 +105,38 @@ func (db *Database) DeleteMessage(ctx TxContext, scnMessageID int64) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *Database) ListMessages(ctx TxContext, userid int64, pageSize int, inTok cursortoken.CursorToken) ([]models.Message, cursortoken.CursorToken, error) {
|
||||||
|
tx, err := ctx.GetOrCreateTransaction(db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cursortoken.CursorToken{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if inTok.Mode == cursortoken.CTMEnd {
|
||||||
|
return make([]models.Message, 0), cursortoken.End(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pageCond := ""
|
||||||
|
if inTok.Mode == cursortoken.CTMNormal {
|
||||||
|
pageCond = fmt.Sprintf("AND ( timestamp_real < %d OR (timestamp_real = %d AND scn_message_id < %d ) )", inTok.Timestamp, inTok.Timestamp, inTok.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := tx.QueryContext(ctx, "SELECT messages.* FROM messages LEFT JOIN subscriptions subs on messages.channel_id = subs.channel_id WHERE subs.subscriber_user_id = ? AND subs.confirmed = 1 "+pageCond+" ORDER BY timestamp_real DESC LIMIT ?",
|
||||||
|
userid,
|
||||||
|
pageSize+1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cursortoken.CursorToken{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := models.DecodeMessages(rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cursortoken.CursorToken{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) <= pageSize {
|
||||||
|
return data, cursortoken.End(), nil
|
||||||
|
} else {
|
||||||
|
outToken := cursortoken.Normal(data[pageSize-1].TimestampReal, data[pageSize-1].SCNMessageID, "DESC")
|
||||||
|
return data[0:pageSize], outToken, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
12
server/db/schema/assets.go
Normal file
12
server/db/schema/assets.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed schema_1.ddl
|
||||||
|
var Schema1 string
|
||||||
|
|
||||||
|
//go:embed schema_2.ddl
|
||||||
|
var Schema2 string
|
||||||
|
|
||||||
|
//go:embed schema_3.ddl
|
||||||
|
var Schema3 string
|
@ -42,6 +42,18 @@ func (ac *AppContext) CheckPermissionUserRead(userid int64) *ginresp.HTTPRespons
|
|||||||
return langext.Ptr(respoNotAuthorized)
|
return langext.Ptr(respoNotAuthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ac *AppContext) CheckPermissionRead() *ginresp.HTTPResponse {
|
||||||
|
p := ac.permissions
|
||||||
|
if p.UserID != nil && p.KeyType == PermKeyTypeUserRead {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if p.UserID != nil && p.KeyType == PermKeyTypeUserAdmin {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return langext.Ptr(respoNotAuthorized)
|
||||||
|
}
|
||||||
|
|
||||||
func (ac *AppContext) CheckPermissionUserAdmin(userid int64) *ginresp.HTTPResponse {
|
func (ac *AppContext) CheckPermissionUserAdmin(userid int64) *ginresp.HTTPResponse {
|
||||||
p := ac.permissions
|
p := ac.permissions
|
||||||
if p.UserID != nil && *p.UserID == userid && p.KeyType == PermKeyTypeUserAdmin {
|
if p.UserID != nil && *p.UserID == userid && p.KeyType == PermKeyTypeUserAdmin {
|
||||||
|
@ -11,16 +11,22 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
"post": {
|
"post": {
|
||||||
|
"description": "All parameter can be set via query-parameter or the json body. Only UserID, UserKey and Title are required",
|
||||||
"summary": "Send a new message",
|
"summary": "Send a new message",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"name": "message_content",
|
"name": "chanKey",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"name": "message_title",
|
"name": "channel",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "content",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -29,25 +35,30 @@
|
|||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "number",
|
||||||
"name": "sendTimestamp",
|
"name": "sendTimestamp",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "title",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "userID",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "userKey",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"name": "userMessageID",
|
"name": "userMessageID",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"name": "user_id",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"name": "user_key",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": " ",
|
"description": " ",
|
||||||
"name": "post_body",
|
"name": "post_body",
|
||||||
@ -61,7 +72,122 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.ClientJSON"
|
"$ref": "#/definitions/handler.SendMessage.response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/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)",
|
||||||
|
"summary": "List all (subscribed) messages",
|
||||||
|
"operationId": "api-messages-list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "filter",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "nextPageToken",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "pageSize",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"name": "trimmed",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.ListMessages.response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api-v2/messages/{mid}": {
|
||||||
|
"patch": {
|
||||||
|
"description": "The user must own the message and request the resource with the ADMIN Key",
|
||||||
|
"summary": "Delete a single message",
|
||||||
|
"operationId": "api-messages-delete",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "SCNMessageID",
|
||||||
|
"name": "mid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.MessageJSON"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@ -221,6 +347,161 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api-v2/users/{uid}/channels": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all channels of a user",
|
||||||
|
"operationId": "api-channels-list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.ListChannels.response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api-v2/users/{uid}/channels/{cid}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all channels of a user",
|
||||||
|
"operationId": "api-channels-get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ChannelID",
|
||||||
|
"name": "cid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.ChannelJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api-v2/users/{uid}/channels/{cid}/subscriptions": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all subscriptions of a channel",
|
||||||
|
"operationId": "api-chan-subscriptions-list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ChannelID",
|
||||||
|
"name": "cid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.ListChannelSubscriptions.response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api-v2/users/{uid}/clients": {
|
"/api-v2/users/{uid}/clients": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "List all clients",
|
"summary": "List all clients",
|
||||||
@ -238,7 +519,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/handler.ListClients.result"
|
"$ref": "#/definitions/handler.ListClients.response"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@ -374,6 +655,269 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api-v2/users/{uid}/subscriptions": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List all channels of a user",
|
||||||
|
"operationId": "api-user-subscriptions-list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.ListUserSubscriptions.response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"summary": "Creare/Request a subscription",
|
||||||
|
"operationId": "api-subscriptions-create",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "chanSubscribeKey",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": " ",
|
||||||
|
"name": "post_data",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.CreateSubscription.body"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.SubscriptionJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api-v2/users/{uid}/subscriptions/{sid}": {
|
||||||
|
"get": {
|
||||||
|
"summary": "Get a single subscription",
|
||||||
|
"operationId": "api-subscriptions-get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "SubscriptionID",
|
||||||
|
"name": "sid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.SubscriptionJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"summary": "Cancel (delete) subscription",
|
||||||
|
"operationId": "api-subscriptions-delete",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "SubscriptionID",
|
||||||
|
"name": "sid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.SubscriptionJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"summary": "Update a subscription (e.g. confirm)",
|
||||||
|
"operationId": "api-subscriptions-update",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "UserID",
|
||||||
|
"name": "uid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "SubscriptionID",
|
||||||
|
"name": "sid",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/models.SubscriptionJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/ack.php": {
|
"/api/ack.php": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "Acknowledge that a message was received",
|
"summary": "Acknowledge that a message was received",
|
||||||
@ -773,16 +1317,22 @@
|
|||||||
},
|
},
|
||||||
"/send": {
|
"/send": {
|
||||||
"post": {
|
"post": {
|
||||||
|
"description": "All parameter can be set via query-parameter or the json body. Only UserID, UserKey and Title are required",
|
||||||
"summary": "Send a new message",
|
"summary": "Send a new message",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"name": "message_content",
|
"name": "chanKey",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"name": "message_title",
|
"name": "channel",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "content",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -791,25 +1341,30 @@
|
|||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "number",
|
||||||
"name": "sendTimestamp",
|
"name": "sendTimestamp",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "title",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"name": "userID",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"name": "userKey",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"name": "userMessageID",
|
"name": "userMessageID",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"name": "user_id",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"name": "user_key",
|
|
||||||
"in": "query"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": " ",
|
"description": " ",
|
||||||
"name": "post_body",
|
"name": "post_body",
|
||||||
@ -823,7 +1378,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.ClientJSON"
|
"$ref": "#/definitions/handler.SendMessage.response"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
@ -838,6 +1393,12 @@
|
|||||||
"$ref": "#/definitions/ginresp.apiError"
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Not Found",
|
"description": "Not Found",
|
||||||
"schema": {
|
"schema": {
|
||||||
@ -907,6 +1468,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handler.CreateSubscription.body": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"channel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"channelOwnerUserID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handler.CreateUser.body": {
|
"handler.CreateUser.body": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1001,7 +1573,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handler.ListClients.result": {
|
"handler.ListChannelSubscriptions.response": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"subscriptions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.SubscriptionJSON"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handler.ListChannels.response": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"channels": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.ChannelJSON"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handler.ListClients.response": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"clients": {
|
"clients": {
|
||||||
@ -1012,6 +1606,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handler.ListMessages.response": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"messages": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.MessageJSON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"next_page_token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"page_size": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handler.ListUserSubscriptions.response": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"subscriptions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/models.SubscriptionJSON"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handler.Register.response": {
|
"handler.Register.response": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1061,29 +1683,70 @@
|
|||||||
"handler.SendMessage.body": {
|
"handler.SendMessage.body": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"chanKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"channel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"message_content": {
|
"message_content": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"message_title": {
|
"message_title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"msg_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"priority": {
|
"priority": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"sendTimestamp": {
|
"timestamp": {
|
||||||
"type": "integer"
|
"type": "number"
|
||||||
},
|
|
||||||
"userMessageID": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"type": "string"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"user_key": {
|
"user_key": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handler.SendMessage.response": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"errhighlight": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_pro": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"messagecount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"quota": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"quota_max": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"scn_msg_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"suppress_send": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handler.Update.response": {
|
"handler.Update.response": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1172,6 +1835,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.ChannelJSON": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"channel_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"messages_sent": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"owner_user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"send_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"subscribe_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp_created": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp_last_sent": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.ClientJSON": {
|
"models.ClientJSON": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1221,6 +1913,44 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.MessageJSON": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"body": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"channel_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"channel_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"owner_user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"scn_message_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"sender_user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"trimmed": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"usr_message_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.ShortCompatMessage": {
|
"models.ShortCompatMessage": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1247,6 +1977,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"models.SubscriptionJSON": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"channel_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"channel_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"channel_owner_user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"confirmed": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"subscriber_user_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"subscription_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"timestamp_created": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"models.UserJSON": {
|
"models.UserJSON": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -1259,12 +2015,12 @@
|
|||||||
"messages_sent": {
|
"messages_sent": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"quota_day": {
|
"quota_used": {
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"quota_today": {
|
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"quota_used_day": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"read_key": {
|
"read_key": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -34,6 +34,13 @@ definitions:
|
|||||||
fcm_token:
|
fcm_token:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
handler.CreateSubscription.body:
|
||||||
|
properties:
|
||||||
|
channel:
|
||||||
|
type: string
|
||||||
|
channelOwnerUserID:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
handler.CreateUser.body:
|
handler.CreateUser.body:
|
||||||
properties:
|
properties:
|
||||||
agent_model:
|
agent_model:
|
||||||
@ -95,13 +102,45 @@ definitions:
|
|||||||
user_key:
|
user_key:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
handler.ListClients.result:
|
handler.ListChannelSubscriptions.response:
|
||||||
|
properties:
|
||||||
|
subscriptions:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/models.SubscriptionJSON'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
handler.ListChannels.response:
|
||||||
|
properties:
|
||||||
|
channels:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/models.ChannelJSON'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
handler.ListClients.response:
|
||||||
properties:
|
properties:
|
||||||
clients:
|
clients:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/models.ClientJSON'
|
$ref: '#/definitions/models.ClientJSON'
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
|
handler.ListMessages.response:
|
||||||
|
properties:
|
||||||
|
messages:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/models.MessageJSON'
|
||||||
|
type: array
|
||||||
|
next_page_token:
|
||||||
|
type: string
|
||||||
|
page_size:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
handler.ListUserSubscriptions.response:
|
||||||
|
properties:
|
||||||
|
subscriptions:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/models.SubscriptionJSON'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
handler.Register.response:
|
handler.Register.response:
|
||||||
properties:
|
properties:
|
||||||
is_pro:
|
is_pro:
|
||||||
@ -134,20 +173,47 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
handler.SendMessage.body:
|
handler.SendMessage.body:
|
||||||
properties:
|
properties:
|
||||||
|
chanKey:
|
||||||
|
type: string
|
||||||
|
channel:
|
||||||
|
type: string
|
||||||
message_content:
|
message_content:
|
||||||
type: string
|
type: string
|
||||||
message_title:
|
message_title:
|
||||||
type: string
|
type: string
|
||||||
|
msg_id:
|
||||||
|
type: string
|
||||||
priority:
|
priority:
|
||||||
type: integer
|
type: integer
|
||||||
sendTimestamp:
|
timestamp:
|
||||||
type: integer
|
type: number
|
||||||
user_id:
|
user_id:
|
||||||
type: string
|
type: integer
|
||||||
user_key:
|
user_key:
|
||||||
type: string
|
type: string
|
||||||
userMessageID:
|
type: object
|
||||||
|
handler.SendMessage.response:
|
||||||
|
properties:
|
||||||
|
errhighlight:
|
||||||
|
type: integer
|
||||||
|
error:
|
||||||
|
type: integer
|
||||||
|
is_pro:
|
||||||
|
type: boolean
|
||||||
|
message:
|
||||||
type: string
|
type: string
|
||||||
|
messagecount:
|
||||||
|
type: integer
|
||||||
|
quota:
|
||||||
|
type: integer
|
||||||
|
quota_max:
|
||||||
|
type: integer
|
||||||
|
scn_msg_id:
|
||||||
|
type: integer
|
||||||
|
success:
|
||||||
|
type: boolean
|
||||||
|
suppress_send:
|
||||||
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
handler.Update.response:
|
handler.Update.response:
|
||||||
properties:
|
properties:
|
||||||
@ -206,6 +272,25 @@ definitions:
|
|||||||
uri:
|
uri:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.ChannelJSON:
|
||||||
|
properties:
|
||||||
|
channel_id:
|
||||||
|
type: integer
|
||||||
|
messages_sent:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
owner_user_id:
|
||||||
|
type: integer
|
||||||
|
send_key:
|
||||||
|
type: string
|
||||||
|
subscribe_key:
|
||||||
|
type: string
|
||||||
|
timestamp_created:
|
||||||
|
type: string
|
||||||
|
timestamp_last_sent:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
models.ClientJSON:
|
models.ClientJSON:
|
||||||
properties:
|
properties:
|
||||||
agent_model:
|
agent_model:
|
||||||
@ -238,6 +323,31 @@ definitions:
|
|||||||
usr_msg_id:
|
usr_msg_id:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.MessageJSON:
|
||||||
|
properties:
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
channel_id:
|
||||||
|
type: integer
|
||||||
|
channel_name:
|
||||||
|
type: string
|
||||||
|
owner_user_id:
|
||||||
|
type: integer
|
||||||
|
priority:
|
||||||
|
type: integer
|
||||||
|
scn_message_id:
|
||||||
|
type: integer
|
||||||
|
sender_user_id:
|
||||||
|
type: integer
|
||||||
|
timestamp:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
trimmed:
|
||||||
|
type: boolean
|
||||||
|
usr_message_id:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
models.ShortCompatMessage:
|
models.ShortCompatMessage:
|
||||||
properties:
|
properties:
|
||||||
body:
|
body:
|
||||||
@ -255,6 +365,23 @@ definitions:
|
|||||||
usr_msg_id:
|
usr_msg_id:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
models.SubscriptionJSON:
|
||||||
|
properties:
|
||||||
|
channel_id:
|
||||||
|
type: integer
|
||||||
|
channel_name:
|
||||||
|
type: string
|
||||||
|
channel_owner_user_id:
|
||||||
|
type: integer
|
||||||
|
confirmed:
|
||||||
|
type: boolean
|
||||||
|
subscriber_user_id:
|
||||||
|
type: integer
|
||||||
|
subscription_id:
|
||||||
|
type: integer
|
||||||
|
timestamp_created:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
models.UserJSON:
|
models.UserJSON:
|
||||||
properties:
|
properties:
|
||||||
admin_key:
|
admin_key:
|
||||||
@ -263,10 +390,10 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
messages_sent:
|
messages_sent:
|
||||||
type: integer
|
type: integer
|
||||||
quota_day:
|
quota_used:
|
||||||
type: string
|
|
||||||
quota_today:
|
|
||||||
type: integer
|
type: integer
|
||||||
|
quota_used_day:
|
||||||
|
type: string
|
||||||
read_key:
|
read_key:
|
||||||
type: string
|
type: string
|
||||||
send_key:
|
send_key:
|
||||||
@ -291,28 +418,36 @@ info:
|
|||||||
paths:
|
paths:
|
||||||
/:
|
/:
|
||||||
post:
|
post:
|
||||||
|
description: All parameter can be set via query-parameter or the json body.
|
||||||
|
Only UserID, UserKey and Title are required
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: message_content
|
name: chanKey
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: message_title
|
name: channel
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: content
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: priority
|
name: priority
|
||||||
type: integer
|
type: integer
|
||||||
- in: query
|
- in: query
|
||||||
name: sendTimestamp
|
name: sendTimestamp
|
||||||
|
type: number
|
||||||
|
- in: query
|
||||||
|
name: title
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: userID
|
||||||
type: integer
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: userKey
|
||||||
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: userMessageID
|
name: userMessageID
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
|
||||||
name: user_id
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: user_key
|
|
||||||
type: string
|
|
||||||
- description: ' '
|
- description: ' '
|
||||||
in: body
|
in: body
|
||||||
name: post_body
|
name: post_body
|
||||||
@ -322,7 +457,54 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/models.ClientJSON'
|
$ref: '#/definitions/handler.SendMessage.response'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Send a new message
|
||||||
|
/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: nextPageToken
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: pageSize
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: trimmed
|
||||||
|
type: boolean
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handler.ListMessages.response'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
@ -339,7 +521,40 @@ paths:
|
|||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/ginresp.apiError'
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
summary: Send a new message
|
summary: List all (subscribed) messages
|
||||||
|
/api-v2/messages/{mid}:
|
||||||
|
patch:
|
||||||
|
description: The user must own the message and request the resource with the
|
||||||
|
ADMIN Key
|
||||||
|
operationId: api-messages-delete
|
||||||
|
parameters:
|
||||||
|
- description: SCNMessageID
|
||||||
|
in: path
|
||||||
|
name: mid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.MessageJSON'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Delete a single message
|
||||||
/api-v2/users/:
|
/api-v2/users/:
|
||||||
post:
|
post:
|
||||||
operationId: api-user-create
|
operationId: api-user-create
|
||||||
@ -425,6 +640,109 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/ginresp.apiError'
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
summary: (Partially) update a user
|
summary: (Partially) update a user
|
||||||
|
/api-v2/users/{uid}/channels:
|
||||||
|
get:
|
||||||
|
operationId: api-channels-list
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handler.ListChannels.response'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: List all channels of a user
|
||||||
|
/api-v2/users/{uid}/channels/{cid}:
|
||||||
|
get:
|
||||||
|
operationId: api-channels-get
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: ChannelID
|
||||||
|
in: path
|
||||||
|
name: cid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.ChannelJSON'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: List all channels of a user
|
||||||
|
/api-v2/users/{uid}/channels/{cid}/subscriptions:
|
||||||
|
get:
|
||||||
|
operationId: api-chan-subscriptions-list
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: ChannelID
|
||||||
|
in: path
|
||||||
|
name: cid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handler.ListChannelSubscriptions.response'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: List all subscriptions of a channel
|
||||||
/api-v2/users/{uid}/clients:
|
/api-v2/users/{uid}/clients:
|
||||||
get:
|
get:
|
||||||
operationId: api-clients-list
|
operationId: api-clients-list
|
||||||
@ -438,7 +756,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/handler.ListClients.result'
|
$ref: '#/definitions/handler.ListClients.response'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
@ -527,6 +845,181 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/ginresp.apiError'
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
summary: Get a single clients
|
summary: Get a single clients
|
||||||
|
/api-v2/users/{uid}/subscriptions:
|
||||||
|
get:
|
||||||
|
operationId: api-user-subscriptions-list
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handler.ListUserSubscriptions.response'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: List all channels of a user
|
||||||
|
post:
|
||||||
|
operationId: api-subscriptions-create
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: chanSubscribeKey
|
||||||
|
type: string
|
||||||
|
- description: ' '
|
||||||
|
in: body
|
||||||
|
name: post_data
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handler.CreateSubscription.body'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.SubscriptionJSON'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Creare/Request a subscription
|
||||||
|
/api-v2/users/{uid}/subscriptions/{sid}:
|
||||||
|
delete:
|
||||||
|
operationId: api-subscriptions-delete
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: SubscriptionID
|
||||||
|
in: path
|
||||||
|
name: sid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.SubscriptionJSON'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Cancel (delete) subscription
|
||||||
|
get:
|
||||||
|
operationId: api-subscriptions-get
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: SubscriptionID
|
||||||
|
in: path
|
||||||
|
name: sid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.SubscriptionJSON'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Get a single subscription
|
||||||
|
patch:
|
||||||
|
operationId: api-subscriptions-update
|
||||||
|
parameters:
|
||||||
|
- description: UserID
|
||||||
|
in: path
|
||||||
|
name: uid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: SubscriptionID
|
||||||
|
in: path
|
||||||
|
name: sid
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/models.SubscriptionJSON'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Update a subscription (e.g. confirm)
|
||||||
/api/ack.php:
|
/api/ack.php:
|
||||||
get:
|
get:
|
||||||
operationId: compat-ack
|
operationId: compat-ack
|
||||||
@ -790,28 +1283,36 @@ paths:
|
|||||||
$ref: '#/definitions/ginresp.apiError'
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
/send:
|
/send:
|
||||||
post:
|
post:
|
||||||
|
description: All parameter can be set via query-parameter or the json body.
|
||||||
|
Only UserID, UserKey and Title are required
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: message_content
|
name: chanKey
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: message_title
|
name: channel
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: content
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: priority
|
name: priority
|
||||||
type: integer
|
type: integer
|
||||||
- in: query
|
- in: query
|
||||||
name: sendTimestamp
|
name: sendTimestamp
|
||||||
|
type: number
|
||||||
|
- in: query
|
||||||
|
name: title
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: userID
|
||||||
type: integer
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: userKey
|
||||||
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: userMessageID
|
name: userMessageID
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
|
||||||
name: user_id
|
|
||||||
type: string
|
|
||||||
- in: query
|
|
||||||
name: user_key
|
|
||||||
type: string
|
|
||||||
- description: ' '
|
- description: ' '
|
||||||
in: body
|
in: body
|
||||||
name: post_body
|
name: post_body
|
||||||
@ -821,7 +1322,7 @@ paths:
|
|||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/models.ClientJSON'
|
$ref: '#/definitions/handler.SendMessage.response'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
@ -830,6 +1331,10 @@ paths:
|
|||||||
description: Unauthorized
|
description: Unauthorized
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/ginresp.apiError'
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
"404":
|
"404":
|
||||||
description: Not Found
|
description: Not Found
|
||||||
schema:
|
schema:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user