⬆️ Switch to Paperclip
This commit is contained in:
parent
f38aab68cd
commit
b3b1ec4585
15
go.mod
15
go.mod
@ -5,13 +5,13 @@ go 1.22
|
|||||||
toolchain go1.22.1
|
toolchain go1.22.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.solsynth.dev/hydrogen/passport v0.0.0-20240504085931-7c418a3cd32f
|
git.solsynth.dev/hydrogen/paperclip v0.0.0-20240520143155-2b131982b821
|
||||||
|
git.solsynth.dev/hydrogen/passport v0.0.0-20240517121420-1e2d5e9f9d87
|
||||||
github.com/go-playground/validator/v10 v10.17.0
|
github.com/go-playground/validator/v10 v10.17.0
|
||||||
github.com/gofiber/contrib/websocket v1.3.0
|
github.com/gofiber/contrib/websocket v1.3.0
|
||||||
github.com/gofiber/fiber/v2 v2.52.4
|
github.com/gofiber/fiber/v2 v2.52.4
|
||||||
github.com/gofiber/template/html/v2 v2.1.1
|
github.com/gofiber/template/html/v2 v2.1.1
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.0
|
github.com/golang-jwt/jwt/v5 v5.2.0
|
||||||
github.com/google/uuid v1.6.0
|
|
||||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/livekit/protocol v1.14.0
|
github.com/livekit/protocol v1.14.0
|
||||||
@ -20,7 +20,7 @@ require (
|
|||||||
github.com/rs/zerolog v1.31.0
|
github.com/rs/zerolog v1.31.0
|
||||||
github.com/samber/lo v1.39.0
|
github.com/samber/lo v1.39.0
|
||||||
github.com/spf13/viper v1.18.2
|
github.com/spf13/viper v1.18.2
|
||||||
golang.org/x/crypto v0.22.0
|
golang.org/x/crypto v0.23.0
|
||||||
google.golang.org/grpc v1.63.2
|
google.golang.org/grpc v1.63.2
|
||||||
gorm.io/datatypes v1.2.0
|
gorm.io/datatypes v1.2.0
|
||||||
gorm.io/driver/postgres v1.5.4
|
gorm.io/driver/postgres v1.5.4
|
||||||
@ -50,6 +50,7 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||||
github.com/gofiber/template v1.8.3 // indirect
|
github.com/gofiber/template v1.8.3 // indirect
|
||||||
github.com/gofiber/utils v1.1.0 // indirect
|
github.com/gofiber/utils v1.1.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.1 // indirect
|
github.com/gorilla/websocket v1.5.1 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
@ -60,7 +61,7 @@ require (
|
|||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/jxskiss/base62 v1.1.0 // indirect
|
github.com/jxskiss/base62 v1.1.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/klauspost/compress v1.17.8 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/lithammer/shortuuid/v4 v4.0.0 // indirect
|
github.com/lithammer/shortuuid/v4 v4.0.0 // indirect
|
||||||
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 // indirect
|
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 // indirect
|
||||||
@ -124,10 +125,10 @@ require (
|
|||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
go.uber.org/zap/exp v0.2.0 // indirect
|
go.uber.org/zap/exp v0.2.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||||
golang.org/x/net v0.24.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.19.0 // indirect
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
25
go.sum
25
go.sum
@ -1,5 +1,7 @@
|
|||||||
git.solsynth.dev/hydrogen/passport v0.0.0-20240504085931-7c418a3cd32f h1:sKrQrKZc5C+dwefRsnc0uAGttzpSUWXUBoFaCXLkaTo=
|
git.solsynth.dev/hydrogen/paperclip v0.0.0-20240520143155-2b131982b821 h1:azsoKVRp239SkfLU6yg6LkMc2t39vRr6aYCEVstKnms=
|
||||||
git.solsynth.dev/hydrogen/passport v0.0.0-20240504085931-7c418a3cd32f/go.mod h1:3JRFPtf0dXRk2UQ1yVIgIspNfytM2yLBeBePJChgLZE=
|
git.solsynth.dev/hydrogen/paperclip v0.0.0-20240520143155-2b131982b821/go.mod h1:uTNEtJcNdgt7DhOgsewPaLQQ5kTN9H+tGNRT2CshHGs=
|
||||||
|
git.solsynth.dev/hydrogen/passport v0.0.0-20240517121420-1e2d5e9f9d87 h1:r+x72tRB9LTJFH3F2rIKydQUXREc7lgxITDnjfFWwGw=
|
||||||
|
git.solsynth.dev/hydrogen/passport v0.0.0-20240517121420-1e2d5e9f9d87/go.mod h1:mEcDEKashAh3jvoGDbNLefK+HgsJaMj4xEc6vkLZ+Zc=
|
||||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||||
@ -121,8 +123,8 @@ github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw=
|
|||||||
github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc=
|
github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
@ -330,8 +332,8 @@ golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIi
|
|||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
@ -354,8 +356,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|||||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -391,8 +393,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -414,8 +416,9 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/external"
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"git.solsynth.dev/hydrogen/messaging/pkg/external"
|
||||||
|
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/grpc"
|
"git.solsynth.dev/hydrogen/messaging/pkg/grpc"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/server"
|
"git.solsynth.dev/hydrogen/messaging/pkg/server"
|
||||||
|
|
||||||
@ -45,7 +46,10 @@ func main() {
|
|||||||
// Connect other services
|
// Connect other services
|
||||||
external.SetupLiveKit()
|
external.SetupLiveKit()
|
||||||
if err := grpc.ConnectPassport(); err != nil {
|
if err := grpc.ConnectPassport(); err != nil {
|
||||||
log.Fatal().Err(err).Msg("An error occurred when connecting to identity grpc endpoint...")
|
log.Fatal().Err(err).Msg("An error occurred when connecting to passport...")
|
||||||
|
}
|
||||||
|
if err := grpc.ConnectPaperclip(); err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("An error occurred when connecting to paperclip...")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server
|
// Server
|
||||||
|
@ -12,7 +12,6 @@ var DatabaseAutoActionRange = []any{
|
|||||||
&models.ChannelMember{},
|
&models.ChannelMember{},
|
||||||
&models.Call{},
|
&models.Call{},
|
||||||
&models.Message{},
|
&models.Message{},
|
||||||
&models.Attachment{},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMigration(source *gorm.DB) error {
|
func RunMigration(source *gorm.DB) error {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package grpc
|
package grpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
pcpb "git.solsynth.dev/hydrogen/paperclip/pkg/grpc/proto"
|
||||||
idpb "git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
idpb "git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
|
||||||
@ -8,13 +9,28 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Realms idpb.RealmsClient
|
var Attachments pcpb.AttachmentsClient
|
||||||
var Friendships idpb.FriendshipsClient
|
|
||||||
var Notify idpb.NotifyClient
|
func ConnectPaperclip() error {
|
||||||
var Auth idpb.AuthClient
|
addr := viper.GetString("paperclip.grpc_endpoint")
|
||||||
|
if conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
Attachments = pcpb.NewAttachmentsClient(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Realms idpb.RealmsClient
|
||||||
|
Friendships idpb.FriendshipsClient
|
||||||
|
Notify idpb.NotifyClient
|
||||||
|
Auth idpb.AuthClient
|
||||||
|
)
|
||||||
|
|
||||||
func ConnectPassport() error {
|
func ConnectPassport() error {
|
||||||
addr := viper.GetString("identity.grpc_endpoint")
|
addr := viper.GetString("passport.grpc_endpoint")
|
||||||
if conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil {
|
if conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,7 +13,6 @@ type Account struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
EmailAddress string `json:"email_address"`
|
EmailAddress string `json:"email_address"`
|
||||||
PowerLevel int `json:"power_level"`
|
PowerLevel int `json:"power_level"`
|
||||||
Attachments []Attachment `json:"attachments" gorm:"foreignKey:AuthorID"`
|
|
||||||
Channels []Channel `json:"channels"`
|
Channels []Channel `json:"channels"`
|
||||||
ExternalID uint `json:"external_id"`
|
ExternalID uint `json:"external_id"`
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AttachmentType = uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
AttachmentOthers = AttachmentType(iota)
|
|
||||||
AttachmentPhoto
|
|
||||||
AttachmentVideo
|
|
||||||
AttachmentAudio
|
|
||||||
)
|
|
||||||
|
|
||||||
type Attachment struct {
|
|
||||||
BaseModel
|
|
||||||
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Filesize int64 `json:"filesize"`
|
|
||||||
Filename string `json:"filename"`
|
|
||||||
Mimetype string `json:"mimetype"`
|
|
||||||
Hashcode string `json:"hashcode"`
|
|
||||||
Type AttachmentType `json:"type"`
|
|
||||||
ExternalUrl string `json:"external_url"`
|
|
||||||
Author Account `json:"author"`
|
|
||||||
MessageID *uint `json:"message_id"`
|
|
||||||
AuthorID uint `json:"author_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Attachment) GetStoragePath() string {
|
|
||||||
basepath := viper.GetString("content")
|
|
||||||
return filepath.Join(basepath, v.FileID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Attachment) GetAccessPath() string {
|
|
||||||
return fmt.Sprintf("/api/attachments/o/%s", v.FileID)
|
|
||||||
}
|
|
@ -3,8 +3,8 @@ package models
|
|||||||
type ChannelType = uint8
|
type ChannelType = uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ChannelTypeDirect = ChannelType(iota)
|
ChannelTypeCommon = ChannelType(iota)
|
||||||
ChannelTypeRealm
|
ChannelTypeDirect
|
||||||
)
|
)
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
@ -41,6 +41,7 @@ type ChannelMember struct {
|
|||||||
Channel Channel `json:"channel"`
|
Channel Channel `json:"channel"`
|
||||||
Account Account `json:"account"`
|
Account Account `json:"account"`
|
||||||
Notify NotifyLevel `json:"notify"`
|
Notify NotifyLevel `json:"notify"`
|
||||||
|
PowerLevel int `json:"power_level"`
|
||||||
|
|
||||||
Calls []Call `json:"calls" gorm:"foreignKey:FounderID"`
|
Calls []Call `json:"calls" gorm:"foreignKey:FounderID"`
|
||||||
Messages []Message `json:"messages" gorm:"foreignKey:SenderID"`
|
Messages []Message `json:"messages" gorm:"foreignKey:SenderID"`
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import "gorm.io/datatypes"
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
|
|
||||||
Content []byte `json:"content"`
|
Uuid string `json:"uuid"`
|
||||||
|
Content datatypes.JSONMap `json:"content"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Attachments []Attachment `json:"attachments"`
|
Attachments datatypes.JSONSlice[uint] `json:"attachments"`
|
||||||
Channel Channel `json:"channel"`
|
Channel Channel `json:"channel"`
|
||||||
Sender ChannelMember `json:"sender"`
|
Sender ChannelMember `json:"sender"`
|
||||||
ReplyID *uint `json:"reply_id"`
|
ReplyID *uint `json:"reply_id"`
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func readAttachment(c *fiber.Ctx) error {
|
|
||||||
id := c.Params("fileId")
|
|
||||||
basepath := viper.GetString("content")
|
|
||||||
|
|
||||||
return c.SendFile(filepath.Join(basepath, id))
|
|
||||||
}
|
|
||||||
|
|
||||||
func uploadAttachment(c *fiber.Ctx) error {
|
|
||||||
user := c.Locals("principal").(models.Account)
|
|
||||||
hashcode := c.FormValue("hashcode")
|
|
||||||
if len(hashcode) != 64 {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "please provide a SHA256 hashcode, length should be 64 characters")
|
|
||||||
}
|
|
||||||
file, err := c.FormFile("attachment")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
attachment, err := services.NewAttachment(user, file, hashcode)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.SaveFile(file, attachment.GetStoragePath()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(fiber.Map{
|
|
||||||
"info": attachment,
|
|
||||||
"url": attachment.GetAccessPath(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteAttachment(c *fiber.Ctx) error {
|
|
||||||
id, _ := c.ParamsInt("id", 0)
|
|
||||||
user := c.Locals("principal").(models.Account)
|
|
||||||
|
|
||||||
attachment, err := services.GetAttachmentByID(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
|
||||||
} else if attachment.AuthorID != user.ID {
|
|
||||||
return fiber.NewError(fiber.StatusNotFound, "record not created by you")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := services.DeleteAttachment(attachment); err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
|
||||||
} else {
|
|
||||||
return c.SendStatus(fiber.StatusOK)
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||||
@ -44,9 +45,12 @@ func addChannelMember(c *fiber.Ctx) error {
|
|||||||
var channel models.Channel
|
var channel models.Channel
|
||||||
if err := database.C.Where(&models.Channel{
|
if err := database.C.Where(&models.Channel{
|
||||||
Alias: alias,
|
Alias: alias,
|
||||||
AccountID: user.ID,
|
|
||||||
}).First(&channel).Error; err != nil {
|
}).First(&channel).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
|
} else if member, err := services.GetChannelMember(user, channel.ID); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, err.Error())
|
||||||
|
} else if member.PowerLevel < 50 {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "you must be a moderator of a channel to add member into it")
|
||||||
}
|
}
|
||||||
|
|
||||||
var account models.Account
|
var account models.Account
|
||||||
@ -81,6 +85,10 @@ func removeChannelMember(c *fiber.Ctx) error {
|
|||||||
AccountID: user.ID,
|
AccountID: user.ID,
|
||||||
}).First(&channel).Error; err != nil {
|
}).First(&channel).Error; err != nil {
|
||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
|
} else if member, err := services.GetChannelMember(user, channel.ID); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, err.Error())
|
||||||
|
} else if member.PowerLevel < 50 {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "you must be a moderator of a channel to remove member into it")
|
||||||
}
|
}
|
||||||
|
|
||||||
var account models.Account
|
var account models.Account
|
||||||
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||||
@ -111,22 +112,31 @@ func createChannel(c *fiber.Ctx) error {
|
|||||||
var realm *models.Realm
|
var realm *models.Realm
|
||||||
if val, ok := c.Locals("realm").(models.Realm); ok {
|
if val, ok := c.Locals("realm").(models.Realm); ok {
|
||||||
if info, err := services.GetRealmMember(val.ExternalID, user.ExternalID); err != nil {
|
if info, err := services.GetRealmMember(val.ExternalID, user.ExternalID); err != nil {
|
||||||
return fmt.Errorf("you must be a part of that realm then can create channel related to it")
|
return fiber.NewError(fiber.StatusForbidden, "you must be a part of that realm then can create channel related to it")
|
||||||
} else if info.GetPowerLevel() < 50 {
|
} else if info.GetPowerLevel() < 50 {
|
||||||
return fmt.Errorf("you must be a moderator of that realm then can create channel related to it")
|
return fiber.NewError(fiber.StatusForbidden, "you must be a moderator of that realm then can create channel related to it")
|
||||||
} else {
|
} else {
|
||||||
realm = &val
|
realm = &val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
channel := models.Channel{
|
||||||
var channel models.Channel
|
Alias: data.Alias,
|
||||||
if realm != nil {
|
Name: data.Name,
|
||||||
channel, err = services.NewChannel(user, data.Alias, data.Name, data.Description, data.IsEncrypted, realm.ID)
|
Description: data.Description,
|
||||||
} else {
|
IsEncrypted: data.IsEncrypted,
|
||||||
channel, err = services.NewChannel(user, data.Alias, data.Name, data.Description, data.IsEncrypted)
|
AccountID: user.ID,
|
||||||
|
Type: models.ChannelTypeCommon,
|
||||||
|
Members: []models.ChannelMember{
|
||||||
|
{AccountID: user.ID, PowerLevel: 100},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if realm != nil {
|
||||||
|
channel.RealmID = &realm.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := services.NewChannel(channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
}
|
}
|
||||||
@ -153,14 +163,14 @@ func editChannel(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
if val, ok := c.Locals("realm").(models.Realm); ok {
|
if val, ok := c.Locals("realm").(models.Realm); ok {
|
||||||
if info, err := services.GetRealmMember(val.ExternalID, user.ExternalID); err != nil {
|
if info, err := services.GetRealmMember(val.ExternalID, user.ExternalID); err != nil {
|
||||||
return fmt.Errorf("you must be a part of that realm then can edit channel related to it")
|
return fiber.NewError(fiber.StatusForbidden, "you must be a part of that realm then can edit channel related to it")
|
||||||
} else if info.GetPowerLevel() < 50 {
|
} else if info.GetPowerLevel() < 50 {
|
||||||
return fmt.Errorf("you must be a moderator of that realm then can edit channel related to it")
|
return fiber.NewError(fiber.StatusForbidden, "you must be a moderator of that realm then can edit channel related to it")
|
||||||
} else {
|
} else {
|
||||||
tx = tx.Where("realm_id = ?", val.ID)
|
tx = tx.Where("realm_id = ?", val.ID)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tx = tx.Where("account_id = ? AND realm_id IS NULL", user.ID)
|
tx = tx.Where("realm_id IS NULL")
|
||||||
}
|
}
|
||||||
|
|
||||||
var channel models.Channel
|
var channel models.Channel
|
||||||
@ -168,6 +178,14 @@ func editChannel(c *fiber.Ctx) error {
|
|||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if channel.RealmID != nil {
|
||||||
|
if member, err := services.GetChannelMember(user, channel.ID); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "you must be a part of this channel to edit it")
|
||||||
|
} else if member.PowerLevel < 100 {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "you must be channel admin to edit it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
channel, err := services.EditChannel(channel, data.Alias, data.Name, data.Description, data.IsEncrypted)
|
channel, err := services.EditChannel(channel, data.Alias, data.Name, data.Description, data.IsEncrypted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
68
pkg/server/direct_channels_api.go
Normal file
68
pkg/server/direct_channels_api.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
|
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createDirectChannel(c *fiber.Ctx) error {
|
||||||
|
user := c.Locals("principal").(models.Account)
|
||||||
|
|
||||||
|
var data struct {
|
||||||
|
Alias string `json:"alias" validate:"required,lowercase,min=4,max=32"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Members []uint `json:"members"`
|
||||||
|
IsEncrypted bool `json:"is_encrypted"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := BindAndValidate(c, &data); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = services.GetChannelAliasAvailability(data.Alias); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var realm *models.Realm
|
||||||
|
if val, ok := c.Locals("realm").(models.Realm); ok {
|
||||||
|
if info, err := services.GetRealmMember(val.ExternalID, user.ExternalID); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "you must be a part of that realm then can create channel related to it")
|
||||||
|
} else if info.GetPowerLevel() < 50 {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "you must be a moderator of that realm then can create channel related to it")
|
||||||
|
} else {
|
||||||
|
realm = &val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var members []models.Account
|
||||||
|
if err := database.C.Where("id IN ?", data.Members).Find(&members).Error; err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := models.Channel{
|
||||||
|
Alias: data.Alias,
|
||||||
|
Name: data.Name,
|
||||||
|
Description: data.Description,
|
||||||
|
IsEncrypted: data.IsEncrypted,
|
||||||
|
AccountID: user.ID,
|
||||||
|
Type: models.ChannelTypeDirect,
|
||||||
|
Members: append([]models.ChannelMember{
|
||||||
|
{AccountID: user.ID, PowerLevel: 100},
|
||||||
|
}, lo.Map(members, func(item models.Account, idx int) models.ChannelMember {
|
||||||
|
return models.ChannelMember{AccountID: item.ID, PowerLevel: 100}
|
||||||
|
})...),
|
||||||
|
}
|
||||||
|
|
||||||
|
if realm != nil {
|
||||||
|
channel.RealmID = &realm.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := services.NewChannel(channel)
|
||||||
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(channel)
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||||
@ -45,16 +45,25 @@ func newMessage(c *fiber.Ctx) error {
|
|||||||
alias := c.Params("channel")
|
alias := c.Params("channel")
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
|
Uuid string `json:"uuid" validate:"required"`
|
||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
Content map[string]any `json:"content"`
|
Content map[string]any `json:"content"`
|
||||||
Attachments []models.Attachment `json:"attachments"`
|
Attachments []uint `json:"attachments"`
|
||||||
ReplyTo *uint `json:"reply_to"`
|
ReplyTo *uint `json:"reply_to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := BindAndValidate(c, &data); err != nil {
|
if err := BindAndValidate(c, &data); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if len(data.Attachments) == 0 && len(data.Content) == 0 {
|
} else if len(data.Attachments) == 0 && len(data.Content) == 0 {
|
||||||
return fmt.Errorf("you must write or upload some content in a single message")
|
return fiber.NewError(fiber.StatusBadRequest, "you must write or upload some content in a single message")
|
||||||
|
} else if len(data.Uuid) < 36 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "message uuid was not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attachment := range data.Attachments {
|
||||||
|
if !services.CheckAttachmentByIDExists(attachment, "m.attachment") {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("attachment %d not found", attachment))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -72,13 +81,9 @@ func newMessage(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rawContent, err := json.Marshal(data.Content)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid message content, unable to encode: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
message := models.Message{
|
message := models.Message{
|
||||||
Content: rawContent,
|
Uuid: data.Uuid,
|
||||||
|
Content: data.Content,
|
||||||
Sender: member,
|
Sender: member,
|
||||||
Channel: channel,
|
Channel: channel,
|
||||||
ChannelID: channel.ID,
|
ChannelID: channel.ID,
|
||||||
@ -112,7 +117,7 @@ func editMessage(c *fiber.Ctx) error {
|
|||||||
var data struct {
|
var data struct {
|
||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
Content map[string]any `json:"content"`
|
Content map[string]any `json:"content"`
|
||||||
Attachments []models.Attachment `json:"attachments"`
|
Attachments []uint `json:"attachments"`
|
||||||
ReplyTo *uint `json:"reply_to"`
|
ReplyTo *uint `json:"reply_to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +125,12 @@ func editMessage(c *fiber.Ctx) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, attachment := range data.Attachments {
|
||||||
|
if !services.CheckAttachmentByIDExists(attachment, "m.attachment") {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("attachment %d not found", attachment))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var channel models.Channel
|
var channel models.Channel
|
||||||
var member models.ChannelMember
|
var member models.ChannelMember
|
||||||
@ -140,13 +151,8 @@ func editMessage(c *fiber.Ctx) error {
|
|||||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
rawContent, err := json.Marshal(data.Content)
|
|
||||||
if err != nil {
|
|
||||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid message content, unable to encode: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
message.Attachments = data.Attachments
|
message.Attachments = data.Attachments
|
||||||
message.Content = rawContent
|
message.Content = data.Content
|
||||||
message.Type = data.Type
|
message.Type = data.Type
|
||||||
|
|
||||||
message, err = services.EditMessage(message)
|
message, err = services.EditMessage(message)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||||
"github.com/gofiber/contrib/websocket"
|
"github.com/gofiber/contrib/websocket"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func messageGateway(c *websocket.Conn) {
|
func messageGateway(c *websocket.Conn) {
|
||||||
@ -12,6 +13,7 @@ func messageGateway(c *websocket.Conn) {
|
|||||||
|
|
||||||
// Push connection
|
// Push connection
|
||||||
services.ClientRegister(user, c)
|
services.ClientRegister(user, c)
|
||||||
|
log.Debug().Uint("user", user.ID).Msg("New websocket connection established...")
|
||||||
|
|
||||||
// Event loop
|
// Event loop
|
||||||
var task models.UnifiedCommand
|
var task models.UnifiedCommand
|
||||||
@ -42,4 +44,5 @@ func messageGateway(c *websocket.Conn) {
|
|||||||
|
|
||||||
// Pop connection
|
// Pop connection
|
||||||
services.ClientUnregister(user, c)
|
services.ClientUnregister(user, c)
|
||||||
|
log.Debug().Uint("user", user.ID).Msg("A websocket connection disconnected...")
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,12 @@ package server
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg"
|
"git.solsynth.dev/hydrogen/messaging/pkg"
|
||||||
"github.com/gofiber/contrib/websocket"
|
"github.com/gofiber/contrib/websocket"
|
||||||
"github.com/gofiber/fiber/v2/middleware/favicon"
|
"github.com/gofiber/fiber/v2/middleware/favicon"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/middleware/cache"
|
|
||||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
"github.com/gofiber/fiber/v2/middleware/idempotency"
|
"github.com/gofiber/fiber/v2/middleware/idempotency"
|
||||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||||
@ -68,22 +66,16 @@ func NewServer() {
|
|||||||
api.Get("/users/me", authMiddleware, getUserinfo)
|
api.Get("/users/me", authMiddleware, getUserinfo)
|
||||||
api.Get("/users/:accountId", getOthersInfo)
|
api.Get("/users/:accountId", getOthersInfo)
|
||||||
|
|
||||||
api.Get("/attachments/o/:fileId", cache.New(cache.Config{
|
|
||||||
Expiration: 365 * 24 * time.Hour,
|
|
||||||
CacheControl: true,
|
|
||||||
}), readAttachment)
|
|
||||||
api.Post("/attachments", authMiddleware, uploadAttachment)
|
|
||||||
api.Delete("/attachments/:id", authMiddleware, deleteAttachment)
|
|
||||||
|
|
||||||
channels := api.Group("/channels/:realm").Use(realmMiddleware).Name("Channels API")
|
channels := api.Group("/channels/:realm").Use(realmMiddleware).Name("Channels API")
|
||||||
{
|
{
|
||||||
channels.Get("/", listChannel)
|
channels.Get("/", listChannel)
|
||||||
channels.Get("/:channel", getChannel)
|
|
||||||
channels.Get("/:channel/availability", authMiddleware, getChannelAvailability)
|
|
||||||
channels.Get("/me", authMiddleware, listOwnedChannel)
|
channels.Get("/me", authMiddleware, listOwnedChannel)
|
||||||
channels.Get("/me/available", authMiddleware, listAvailableChannel)
|
channels.Get("/me/available", authMiddleware, listAvailableChannel)
|
||||||
|
channels.Get("/:channel", getChannel)
|
||||||
|
channels.Get("/:channel/availability", authMiddleware, getChannelAvailability)
|
||||||
|
|
||||||
channels.Post("/", authMiddleware, createChannel)
|
channels.Post("/", authMiddleware, createChannel)
|
||||||
|
channels.Post("/dm", authMiddleware, createDirectChannel)
|
||||||
channels.Put("/:channelId", authMiddleware, editChannel)
|
channels.Put("/:channelId", authMiddleware, editChannel)
|
||||||
channels.Delete("/:channelId", authMiddleware, deleteChannel)
|
channels.Delete("/:channelId", authMiddleware, deleteChannel)
|
||||||
|
|
||||||
|
@ -1,127 +1,30 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"mime/multipart"
|
"context"
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
"git.solsynth.dev/hydrogen/messaging/pkg/grpc"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
pcpb "git.solsynth.dev/hydrogen/paperclip/pkg/grpc/proto"
|
||||||
"github.com/google/uuid"
|
"github.com/samber/lo"
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetAttachmentByID(id uint) (models.Attachment, error) {
|
func GetAttachmentByID(id uint) (*pcpb.Attachment, error) {
|
||||||
var attachment models.Attachment
|
return grpc.Attachments.GetAttachment(context.Background(), &pcpb.AttachmentLookupRequest{
|
||||||
if err := database.C.Where(models.Attachment{
|
Id: lo.ToPtr(uint64(id)),
|
||||||
BaseModel: models.BaseModel{ID: id},
|
})
|
||||||
}).First(&attachment).Error; err != nil {
|
|
||||||
return attachment, err
|
|
||||||
}
|
|
||||||
return attachment, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAttachmentByUUID(fileId string) (models.Attachment, error) {
|
func GetAttachmentByUUID(uuid string) (*pcpb.Attachment, error) {
|
||||||
var attachment models.Attachment
|
return grpc.Attachments.GetAttachment(context.Background(), &pcpb.AttachmentLookupRequest{
|
||||||
if err := database.C.Where(models.Attachment{
|
Uuid: &uuid,
|
||||||
FileID: fileId,
|
})
|
||||||
}).First(&attachment).Error; err != nil {
|
|
||||||
return attachment, err
|
|
||||||
}
|
|
||||||
return attachment, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAttachmentByHashcode(hashcode string) (models.Attachment, error) {
|
func CheckAttachmentByIDExists(id uint, usage string) bool {
|
||||||
var attachment models.Attachment
|
_, err := grpc.Attachments.CheckAttachmentExists(context.Background(), &pcpb.AttachmentLookupRequest{
|
||||||
if err := database.C.Where(models.Attachment{
|
Id: lo.ToPtr(uint64(id)),
|
||||||
Hashcode: hashcode,
|
Usage: &usage,
|
||||||
}).First(&attachment).Error; err != nil {
|
})
|
||||||
return attachment, err
|
|
||||||
}
|
return err == nil
|
||||||
return attachment, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAttachment(user models.Account, header *multipart.FileHeader, hashcode string) (models.Attachment, error) {
|
|
||||||
var attachment models.Attachment
|
|
||||||
existsAttachment, err := GetAttachmentByHashcode(hashcode)
|
|
||||||
if err != nil {
|
|
||||||
// Upload the new file
|
|
||||||
attachment = models.Attachment{
|
|
||||||
FileID: uuid.NewString(),
|
|
||||||
Filesize: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
Hashcode: hashcode,
|
|
||||||
Mimetype: "unknown/unknown",
|
|
||||||
Type: models.AttachmentOthers,
|
|
||||||
AuthorID: user.ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open file
|
|
||||||
file, err := header.Open()
|
|
||||||
if err != nil {
|
|
||||||
return attachment, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
// Detect mimetype
|
|
||||||
fileHeader := make([]byte, 512)
|
|
||||||
_, err = file.Read(fileHeader)
|
|
||||||
if err != nil {
|
|
||||||
return attachment, err
|
|
||||||
}
|
|
||||||
attachment.Mimetype = http.DetectContentType(fileHeader)
|
|
||||||
|
|
||||||
switch strings.Split(attachment.Mimetype, "/")[0] {
|
|
||||||
case "image":
|
|
||||||
attachment.Type = models.AttachmentPhoto
|
|
||||||
case "video":
|
|
||||||
attachment.Type = models.AttachmentVideo
|
|
||||||
case "audio":
|
|
||||||
attachment.Type = models.AttachmentAudio
|
|
||||||
default:
|
|
||||||
attachment.Type = models.AttachmentOthers
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Instant upload, build link with the exists file
|
|
||||||
attachment = models.Attachment{
|
|
||||||
FileID: existsAttachment.FileID,
|
|
||||||
Filesize: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
Hashcode: hashcode,
|
|
||||||
Mimetype: existsAttachment.Mimetype,
|
|
||||||
Type: existsAttachment.Type,
|
|
||||||
AuthorID: user.ID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save into database
|
|
||||||
err = database.C.Save(&attachment).Error
|
|
||||||
|
|
||||||
return attachment, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteAttachment(item models.Attachment) error {
|
|
||||||
var dupeCount int64
|
|
||||||
if err := database.C.
|
|
||||||
Where(&models.Attachment{Hashcode: item.Hashcode}).
|
|
||||||
Model(&models.Attachment{}).
|
|
||||||
Count(&dupeCount).Error; err != nil {
|
|
||||||
dupeCount = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := database.C.Delete(&item).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if dupeCount != -1 && dupeCount <= 1 {
|
|
||||||
// Safe for deletion the physics file
|
|
||||||
basepath := viper.GetString("content")
|
|
||||||
fullpath := filepath.Join(basepath, item.FileID)
|
|
||||||
|
|
||||||
os.Remove(fullpath)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
)
|
)
|
||||||
@ -19,6 +20,18 @@ func ListChannelMember(channelId uint) ([]models.ChannelMember, error) {
|
|||||||
return members, nil
|
return members, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetChannelMember(user models.Account, channelId uint) (models.ChannelMember, error) {
|
||||||
|
var member models.ChannelMember
|
||||||
|
|
||||||
|
if err := database.C.
|
||||||
|
Where(&models.ChannelMember{AccountID: user.ID, ChannelID: channelId}).
|
||||||
|
Find(&member).Error; err != nil {
|
||||||
|
return member, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return member, nil
|
||||||
|
}
|
||||||
|
|
||||||
func AddChannelMemberWithCheck(user models.Account, target models.Channel) error {
|
func AddChannelMemberWithCheck(user models.Account, target models.Channel) error {
|
||||||
if _, err := GetAccountFriend(user.ID, target.AccountID, 1); err != nil {
|
if _, err := GetAccountFriend(user.ID, target.AccountID, 1); err != nil {
|
||||||
return fmt.Errorf("you only can invite your friends to your channel")
|
return fmt.Errorf("you only can invite your friends to your channel")
|
||||||
|
@ -80,11 +80,9 @@ func GetAvailableChannel(id uint, user models.Account) (models.Channel, models.C
|
|||||||
|
|
||||||
func ListChannel(realmId ...uint) ([]models.Channel, error) {
|
func ListChannel(realmId ...uint) ([]models.Channel, error) {
|
||||||
var channels []models.Channel
|
var channels []models.Channel
|
||||||
tx := database.C.Preload("Account")
|
tx := database.C.Preload("Account").Preload("Realm")
|
||||||
if len(realmId) > 0 {
|
if len(realmId) > 0 {
|
||||||
tx = tx.Where("realm_id = ?", realmId)
|
tx = tx.Where("realm_id = ?", realmId)
|
||||||
} else {
|
|
||||||
tx = tx.Where("realm_id IS NULL")
|
|
||||||
}
|
}
|
||||||
if err := tx.Find(&channels).Error; err != nil {
|
if err := tx.Find(&channels).Error; err != nil {
|
||||||
return channels, err
|
return channels, err
|
||||||
@ -95,7 +93,7 @@ func ListChannel(realmId ...uint) ([]models.Channel, error) {
|
|||||||
|
|
||||||
func ListChannelWithUser(user models.Account, realmId ...uint) ([]models.Channel, error) {
|
func ListChannelWithUser(user models.Account, realmId ...uint) ([]models.Channel, error) {
|
||||||
var channels []models.Channel
|
var channels []models.Channel
|
||||||
tx := database.C.Where(&models.Channel{AccountID: user.ID})
|
tx := database.C.Where(&models.Channel{AccountID: user.ID}).Preload("Realm")
|
||||||
if len(realmId) > 0 {
|
if len(realmId) > 0 {
|
||||||
tx = tx.Where("realm_id = ?", realmId)
|
tx = tx.Where("realm_id = ?", realmId)
|
||||||
} else {
|
} else {
|
||||||
@ -121,7 +119,7 @@ func ListAvailableChannel(user models.Account, realmId ...uint) ([]models.Channe
|
|||||||
return item.ChannelID
|
return item.ChannelID
|
||||||
})
|
})
|
||||||
|
|
||||||
tx := database.C.Where("id IN ?", idx)
|
tx := database.C.Preload("Realm").Where("id IN ?", idx)
|
||||||
if len(realmId) > 0 {
|
if len(realmId) > 0 {
|
||||||
tx = tx.Where("realm_id = ?", realmId)
|
tx = tx.Where("realm_id = ?", realmId)
|
||||||
} else {
|
} else {
|
||||||
@ -134,23 +132,8 @@ func ListAvailableChannel(user models.Account, realmId ...uint) ([]models.Channe
|
|||||||
return channels, nil
|
return channels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChannel(user models.Account, alias, name, description string, isEncrypted bool, realmId ...uint) (models.Channel, error) {
|
func NewChannel(channel models.Channel) (models.Channel, error) {
|
||||||
channel := models.Channel{
|
|
||||||
Alias: alias,
|
|
||||||
Name: name,
|
|
||||||
Description: description,
|
|
||||||
IsEncrypted: isEncrypted,
|
|
||||||
AccountID: user.ID,
|
|
||||||
Members: []models.ChannelMember{
|
|
||||||
{AccountID: user.ID},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if len(realmId) > 0 {
|
|
||||||
channel.RealmID = &realmId[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
err := database.C.Save(&channel).Error
|
err := database.C.Save(&channel).Error
|
||||||
|
|
||||||
return channel, err
|
return channel, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DoAutoDatabaseCleanup() {
|
func DoAutoDatabaseCleanup() {
|
||||||
@ -16,18 +16,10 @@ func DoAutoDatabaseCleanup() {
|
|||||||
for _, model := range database.DatabaseAutoActionRange {
|
for _, model := range database.DatabaseAutoActionRange {
|
||||||
tx := database.C.Unscoped().Delete(model, "deleted_at >= ?", deadline)
|
tx := database.C.Unscoped().Delete(model, "deleted_at >= ?", deadline)
|
||||||
if tx.Error != nil {
|
if tx.Error != nil {
|
||||||
log.Error().Err(tx.Error).Msg("An error occurred when running auth context cleanup...")
|
log.Error().Err(tx.Error).Msg("An error occurred when running database cleanup...")
|
||||||
}
|
}
|
||||||
count += tx.RowsAffected
|
count += tx.RowsAffected
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up outdated chat history
|
|
||||||
tx := database.C.Unscoped().Delete(&models.Message{}, "created_at < ?", time.Now().Add(30*24*time.Hour))
|
|
||||||
if tx.Error != nil {
|
|
||||||
log.Error().Err(tx.Error).Msg("An error occurred when running auth context cleanup...")
|
|
||||||
} else {
|
|
||||||
count += tx.RowsAffected
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().Int64("affected", count).Msg("Clean up entire database accomplished.")
|
log.Debug().Int64("affected", count).Msg("Clean up entire database accomplished.")
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,33 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
"github.com/gofiber/contrib/websocket"
|
"github.com/gofiber/contrib/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
var wsConn = make(map[uint]map[*websocket.Conn]bool)
|
var (
|
||||||
|
wsMutex sync.Mutex
|
||||||
|
wsConn = make(map[uint]map[*websocket.Conn]bool)
|
||||||
|
)
|
||||||
|
|
||||||
func ClientRegister(user models.Account, conn *websocket.Conn) {
|
func ClientRegister(user models.Account, conn *websocket.Conn) {
|
||||||
|
wsMutex.Lock()
|
||||||
if wsConn[user.ID] == nil {
|
if wsConn[user.ID] == nil {
|
||||||
wsConn[user.ID] = make(map[*websocket.Conn]bool)
|
wsConn[user.ID] = make(map[*websocket.Conn]bool)
|
||||||
}
|
}
|
||||||
wsConn[user.ID][conn] = true
|
wsConn[user.ID][conn] = true
|
||||||
|
wsMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClientUnregister(user models.Account, conn *websocket.Conn) {
|
func ClientUnregister(user models.Account, conn *websocket.Conn) {
|
||||||
|
wsMutex.Lock()
|
||||||
if wsConn[user.ID] == nil {
|
if wsConn[user.ID] == nil {
|
||||||
wsConn[user.ID] = make(map[*websocket.Conn]bool)
|
wsConn[user.ID] = make(map[*websocket.Conn]bool)
|
||||||
}
|
}
|
||||||
delete(wsConn[user.ID], conn)
|
delete(wsConn[user.ID], conn)
|
||||||
|
wsMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func PushCommand(userId uint, task models.UnifiedCommand) {
|
func PushCommand(userId uint, task models.UnifiedCommand) {
|
||||||
|
@ -2,11 +2,11 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CountMessage(channel models.Channel) int64 {
|
func CountMessage(channel models.Channel) int64 {
|
||||||
@ -31,7 +31,6 @@ func ListMessage(channel models.Channel, take int, offset int) ([]models.Message
|
|||||||
ChannelID: channel.ID,
|
ChannelID: channel.ID,
|
||||||
}).Limit(take).Offset(offset).
|
}).Limit(take).Offset(offset).
|
||||||
Order("created_at DESC").
|
Order("created_at DESC").
|
||||||
Preload("Attachments").
|
|
||||||
Preload("ReplyTo").
|
Preload("ReplyTo").
|
||||||
Preload("ReplyTo.Sender").
|
Preload("ReplyTo.Sender").
|
||||||
Preload("ReplyTo.Sender.Account").
|
Preload("ReplyTo.Sender.Account").
|
||||||
@ -54,7 +53,6 @@ func GetMessage(channel models.Channel, id uint) (models.Message, error) {
|
|||||||
Preload("ReplyTo").
|
Preload("ReplyTo").
|
||||||
Preload("ReplyTo.Sender").
|
Preload("ReplyTo.Sender").
|
||||||
Preload("ReplyTo.Sender.Account").
|
Preload("ReplyTo.Sender.Account").
|
||||||
Preload("Attachments").
|
|
||||||
Preload("Sender").
|
Preload("Sender").
|
||||||
Preload("Sender.Account").
|
Preload("Sender.Account").
|
||||||
First(&message).Error; err != nil {
|
First(&message).Error; err != nil {
|
||||||
@ -78,9 +76,6 @@ func GetMessageWithPrincipal(channel models.Channel, member models.ChannelMember
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewMessage(message models.Message) (models.Message, error) {
|
func NewMessage(message models.Message) (models.Message, error) {
|
||||||
var decodedContent fiber.Map
|
|
||||||
_ = jsoniter.Unmarshal(message.Content, &decodedContent)
|
|
||||||
|
|
||||||
var members []models.ChannelMember
|
var members []models.ChannelMember
|
||||||
if err := database.C.Save(&message).Error; err != nil {
|
if err := database.C.Save(&message).Error; err != nil {
|
||||||
return message, err
|
return message, err
|
||||||
@ -91,12 +86,32 @@ func NewMessage(message models.Message) (models.Message, error) {
|
|||||||
message, _ = GetMessage(message.Channel, message.ID)
|
message, _ = GetMessage(message.Channel, message.ID)
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
if member.ID != message.Sender.ID {
|
if member.ID != message.Sender.ID {
|
||||||
// TODO Check the mentioned status
|
switch member.Notify {
|
||||||
if member.Notify == models.NotifyLevelAll {
|
case models.NotifyLevelNone:
|
||||||
displayText := "*encrypted message*"
|
continue
|
||||||
if decodedContent["algorithm"] == "plain" {
|
case models.NotifyLevelMentioned:
|
||||||
displayText, _ = decodedContent["value"].(string)
|
if val, ok := message.Content["metioned_users"]; ok {
|
||||||
|
if usernames, ok := val.([]string); ok {
|
||||||
|
if lo.Contains(usernames, member.Account.Name) {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayText string
|
||||||
|
if message.Content["algorithm"] == "plain" {
|
||||||
|
displayText, _ = message.Content["value"].(string)
|
||||||
|
} else {
|
||||||
|
displayText = "*encrypted message*"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(displayText) == 0 {
|
||||||
|
displayText = fmt.Sprintf("%d attachment(s)", len(message.Attachments))
|
||||||
|
}
|
||||||
|
|
||||||
err = NotifyAccount(member.Account,
|
err = NotifyAccount(member.Account,
|
||||||
fmt.Sprintf("New Message #%s", channel.Alias),
|
fmt.Sprintf("New Message #%s", channel.Alias),
|
||||||
fmt.Sprintf("%s: %s", message.Sender.Account.Name, displayText),
|
fmt.Sprintf("%s: %s", message.Sender.Account.Name, displayText),
|
||||||
@ -106,7 +121,6 @@ func NewMessage(message models.Message) (models.Message, error) {
|
|||||||
log.Warn().Err(err).Msg("An error occurred when trying notify user.")
|
log.Warn().Err(err).Msg("An error occurred when trying notify user.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
PushCommand(member.AccountID, models.UnifiedCommand{
|
PushCommand(member.AccountID, models.UnifiedCommand{
|
||||||
Action: "messages.new",
|
Action: "messages.new",
|
||||||
Payload: message,
|
Payload: message,
|
||||||
|
@ -10,14 +10,18 @@ secret = "LtTjzAGFLshwXhN4ZD4nG5KlMv1MWcsvfv03TSZYnT1VhiAnLIZFTnHUwR0XhGgi"
|
|||||||
content = "uploads"
|
content = "uploads"
|
||||||
|
|
||||||
[debug]
|
[debug]
|
||||||
database = true
|
database = false
|
||||||
print_routes = false
|
print_routes = false
|
||||||
|
|
||||||
[identity]
|
[paperclip]
|
||||||
|
endpoint = "http://localhost:8443"
|
||||||
|
grpc_endpoint = "localhost:7443"
|
||||||
|
|
||||||
|
[passport]
|
||||||
client_id = "solarecho"
|
client_id = "solarecho"
|
||||||
client_secret = "Z9k9AFTj^p"
|
client_secret = "Z9k9AFTj^p"
|
||||||
endpoint = "https://id.solsynth.dev"
|
endpoint = "http://localhost:8444"
|
||||||
grpc_endpoint = "id.solsynth.dev:7444"
|
grpc_endpoint = "localhost:7444"
|
||||||
|
|
||||||
[calling]
|
[calling]
|
||||||
api_key = "APIZwKRLAWaWa8d"
|
api_key = "APIZwKRLAWaWa8d"
|
||||||
@ -41,5 +45,5 @@ access_token_duration = 300
|
|||||||
refresh_token_duration = 2592000
|
refresh_token_duration = 2592000
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
dsn = "host=localhost dbname=hy_messaging port=5432 sslmode=disable"
|
dsn = "host=localhost user=postgres password=password dbname=hy_messaging port=5432 sslmode=disable"
|
||||||
prefix = "messaging_"
|
prefix = "messaging_"
|
||||||
|
Loading…
Reference in New Issue
Block a user