init storage server
commit
8a55703b58
|
@ -0,0 +1,8 @@
|
|||
debug: false
|
||||
storagePath: "./storage/"
|
||||
imageUrlAddress: "http://localhost:8081/v1/"
|
||||
scylladb:
|
||||
host: 127.0.0.1
|
||||
username: user
|
||||
password: password
|
||||
keyspace: keyspace
|
|
@ -0,0 +1,28 @@
|
|||
module clickandjoin.app/storageserver
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/gocql/gocql v1.3.1 // indirect
|
||||
github.com/gofiber/fiber/v2 v2.40.1 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/h2non/bimg v1.1.9 // indirect
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/kolesa-team/go-webp v1.0.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/scylladb/go-reflectx v1.0.1 // indirect
|
||||
github.com/scylladb/gocqlx/v2 v2.7.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.41.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
|
@ -0,0 +1,73 @@
|
|||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gocql/gocql v1.3.1 h1:BTwM4rux+ah5G3oH6/MQa+tur/TDd/XAAOXDxBBs7rg=
|
||||
github.com/gocql/gocql v1.3.1/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8=
|
||||
github.com/gofiber/fiber/v2 v2.40.1 h1:pc7n9VVpGIqNsvg9IPLQhyFEMJL8gCs1kneH5D1pIl4=
|
||||
github.com/gofiber/fiber/v2 v2.40.1/go.mod h1:Gko04sLksnHbzLSRBFWPFdzM9Ws9pRxvvIaohJK1dsk=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/h2non/bimg v1.1.9 h1:WH20Nxko9l/HFm4kZCA3Phbgu2cbHvYzxwxn9YROEGg=
|
||||
github.com/h2non/bimg v1.1.9/go.mod h1:R3+UiYwkK4rQl6KVFTOFJHitgLbZXBZNFh2cv3AEbp8=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/kolesa-team/go-webp v1.0.2 h1:XCrWqxI7tNOI3dr0YufD9TUb+54vBDogg9KsHH7q5Lc=
|
||||
github.com/kolesa-team/go-webp v1.0.2/go.mod h1:oMvdivD6K+Q5qIIkVC2w4k2ZUnI1H+MyP7inwgWq9aA=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ=
|
||||
github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc=
|
||||
github.com/scylladb/gocqlx/v2 v2.7.0 h1:/w1VeJHCEAsg9eTculTvIS9eIe/VmEu0clhlH1CF7lc=
|
||||
github.com/scylladb/gocqlx/v2 v2.7.0/go.mod h1:jKhM0/LkEAhEOSwd10TCMQdlC5x8aEzK7cXjQcPyMJ0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY=
|
||||
github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,46 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"clickandjoin.app/storageserver/modules/config"
|
||||
"clickandjoin.app/storageserver/modules/scylladb"
|
||||
"clickandjoin.app/storageserver/routers/router"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
config.LoadConfig()
|
||||
|
||||
if config.Cfg.Debug {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
|
||||
logrus.Println("Debug:", config.Cfg.Debug)
|
||||
|
||||
scylladb.InitDatabase()
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
|
||||
app.Use(cors.New())
|
||||
|
||||
if config.Cfg.Debug {
|
||||
app.Use(logger.New(logger.Config{
|
||||
Format: "${pid} ${locals:requestid} ${status} - ${method} ${path}\n",
|
||||
}))
|
||||
}
|
||||
|
||||
router.SetupRoutes(app)
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatalln("Please specify port")
|
||||
}
|
||||
|
||||
app.Listen("127.0.0.1:" + os.Args[1])
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var Cfg Config
|
||||
|
||||
type Config struct {
|
||||
Debug bool
|
||||
StoragePath string `yaml:"storagePath"`
|
||||
ImageUrlAddress string `yaml:"imageUrlAddress"`
|
||||
ScyllaDB ScyllaDB `yaml:"scylladb"`
|
||||
}
|
||||
|
||||
type ScyllaDB struct {
|
||||
Host string
|
||||
Username string
|
||||
Password string
|
||||
Keyspace string
|
||||
}
|
||||
|
||||
func LoadConfig() {
|
||||
data, err := os.ReadFile("config.yml")
|
||||
|
||||
if err != nil {
|
||||
logrus.Fatalln("Failed to read config file, err:", err)
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(data, &Cfg); err != nil {
|
||||
logrus.Fatalln("Failed to unmarshal config file, err:", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package image
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"clickandjoin.app/storageserver/modules/config"
|
||||
"clickandjoin.app/storageserver/modules/utils"
|
||||
"github.com/google/uuid"
|
||||
"github.com/h2non/bimg"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// is specified in the form data of the frontend
|
||||
const FormFileKey = "file"
|
||||
|
||||
const MaxAvatarSize = 2 * 1024 * 1024 // 2 MB
|
||||
|
||||
// filename len = 36 + dot . 1 + longestFileType 4
|
||||
// example: cf75ace7-da4c-434d-bf7d-0bdbcea5c57d.webp
|
||||
const MaxFileNameLen = 41
|
||||
|
||||
var validFileTypes = []string{"jpeg", "jpg", "png", "webp"}
|
||||
|
||||
// represents the query parameter size for the dynamic image resolution
|
||||
// example ?size=1 -> 64x64
|
||||
var ImageSizes = []int{32, 64, 150, 256, 512, 1024}
|
||||
|
||||
const DefaultImageSize = 0
|
||||
|
||||
func FileTypeVerification(fileType string) bool {
|
||||
for _, validFileType := range validFileTypes {
|
||||
if fileType == "image/"+validFileType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func createUserFolder(userId string) error {
|
||||
path := config.Cfg.StoragePath + userId
|
||||
|
||||
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
||||
err = os.Mkdir(utils.GetUserStoragePath(userId), os.ModePerm)
|
||||
|
||||
if err != nil && !errors.Is(err, os.ErrExist) {
|
||||
logrus.Errorln("Failed to create user folder, err:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SaveImage(fileHeader *multipart.FileHeader, userId string) (fileName string, err error) {
|
||||
err = createUserFolder(userId)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
f, err := fileHeader.Open()
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to open file header, err:", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileData, err := io.ReadAll(f)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to read file, err:", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
fileName = uuid.New().String()
|
||||
newImage := bimg.NewImage(fileData).Image()
|
||||
|
||||
err = bimg.Write(utils.GetUserStoragePath(userId)+fileName+".webp", newImage)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to save image, err:", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fileName + ".webp", nil
|
||||
}
|
||||
|
||||
func GetImage(userId string, fileName string, imageSize string) ([]byte, error) {
|
||||
imgSize, err := strconv.Atoi(imageSize)
|
||||
|
||||
if err != nil {
|
||||
imgSize = DefaultImageSize
|
||||
}
|
||||
|
||||
buffer, err := bimg.Read(utils.GetUserStoragePath(userId) + fileName)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to read image, err:", err)
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
// check that the value has not been manipulated and is greater than the largest index value in the list
|
||||
if imgSize > len(ImageSizes)-1 {
|
||||
imgSize = DefaultImageSize
|
||||
}
|
||||
|
||||
resolution := ImageSizes[imgSize]
|
||||
|
||||
newImage, err := bimg.NewImage(buffer).ForceResize(resolution, resolution)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to force resize, err:", err)
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return newImage, nil
|
||||
}
|
||||
|
||||
func DeleteOldAvatarImage(userId string) error {
|
||||
path := utils.GetUserStoragePath(userId)
|
||||
|
||||
dir, err := os.ReadDir(path)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to read dir, err:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, file := range dir {
|
||||
logrus.Println(file.Name())
|
||||
os.Remove(path + file.Name())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package scylladb
|
||||
|
||||
import (
|
||||
"github.com/scylladb/gocqlx/v2/table"
|
||||
)
|
||||
|
||||
var (
|
||||
Users = table.New(table.Metadata{
|
||||
Name: "users",
|
||||
Columns: []string{
|
||||
"id",
|
||||
"username",
|
||||
"account_name",
|
||||
"email",
|
||||
"password",
|
||||
"description",
|
||||
"latitude",
|
||||
"longitude",
|
||||
"privacy",
|
||||
"xp_level",
|
||||
"xp_points",
|
||||
"followers_count",
|
||||
"following_count",
|
||||
"account_status",
|
||||
"avatar_url",
|
||||
"created_at",
|
||||
"updated_at"},
|
||||
PartKey: []string{"id"},
|
||||
})
|
||||
|
||||
Sessions = table.New(table.Metadata{
|
||||
Name: "sessions",
|
||||
Columns: []string{
|
||||
"id",
|
||||
"user_id"},
|
||||
PartKey: []string{"id"},
|
||||
})
|
||||
)
|
|
@ -0,0 +1,32 @@
|
|||
package scylladb
|
||||
|
||||
import (
|
||||
"clickandjoin.app/storageserver/modules/config"
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/scylladb/gocqlx/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var Session gocqlx.Session
|
||||
var Cluster *gocql.ClusterConfig
|
||||
|
||||
func InitDatabase() {
|
||||
Cluster = gocql.NewCluster(config.Cfg.ScyllaDB.Host)
|
||||
|
||||
Cluster.Authenticator = gocql.PasswordAuthenticator{
|
||||
Username: config.Cfg.ScyllaDB.Username,
|
||||
Password: config.Cfg.ScyllaDB.Password,
|
||||
}
|
||||
|
||||
Cluster.Keyspace = config.Cfg.ScyllaDB.Keyspace
|
||||
|
||||
var err error
|
||||
|
||||
Session, err = gocqlx.WrapSession(Cluster.CreateSession())
|
||||
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
logrus.Info("Database connected")
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package structs
|
||||
|
||||
const (
|
||||
LenUserId = 36
|
||||
LenXAuthorizationToken = 36
|
||||
)
|
||||
|
||||
// Representation of the user model
|
||||
// TABLE users
|
||||
type User struct {
|
||||
Id string
|
||||
Username string
|
||||
AccountName string
|
||||
Email string
|
||||
Password string
|
||||
Description string
|
||||
Latitude float64
|
||||
Longitude float64
|
||||
ParticipatingEvents []string
|
||||
VisitedEvents []string
|
||||
Notifications []string
|
||||
Privacy UserPrivacy
|
||||
XpLevel int
|
||||
XpPoints int
|
||||
FollowersCount int
|
||||
FollowingCount int
|
||||
AccountStatus uint8
|
||||
AvatarUrl string
|
||||
CreatedAt int64
|
||||
UpdatedAt int64
|
||||
}
|
||||
|
||||
type UserPrivacy struct {
|
||||
Test uint8
|
||||
}
|
||||
|
||||
// TABLE sessions
|
||||
type UserSession struct {
|
||||
Id string
|
||||
UserId string
|
||||
FcmToken string
|
||||
UserAgent string
|
||||
AppVersion string
|
||||
Ip string
|
||||
LastUsed int64
|
||||
CreatedAt int64
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"clickandjoin.app/storageserver/modules/config"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
const URL = "http://localhost:8081/v1/"
|
||||
|
||||
func GetAuhorizationToken(c *fiber.Ctx) string {
|
||||
return c.GetReqHeaders()["X-Authorization"]
|
||||
}
|
||||
|
||||
func GetUserStoragePath(userId string) string {
|
||||
return config.Cfg.StoragePath + "users/" + userId + "/"
|
||||
}
|
||||
|
||||
func GetUserAvatarUrl(userId string, filename string) string {
|
||||
return config.Cfg.ImageUrlAddress + "avatars/" + userId + "/" + filename
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
The following library must be installed
|
||||
|
||||
```
|
||||
sudo apt install libvips-dev
|
||||
```
|
||||
so that the used library (https://github.com/h2non/bimg) works.
|
||||
|
||||
*Needed download package found here https://github.com/davidbyttow/govips*
|
|
@ -0,0 +1,14 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"clickandjoin.app/storageserver/routers/routes/v1/user"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func SetupRoutes(app *fiber.App) {
|
||||
v1 := app.Group("/v1")
|
||||
v1.Get("/avatars/:userId/:fileName", user.GetAvatar)
|
||||
|
||||
u := v1.Group("/user")
|
||||
u.Post("/avatar", user.UpdateAvatar)
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"clickandjoin.app/storageserver/modules/image"
|
||||
"clickandjoin.app/storageserver/modules/scylladb"
|
||||
"clickandjoin.app/storageserver/modules/structs"
|
||||
"clickandjoin.app/storageserver/modules/utils"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func GetAvatar(c *fiber.Ctx) error {
|
||||
userId := c.Params("userId")
|
||||
|
||||
if len(userId) != structs.LenUserId {
|
||||
logrus.Debugln("UserId is longer than allowed")
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
fileName := c.Params("fileName")
|
||||
|
||||
// check if the filename length has not been manipulated by the user
|
||||
if len(fileName) > image.MaxFileNameLen {
|
||||
logrus.Debugln("Filename is longer than allowed")
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// image resolution
|
||||
size := c.Query("size")
|
||||
|
||||
img, err := image.GetImage(userId, fileName, size)
|
||||
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
return c.Send(img)
|
||||
}
|
||||
|
||||
func UpdateAvatar(c *fiber.Ctx) error {
|
||||
xAuthorization := utils.GetAuhorizationToken(c)
|
||||
|
||||
if len(xAuthorization) != structs.LenXAuthorizationToken {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
foundSession := structs.UserSession{Id: xAuthorization}
|
||||
|
||||
q := scylladb.Session.Query(scylladb.Sessions.Get("user_id")).BindStruct(foundSession)
|
||||
|
||||
if err := q.GetRelease(&foundSession); err != nil {
|
||||
logrus.Errorln("Failed to get user session, err:", err)
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
file, err := c.FormFile(image.FormFileKey)
|
||||
|
||||
if err != nil {
|
||||
logrus.Errorln("Failed to get form file, err:", err)
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
logrus.Println("size", file.Size, "header", file.Header, "filename", file.Filename)
|
||||
|
||||
if file.Size > image.MaxAvatarSize {
|
||||
return c.SendStatus(fiber.StatusRequestEntityTooLarge)
|
||||
}
|
||||
|
||||
if valid := image.FileTypeVerification(file.Header.Get("Content-Type")); !valid {
|
||||
return c.SendStatus(fiber.StatusUnsupportedMediaType)
|
||||
}
|
||||
|
||||
if err = image.DeleteOldAvatarImage(foundSession.UserId); err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
fileName, err := image.SaveImage(file, foundSession.UserId)
|
||||
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
user := structs.User{Id: foundSession.UserId, AvatarUrl: utils.GetUserAvatarUrl(foundSession.UserId, fileName)}
|
||||
|
||||
q = scylladb.Session.Query(scylladb.Users.Update("avatar_url")).BindStruct(user)
|
||||
|
||||
if err := q.ExecRelease(); err != nil {
|
||||
logrus.Errorln("Failed to update user avatar url, err:", err)
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
Loading…
Reference in New Issue