fx build fix
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed

This commit is contained in:
Stephan D
2025-11-08 00:30:29 +01:00
parent 590fad0071
commit 49b86efecb
165 changed files with 9466 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
package flrstring
import (
"math/rand"
"time"
)
// Constants and variables for random string generation
const (
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
letterIdxBits = 6
letterIdxMask = 1<<letterIdxBits - 1
letterIdxMax = 63 / letterIdxBits
)
var src = rand.NewSource(time.Now().UnixNano())
// createRandString creates a random string with the size of n
// See: http://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-golang
func CreateRandString(n int) string {
b := make([]byte, n)
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return string(b)
}

View File

@@ -0,0 +1,15 @@
package imagewriter
import (
"net/http"
"strconv"
)
func WriteImage(w http.ResponseWriter, buffer *[]byte, fileType string) error {
w.Header().Set("Content-Type", fileType)
w.Header().Set("Content-Length", strconv.Itoa(len(*buffer)))
w.WriteHeader(http.StatusOK)
_, err := w.Write(*buffer)
return err
}

View File

@@ -0,0 +1,39 @@
package mutil
import (
"fmt"
"strings"
)
func AddParam(base string, param string) string {
base = strings.TrimSuffix(base, "/")
return fmt.Sprintf("%s/{%s}", base, param)
}
func AddAccountRef(base string) string {
return AddParam(base, AccountRefName())
}
func AddObjRef(base string) string {
return AddParam(base, ObjRefName())
}
func AddOrganizaztionRef(base string) string {
return AddParam(base, OrganizationRefName())
}
func AddStatusRef(base string) string {
return AddParam(base, StatusRefName())
}
func AddProjectRef(base string) string {
return AddParam(base, ProjectRefName())
}
func AddInvitationRef(base string) string {
return AddParam(base, InvitationRefName())
}
func AddToken(base string) string {
return AddParam(base, TokenName())
}

View File

@@ -0,0 +1,135 @@
package mutil
import (
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
"github.com/tech/sendico/pkg/mlogger"
"github.com/tech/sendico/pkg/model"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/zap"
)
func GetParam(r *http.Request, paramName string) string {
return chi.URLParam(r, paramName)
}
func GetID(r *http.Request) string {
return GetParam(r, "id")
}
func GetAccountID(r *http.Request) string {
return GetParam(r, AccountRefName())
}
func GetObjRef(r *http.Request) string {
return GetParam(r, ObjRefName())
}
func GetOrganizationID(r *http.Request) string {
return GetParam(r, OrganizationRefName())
}
func GetOrganizationRef(r *http.Request) (primitive.ObjectID, error) {
return primitive.ObjectIDFromHex(GetOrganizationID(r))
}
func GetStatusID(r *http.Request) string {
return GetParam(r, OrganizationRefName())
}
func GetStatusRef(r *http.Request) (primitive.ObjectID, error) {
return primitive.ObjectIDFromHex(GetStatusID(r))
}
func GetProjectID(r *http.Request) string {
return GetParam(r, ProjectRefName())
}
func GetProjectRef(r *http.Request) (primitive.ObjectID, error) {
return primitive.ObjectIDFromHex(GetProjectID(r))
}
func GetInvitationID(r *http.Request) string {
return GetParam(r, InvitationRefName())
}
func GetInvitationRef(r *http.Request) (primitive.ObjectID, error) {
return primitive.ObjectIDFromHex(GetOrganizationID(r))
}
func GetToken(r *http.Request) string {
return GetParam(r, TokenName())
}
// parseFunc is a function type that parses a string to a specific type
type parseFunc[T any] func(string) (T, error)
// getOptionalParam is a generic function that handles optional query parameters
func GetOptionalParam[T any](logger mlogger.Logger, r *http.Request, key string, parse parseFunc[T]) (*T, error) {
vals := r.URL.Query()
s := vals.Get(key)
if s == "" {
return nil, nil
}
val, err := parse(s)
if err != nil {
logger.Debug("Malformed query parameter", zap.Error(err), zap.String(key, s))
return nil, err
}
return &val, nil
}
// getOptionalInt64Param gets an optional int64 query parameter
func GetOptionalInt64Param(logger mlogger.Logger, r *http.Request, key string) (*int64, error) {
return GetOptionalParam(logger, r, key, func(s string) (int64, error) {
return strconv.ParseInt(s, 10, 64)
})
}
func GetLimit(logger mlogger.Logger, r *http.Request) (*int64, error) {
return GetOptionalInt64Param(logger, r, "limit")
}
func GetOffset(logger mlogger.Logger, r *http.Request) (*int64, error) {
return GetOptionalInt64Param(logger, r, "offset")
}
func GetLimitAndOffset(logger mlogger.Logger, r *http.Request) (*int64, *int64, error) {
limit, err := GetLimit(logger, r)
if err != nil {
return nil, nil, err
}
offset, err := GetOffset(logger, r)
if err != nil {
return nil, nil, err
}
return limit, offset, nil
}
func GetOptionalBoolParam(logger mlogger.Logger, r *http.Request, key string) (*bool, error) {
return GetOptionalParam(logger, r, key, strconv.ParseBool)
}
func GetCascadeParam(logger mlogger.Logger, r *http.Request) (*bool, error) {
return GetOptionalBoolParam(logger, r, "cascade")
}
func GetArchiveParam(logger mlogger.Logger, r *http.Request) (*bool, error) {
return GetOptionalBoolParam(logger, r, "archived")
}
func GetViewCursor(logger mlogger.Logger, r *http.Request) (*model.ViewCursor, error) {
var res model.ViewCursor
var err error
if res.Limit, res.Offset, err = GetLimitAndOffset(logger, r); err != nil {
return nil, err
}
if res.IsArchived, err = GetArchiveParam(logger, r); err != nil {
return nil, err
}
return &res, nil
}

