added template for new golang backend

This commit is contained in:
2022-11-13 19:17:07 +01:00
parent bd11d7973c
commit 0e58a5c5f0
36 changed files with 2908 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
package apierr
type APIError int
const (
NO_ERROR APIError = 0000
MISSING_UID APIError = 1101
MISSING_TOK APIError = 1102
MISSING_TITLE APIError = 1103
INVALID_PRIO APIError = 1104
REQ_METHOD APIError = 1105
NO_TITLE APIError = 1201
TITLE_TOO_LONG APIError = 1202
CONTENT_TOO_LONG APIError = 1203
USR_MSG_ID_TOO_LONG APIError = 1204
TIMESTAMP_OUT_OF_RANGE APIError = 1205
USER_NOT_FOUND APIError = 1301
USER_AUTH_FAILED APIError = 1302
NO_DEVICE_LINKED APIError = 1401
QUOTA_REACHED APIError = 2101
FIREBASE_COM_FAILED APIError = 9901
FIREBASE_COM_ERRORED APIError = 9902
INTERNAL_EXCEPTION APIError = 9903
)

View File

@@ -0,0 +1,98 @@
package handler
import (
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
"blackforestbytes.com/simplecloudnotifier/logic"
"bytes"
"github.com/gin-gonic/gin"
sqlite3 "github.com/mattn/go-sqlite3"
"net/http"
)
type CommonHandler struct {
app *logic.Application
}
func NewCommonHandler(app *logic.Application) CommonHandler {
return CommonHandler{
app: app,
}
}
type pingResponse struct {
Message string `json:"message"`
Info pingResponseInfo `json:"info"`
}
type pingResponseInfo struct {
Method string `json:"method"`
Request string `json:"request"`
Headers map[string][]string `json:"headers"`
URI string `json:"uri"`
Address string `json:"addr"`
}
// Ping swaggerdoc
//
// @Success 200 {object} pingResponse
// @Failure 500 {object} ginresp.errBody
// @Router /ping [get]
// @Router /ping [post]
// @Router /ping [put]
// @Router /ping [delete]
// @Router /ping [patch]
func (h CommonHandler) Ping(g *gin.Context) ginresp.HTTPResponse {
buf := new(bytes.Buffer)
_, _ = buf.ReadFrom(g.Request.Body)
resuestBody := buf.String()
return ginresp.JSON(http.StatusOK, pingResponse{
Message: "Pong",
Info: pingResponseInfo{
Method: g.Request.Method,
Request: resuestBody,
Headers: g.Request.Header,
URI: g.Request.RequestURI,
Address: g.Request.RemoteAddr,
},
})
}
// DatabaseTest swaggerdoc
//
// @Success 200 {object} handler.DatabaseTest.response
// @Failure 500 {object} ginresp.errBody
// @Router /db-test [get]
func (h CommonHandler) DatabaseTest(g *gin.Context) ginresp.HTTPResponse {
type response struct {
Success bool `json:"success"`
LibVersion string `json:"libVersion"`
LibVersionNumber int `json:"libVersionNumber"`
SourceID string `json:"sourceID"`
}
libVersion, libVersionNumber, sourceID := sqlite3.Version()
err := h.app.Database.Ping()
if err != nil {
return ginresp.InternalError(err)
}
return ginresp.JSON(http.StatusOK, response{
Success: true,
LibVersion: libVersion,
LibVersionNumber: libVersionNumber,
SourceID: sourceID,
})
}
// Health swaggerdoc
//
// @Success 200 {object} handler.Health.response
// @Failure 500 {object} ginresp.errBody
// @Router /health [get]
func (h CommonHandler) Health(*gin.Context) ginresp.HTTPResponse {
type response struct {
Status string `json:"status"`
}
return ginresp.JSON(http.StatusOK, response{Status: "ok"})
}

View File

