added template for new golang backend
This commit is contained in:
30
server/api/apierr/enums.go
Normal file
30
server/api/apierr/enums.go
Normal 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
|
||||
)
|
98
server/api/handler/common.go
Normal file
98
server/api/handler/common.go
Normal 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"})
|
||||
}
|
248
server/api/handler/compat.go
Normal file
248
server/api/handler/compat.go
Normal 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")
|
||||
}
|
20
server/api/models/compat.go
Normal file
20
server/api/models/compat.go
Normal 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
52
server/api/router.go
Normal 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))
|
||||
}
|
Reference in New Issue
Block a user