View File

@@ -0,0 +1,142 @@
package mutil
import (
"net/http"
"testing"
"github.com/tech/sendico/pkg/mlogger"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
)
func TestGetOptionalBoolParam(t *testing.T) {
logger := mlogger.Logger(zap.NewNop())
tests := []struct {
name string
query string
expected *bool
hasError bool
}{
{
name: "valid true",
query: "?param=true",
expected: boolPtr(true),
hasError: false,
},
{
name: "valid false",
query: "?param=false",
expected: boolPtr(false),
hasError: false,
},
{
name: "missing parameter",
query: "?other=value",
expected: nil,
hasError: false,
},
{
name: "invalid value",
query: "?param=invalid",
expected: nil,
hasError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req, err := http.NewRequest("GET", "http://example.com"+tt.query, nil)
require.NoError(t, err)
result, err := GetOptionalBoolParam(logger, req, "param")
if tt.hasError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
if tt.expected == nil {
assert.Nil(t, result)
} else {
assert.NotNil(t, result)
assert.Equal(t, *tt.expected, *result)
}
})
}
}
func TestGetOptionalInt64Param(t *testing.T) {
logger := mlogger.Logger(zap.NewNop())
tests := []struct {
name string
query string
expected *int64
hasError bool
}{
{
name: "valid positive number",
query: "?param=123",
expected: int64Ptr(123),
hasError: false,
},
{
name: "valid negative number",
query: "?param=-456",
expected: int64Ptr(-456),
hasError: false,
},
{
name: "valid zero",
query: "?param=0",
expected: int64Ptr(0),
hasError: false,
},
{
name: "missing parameter",
query: "?other=value",
expected: nil,
hasError: false,
},
{
name: "invalid value",
query: "?param=invalid",
expected: nil,
hasError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req, err := http.NewRequest("GET", "http://example.com"+tt.query, nil)
require.NoError(t, err)
result, err := GetOptionalInt64Param(logger, req, "param")
if tt.hasError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
if tt.expected == nil {
assert.Nil(t, result)
} else {
assert.NotNil(t, result)
assert.Equal(t, *tt.expected, *result)
}
})
}
}
// Helper functions for creating pointers to values
func boolPtr(b bool) *bool {
return &b
}
func int64Ptr(i int64) *int64 {
return &i
}