@@ -0,0 +1,248 @@
package handler
import (
"blackforestbytes.com/simplecloudnotifier/api/apierr"
"blackforestbytes.com/simplecloudnotifier/api/models"
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
"blackforestbytes.com/simplecloudnotifier/logic"
"github.com/gin-gonic/gin"
)
type CompatHandler struct {
app *logic.Application
}
func NewCompatHandler(app *logic.Application) CompatHandler {
return CompatHandler{
app: app,
}
}
// Register swaggerdoc
//
// @Summary Register a new account
// @Param fcm_token query string true "the (android) fcm token"
// @Param pro query string true "if the user is a paid account" Enums(true, false)
// @Param pro_token query string true "the (android) IAP token"
// @Success 200 {object} handler.Register.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /register.php [get]
func (h CompatHandler) Register(g *gin.Context) ginresp.HTTPResponse {
type query struct {
FCMToken string `form:"fcm_token"`
Pro string `form:"pro"`
ProToken string `form:"pro_token"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
UserID string `json:"user_id"`
UserKey string `json:"user_key"`
QuotaUsed string `json:"quota"`
QuotaMax string `json:"quota_max"`
IsPro string `json:"is_pro"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Info swaggerdoc
//
// @Summary Get information about the current user
// @Param user_id query string true "the user_id"
// @Param user_key query string true "the user_key"
// @Success 200 {object} handler.Info.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /info.php [get]
func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
type query struct {
UserID string `form:"user_id"`
UserKey string `form:"user_key"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
UserID string `json:"user_id"`
UserKey string `json:"user_key"`
QuotaUsed string `json:"quota"`
QuotaMax string `json:"quota_max"`
IsPro string `json:"is_pro"`
FCMSet bool `json:"fcm_token_set"`
UnackCount int `json:"unack_count"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Ack swaggerdoc
//
// @Summary Acknowledge that a message was received
// @Param user_id query string true "the user_id"
// @Param user_key query string true "the user_key"
// @Param scn_msg_id query string true "the message id"
// @Success 200 {object} handler.Ack.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /ack.php [get]
func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
type query struct {
UserID string `form:"user_id"`
UserKey string `form:"user_key"`
MessageID string `form:"scn_msg_id"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
PrevAckValue int `json:"prev_ack"`
NewAckValue int `json:"new_ack"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Requery swaggerdoc
//
// @Summary Return all not-acknowledged messages
// @Param user_id query string true "the user_id"
// @Param user_key query string true "the user_key"
// @Success 200 {object} handler.Requery.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /requery.php [get]
func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
type query struct {
UserID string `form:"user_id"`
UserKey string `form:"user_key"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
Count int `json:"count"`
Data []models.CompatMessage `json:"data"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Update swaggerdoc
//
// @Summary Set the fcm-token (android)
// @Param user_id query string true "the user_id"
// @Param user_key query string true "the user_key"
// @Param fcm_token query string true "the (android) fcm token"
// @Success 200 {object} handler.Update.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /update.php [get]
func (h CompatHandler) Update(g *gin.Context) ginresp.HTTPResponse {
type query struct {
UserID string `form:"user_id"`
UserKey string `form:"user_key"`
FCMToken string `form:"fcm_token"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
UserID string `json:"user_id"`
UserKey string `json:"user_key"`
QuotaUsed string `json:"quota"`
QuotaMax string `json:"quota_max"`
IsPro string `json:"is_pro"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Expand swaggerdoc
//
// @Summary Get a whole (potentially truncated) message
// @Success 200 {object} handler.Expand.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /expand.php [get]
func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
type query struct {
UserID string `form:"user_id"`
UserKey string `form:"user_key"`
MessageID string `form:"scn_msg_id"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
Data models.ShortCompatMessage `json:"data"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Upgrade swaggerdoc
//
// @Summary Upgrade a free account to a paid account
// @Param user_id query string true "the user_id"
// @Param user_key query string true "the user_key"
// @Param pro query string true "if the user is a paid account" Enums(true, false)
// @Param pro_token query string true "the (android) IAP token"
// @Success 200 {object} handler.Upgrade.response
// @Failure 500 {object} ginresp.internAPIError
// @Router /upgrade.php [get]
func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
type query struct {
UserID string `form:"user_id"`
UserKey string `form:"user_key"`
Pro string `form:"pro"`
ProToken string `form:"pro_token"`
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
Data models.ShortCompatMessage `json:"data"`
}
//TODO
return ginresp.NotImplemented(0)
}
// Send swaggerdoc
//
// @Summary Send a message
// @Description all aeguments can either be supplied in the query or in the json body
// @Param user_id query string true "the user_id"
// @Param user_key query string true "the user_key"
// @Param title query string true "The message title"
// @Param content query string false "The message content"
// @Param priority query string false "The message priority" Enum(0, 1, 2)
// @Param msg_id query string false "The message idempotency id"
// @Param timestamp query string false "The message timestamp"
// @Param user_id body string true "the user_id"
// @Param user_key body string true "the user_key"
// @Param title body string true "The message title"
// @Param content body string false "The message content"
// @Param priority body string false "The message priority" Enum(0, 1, 2)
// @Param msg_id body string false "The message idempotency id"
// @Param timestamp body string false "The message timestamp"
// @Success 200 {object} handler.Send.response
// @Failure 500 {object} ginresp.sendAPIError
// @Router /send.php [post]
func (h CompatHandler) Send(g *gin.Context) ginresp.HTTPResponse {
type query struct {
//TODO
}
type response struct {
Success string `json:"success"`
Message string `json:"message"`
//TODO
}
//TODO
return ginresp.SendAPIError(apierr.INTERNAL_EXCEPTION, -1, "NotImplemented")
}

View File

@@ -0,0 +1,20 @@
package models
type CompatMessage struct {
Title string `json:"title"`
Body string `json:"body"`
Priority int `json:"priority"`
Timestamp int64 `json:"timestamp"`
UserMessageID string `json:"usr_msg_id"`
SCNMessageID string `json:"scn_msg_id"`
}
type ShortCompatMessage struct {
Title string `json:"title"`
Body string `json:"body"`
Trimmed bool `json:"trimmed"`
Priority int `json:"priority"`
Timestamp int64 `json:"timestamp"`
UserMessageID string `json:"usr_msg_id"`
SCNMessageID string `json:"scn_msg_id"`
}

52
server/api/router.go Normal file
View File

@@ -0,0 +1,52 @@
package api
import (
"blackforestbytes.com/simplecloudnotifier/api/handler"
"blackforestbytes.com/simplecloudnotifier/common/ginext"
"blackforestbytes.com/simplecloudnotifier/common/ginresp"
"blackforestbytes.com/simplecloudnotifier/logic"
"blackforestbytes.com/simplecloudnotifier/swagger"
"github.com/gin-gonic/gin"
)
type Router struct {
app *logic.Application
commonHandler handler.CommonHandler
compatHandler handler.CompatHandler
}
func NewRouter(app *logic.Application) *Router {
return &Router{
app: app,
commonHandler: handler.NewCommonHandler(app),
compatHandler: handler.NewCompatHandler(app),
}
}
// Init swaggerdocs
// @title SimpleCloudNotifier API
// @version 2.0
// @description API for SCN
// @host scn.blackforestbytes.com
// @BasePath /api/
func (r *Router) Init(e *gin.Engine) {
e.Any("/ping", ginresp.Wrap(r.commonHandler.Ping))
e.POST("/db-test", ginresp.Wrap(r.commonHandler.DatabaseTest))
e.GET("/health", ginresp.Wrap(r.commonHandler.Health))
e.GET("documentation/swagger", ginext.RedirectTemporary("/documentation/swagger/"))
e.GET("documentation/swagger/", ginresp.Wrap(swagger.Handle))
e.GET("documentation/swagger/:fn", ginresp.Wrap(swagger.Handle))
e.POST("/send.php", ginresp.Wrap(r.compatHandler.Send))
e.GET("/register.php", ginresp.Wrap(r.compatHandler.Register))
e.GET("/info.php", ginresp.Wrap(r.compatHandler.Info))
e.GET("/ack.php", ginresp.Wrap(r.compatHandler.Ack))
e.GET("/requery.php", ginresp.Wrap(r.compatHandler.Requery))
e.GET("/update.php", ginresp.Wrap(r.compatHandler.Update))
e.GET("/expand.php", ginresp.Wrap(r.compatHandler.Expand))
e.GET("/upgrade.php", ginresp.Wrap(r.compatHandler.Upgrade))
}