View File

@@ -0,0 +1,44 @@
package mutil
import (
"net/http"
mutilimp "github.com/tech/sendico/server/internal/mutil/param/internal"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type ParamHelper interface {
Name() string
RefName() string
GetID(r *http.Request) string
GetRef(r *http.Request) (primitive.ObjectID, error)
AddRef(base string) string
}
func CreatePH(resource string) ParamHelper {
return mutilimp.CreateImp(resource)
}
type DependentParamHelper struct {
p ParamHelper
c ParamHelper
}
func (ph *DependentParamHelper) Parent() ParamHelper {
return ph.p
}
func (ph *DependentParamHelper) Child() ParamHelper {
return ph.c
}
func (ph *DependentParamHelper) AddRef(base string) string {
return ph.Parent().AddRef(ph.Child().AddRef(base))
}
func CreateDPH(pRes, cRes string) *DependentParamHelper {
return &DependentParamHelper{
p: CreatePH(pRes),
c: CreatePH(cRes),
}
}

View File

@@ -0,0 +1,51 @@
package mutilimp
import (
"fmt"
"net/http"
"strings"
"github.com/go-chi/chi/v5"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func addParam(base string, param string) string {
base = strings.TrimSuffix(base, "/")
return fmt.Sprintf("%s/{%s}", base, param)
}
func _ref(param string) string {
return param + "_ref"
}
func getParam(r *http.Request, paramName string) string {
return chi.URLParam(r, paramName)
}
type ParamHelper struct {
t string
}
func (ph *ParamHelper) Name() string {
return ph.t
}
func (ph *ParamHelper) RefName() string {
return _ref(ph.Name())
}
func (ph *ParamHelper) GetID(r *http.Request) string {
return getParam(r, ph.RefName())
}
func (ph *ParamHelper) GetRef(r *http.Request) (primitive.ObjectID, error) {
return primitive.ObjectIDFromHex(ph.GetID(r))
}
func (ph *ParamHelper) AddRef(base string) string {
return addParam(base, ph.RefName())
}
func CreateImp(resource string) *ParamHelper {
return &ParamHelper{t: resource}
}

View File

@@ -0,0 +1,15 @@
package mutil
import (
"net/http"
"go.uber.org/zap"
)
func PLog(ph ParamHelper, r *http.Request) zap.Field {
return zap.String(ph.Name(), ph.GetID(r))
}
func PLogType(ph ParamHelper) zap.Field {
return zap.String("object", ph.Name())
}

View File

@@ -0,0 +1,33 @@
package mutil
func _ref(param string) string {
return param + "_ref"
}
func AccountRefName() string {
return _ref("account")
}
func ObjRefName() string {
return _ref("obj")
}
func OrganizationRefName() string {
return _ref("org")
}
func StatusRefName() string {
return _ref("status")
}
func ProjectRefName() string {
return _ref("project")
}
func InvitationRefName() string {
return _ref("invitation")
}
func TokenName() string {
return "token"
}

View File

@@ -0,0 +1,11 @@
package mutil
import (
"net/http"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func GetAccountRef(r *http.Request) (primitive.ObjectID, error) {
return primitive.ObjectIDFromHex(GetAccountID(r))
}

View File

@@ -0,0 +1,15 @@
package mutil
import "time"
func ToDate(t time.Time) string {
return t.Format(time.DateOnly)
}
func ToTime(t time.Time) string {
return t.Format(time.TimeOnly)
}
func ToDateTime(t time.Time) string {
return t.Format(time.DateTime)
}