0.0.1
This commit is contained in:
parent
3c6748d5b3
commit
3afc92bccb
3
go.mod
3
go.mod
@ -3,9 +3,9 @@ module donat-widget
|
|||||||
go 1.23.0
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/georgysavva/scany/v2 v2.1.3
|
||||||
github.com/go-playground/validator/v10 v10.22.0
|
github.com/go-playground/validator/v10 v10.22.0
|
||||||
github.com/jackc/pgx/v5 v5.6.0
|
github.com/jackc/pgx/v5 v5.6.0
|
||||||
github.com/jcobhams/echovalidate/v2 v2.0.3
|
|
||||||
github.com/labstack/echo/v4 v4.12.0
|
github.com/labstack/echo/v4 v4.12.0
|
||||||
github.com/swaggo/echo-swagger v1.4.1
|
github.com/swaggo/echo-swagger v1.4.1
|
||||||
github.com/swaggo/swag v1.16.3
|
github.com/swaggo/swag v1.16.3
|
||||||
@ -29,6 +29,7 @@ require (
|
|||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/linxGnu/goseaweedfs v0.1.6 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
69
go.sum
69
go.sum
@ -1,50 +1,113 @@
|
|||||||
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
|
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
|
||||||
|
github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
|
github.com/georgysavva/scany/v2 v2.1.3 h1:Zd4zm/ej79Den7tBSU2kaTDPAH64suq4qlQdhiBeGds=
|
||||||
|
github.com/georgysavva/scany/v2 v2.1.3/go.mod h1:fqp9yHZzM/PFVa3/rYEC57VmDx+KDch0LoqrJzkvtos=
|
||||||
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||||
|
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||||
|
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||||
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||||
|
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
||||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jcobhams/echovalidate/v2 v2.0.3/go.mod h1:I9VVW+j88qwoJC0ugb9B2Olvc2w+RN66oDyrVaT+Gns=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
|
||||||
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
|
||||||
|
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
|
||||||
|
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/linxGnu/goseaweedfs v0.1.6 h1:qcCz0aBJlXVCVX+NiEnU+uGHMBvJR33U3PquzlEpcs8=
|
||||||
|
github.com/linxGnu/goseaweedfs v0.1.6/go.mod h1:cv43dFeG4S6HnLa7U9aYw+wD/uZEi66UmwKdforYuWo=
|
||||||
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
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-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/swaggo/echo-swagger v1.4.1 h1:Yf0uPaJWp1uRtDloZALyLnvdBeoEL5Kc7DtnjzO/TUk=
|
||||||
github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc=
|
github.com/swaggo/echo-swagger v1.4.1/go.mod h1:C8bSi+9yH2FLZsnhqMZLIZddpUxZdBYuNHbtaS1Hljc=
|
||||||
|
github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw=
|
||||||
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
|
||||||
|
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||||
|
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/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
|
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||||
|
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
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.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -2,7 +2,8 @@ package pg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgconn"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@ -33,40 +34,39 @@ func NewPgPool(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pg *Postgres) CreateTable(ctx context.Context) error {
|
func (pg *Postgres) CreateTable(ctx context.Context) error {
|
||||||
result, err := pg.db.Exec(ctx, createTableQuery)
|
_, err := pg.db.Exec(ctx, createTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(result)
|
|
||||||
|
_, err = pg.db.Exec(ctx, onUpdateTableQuery)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pg *Postgres) DropTable(ctx context.Context) error {
|
func (pg *Postgres) DropTable(ctx context.Context) error {
|
||||||
result, err := pg.db.Exec(ctx, dropTableQuery)
|
_, err := pg.db.Exec(ctx, dropTableQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(result)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pg *Postgres) Exec(ctx context.Context, query string, args ...interface{}) (interface{}, error) {
|
func (pg *Postgres) Exec(ctx context.Context, query string, args ...interface{}) (pgconn.CommandTag, error) {
|
||||||
result, err := pg.db.Exec(ctx, query, args...)
|
result, err := pg.db.Exec(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return result, err
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pg *Postgres) Query(ctx context.Context, query string, args ...interface{}) (interface{}, error) {
|
func (pg *Postgres) Query(ctx context.Context, query string, args ...interface{}) (pgx.Rows, error) {
|
||||||
result, err := pg.db.Query(ctx, query, args...)
|
result, err := pg.db.Query(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pg *Postgres) QueryRow(ctx context.Context, query string, args ...interface{}) interface{} {
|
|
||||||
result := pg.db.QueryRow(ctx, query, args...)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
@ -3,21 +3,29 @@ package pg
|
|||||||
var createTableQuery = `
|
var createTableQuery = `
|
||||||
CREATE TABLE IF NOT EXISTS widgets (
|
CREATE TABLE IF NOT EXISTS widgets (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
streamer_id INTEGER NOT NULL,
|
||||||
owner_id INTEGER NOT NULL,
|
template_id INTEGER NOT NULL,
|
||||||
text TEXT DEFAULT 'Текст доаната',
|
background_url TEXT DEFAULT '',
|
||||||
video TEXT DEFAULT '',
|
image_url TEXT DEFAULT '',
|
||||||
image TEXT DEFAULT '',
|
audio_url TEXT DEFAULT '',
|
||||||
audio TEXT DEFAULT '',
|
|
||||||
duration INTEGER DEFAULT 30,
|
duration INTEGER DEFAULT 30,
|
||||||
display BOOLEAN DEFAULT TRUE,
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS donats (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
widget_id INTEGER NOT NULL,
|
||||||
|
text TEXT DEFAULT '',
|
||||||
|
amount TEXT DEFAULT '',
|
||||||
|
donat_user TEXT DEFAULT '',
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
`
|
`
|
||||||
|
|
||||||
var onUpdateTableQuery = `
|
var onUpdateTableQuery = `
|
||||||
CREATE OR REPLACE FUNCTION update_updated_at()
|
CREATE OR REPLACE FUNCTION update_updated_at()
|
||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
NEW.updated_at = NOW();
|
NEW.updated_at = NOW();
|
||||||
@ -26,11 +34,17 @@ CREATE OR REPLACE FUNCTION update_updated_at()
|
|||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
|
|
||||||
CREATE TRIGGER update_updated_at_trigger
|
CREATE TRIGGER update_updated_at_trigger
|
||||||
BEFORE UPDATE ON test_users
|
BEFORE UPDATE ON widgets
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE update_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER update_updated_at_trigger
|
||||||
|
BEFORE UPDATE ON donats
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE update_updated_at();
|
EXECUTE PROCEDURE update_updated_at();
|
||||||
`
|
`
|
||||||
|
|
||||||
var dropTableQuery = `
|
var dropTableQuery = `
|
||||||
DROP TABLE IF EXISTS widgets;
|
DROP TABLE IF EXISTS widgets;
|
||||||
|
DROP TABLE IF EXISTS donats;
|
||||||
`
|
`
|
||||||
|
98
infrastructure/weed/weed.go
Normal file
98
infrastructure/weed/weed.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package weed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"github.com/linxGnu/goseaweedfs"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Weed struct {
|
||||||
|
operation *goseaweedfs.Seaweed
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWeed(
|
||||||
|
filer string,
|
||||||
|
masterUrl string,
|
||||||
|
|
||||||
|
) (*Weed, error) {
|
||||||
|
filers := []string{filer}
|
||||||
|
sw, err := goseaweedfs.NewSeaweed(
|
||||||
|
masterUrl,
|
||||||
|
filers,
|
||||||
|
8096,
|
||||||
|
&http.Client{Timeout: 5 * time.Minute},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return &Weed{}, err
|
||||||
|
}
|
||||||
|
return &Weed{sw}, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (weed *Weed) Upload(
|
||||||
|
file model.UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) (model.FileData, error) {
|
||||||
|
var fileData model.FileData
|
||||||
|
fileData, err := weed.operation.Upload(
|
||||||
|
*file,
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
collection,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fileData, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (weed *Weed) Download(
|
||||||
|
FileID model.FileID,
|
||||||
|
) (model.DownloadFile, error) {
|
||||||
|
var fileBuffer bytes.Buffer
|
||||||
|
|
||||||
|
_, err := weed.operation.Download(
|
||||||
|
string(FileID),
|
||||||
|
nil,
|
||||||
|
func(r io.Reader) error {
|
||||||
|
_, err := io.Copy(&fileBuffer, r)
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
)
|
||||||
|
file := fileBuffer.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
return file, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (weed *Weed) Update(
|
||||||
|
file model.UploadFile,
|
||||||
|
fileID model.FileID,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) error {
|
||||||
|
err := weed.operation.Replace(
|
||||||
|
string(fileID),
|
||||||
|
*file,
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
collection,
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1,52 +0,0 @@
|
|||||||
package widget
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"log/slog"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type requestModel struct {
|
|
||||||
UserId int `json:"userId" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type responseModel struct {
|
|
||||||
WidgetId int `json:"widgetId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Creator interface {
|
|
||||||
Create(ctx context.Context, userId int) (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create @Description Create widget
|
|
||||||
//
|
|
||||||
// @Tags Widget
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param RegisterData body requestModel true "Create widget"
|
|
||||||
// @Success 200 {object} responseModel
|
|
||||||
// @Router /api/widget/create [post]
|
|
||||||
func Create(service Creator, log *slog.Logger) echo.HandlerFunc {
|
|
||||||
return func(request echo.Context) error {
|
|
||||||
ctx := context.Background()
|
|
||||||
var widgetData requestModel
|
|
||||||
if err := request.Bind(&widgetData); err != nil {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
return echo.NewHTTPError(400, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
err := request.Validate(&widgetData)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
return echo.NewHTTPError(400, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := service.Create(ctx, widgetData.UserId)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
return request.JSON(422, err)
|
|
||||||
}
|
|
||||||
return request.String(200, strconv.FormatUint(uint64(id), 10))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package widget
|
|
99
internal/api/http/handlers/widget/donat/donat.go
Normal file
99
internal/api/http/handlers/widget/donat/donat.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package donat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type donatSetter interface {
|
||||||
|
SetDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
text string,
|
||||||
|
amount model.DonatAmount,
|
||||||
|
donatUser string,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
type SetDonatRequest struct {
|
||||||
|
WidgetID model.WidgetID `json:"widgetID" validate:"required"`
|
||||||
|
Text string `json:"text" validate:"required"`
|
||||||
|
Amount model.DonatAmount `json:"amount" validate:"required"`
|
||||||
|
DonatUser string `json:"donatUser" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDonat
|
||||||
|
//
|
||||||
|
// @Description Set donat
|
||||||
|
// @Tags Donat
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param RegisterData body SetDonatRequest true "Set donat"
|
||||||
|
// @Router /api/widget/donat/set [post]
|
||||||
|
func SetDonat(donatService donatSetter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var donatData SetDonatRequest
|
||||||
|
if err := request.Bind(&donatData); err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err := request.Validate(&donatData)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = donatService.SetDonat(
|
||||||
|
ctx,
|
||||||
|
donatData.WidgetID,
|
||||||
|
donatData.Text,
|
||||||
|
donatData.Amount,
|
||||||
|
donatData.DonatUser,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return request.JSON(500, "Set donat error")
|
||||||
|
}
|
||||||
|
slog.Info("donat set success")
|
||||||
|
return request.String(200, "Set donat success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type donatDeleter interface {
|
||||||
|
DeleteDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
DonatID model.DonatID,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDonat
|
||||||
|
//
|
||||||
|
// @Description Delete donat
|
||||||
|
// @Tags Donat
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Router /api/widget/donat/delete/{donatID} [post]
|
||||||
|
func DeleteDonat(donatService donatDeleter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
donatID, err := strconv.Atoi(request.Param("donatID"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(400, "Path parameter 'donatID' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = donatService.DeleteDonat(
|
||||||
|
ctx,
|
||||||
|
model.DonatID(donatID),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "Delete donat error")
|
||||||
|
}
|
||||||
|
slog.Info("Delete donat success")
|
||||||
|
return request.String(200, "Delete donat success")
|
||||||
|
}
|
||||||
|
}
|
210
internal/api/http/handlers/widget/media/media.go
Normal file
210
internal/api/http/handlers/widget/media/media.go
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
package media
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileSetter interface {
|
||||||
|
SetMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
file model.UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMediaFile
|
||||||
|
//
|
||||||
|
// @Description Upload media
|
||||||
|
// @Tags Media
|
||||||
|
// @Accept mpfd
|
||||||
|
// @Produce json
|
||||||
|
// @Param file formData file true "File to upload"
|
||||||
|
// @Param widgetId path int true "Widget ID"
|
||||||
|
// @Router /api/widget/media/{mediaType}/upload [post]
|
||||||
|
func SetMediaFile(service FileSetter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
widgetID, err := strconv.Atoi(request.FormValue("widgetID"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(404, "Path parameter 'widgetID' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType := request.Param("mediaType")
|
||||||
|
|
||||||
|
file, err := request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(404, "Form parameter 'file' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "File is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service.SetMediaFile(
|
||||||
|
ctx,
|
||||||
|
model.MediaType(mediaType),
|
||||||
|
model.WidgetID(widgetID),
|
||||||
|
&src,
|
||||||
|
file.Filename,
|
||||||
|
file.Size,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "File upload is failed")
|
||||||
|
}
|
||||||
|
slog.Info("set " + mediaType + " file successfully")
|
||||||
|
return request.String(200, "File successfully uploaded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileGetter interface {
|
||||||
|
GetMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
) (model.DownloadFile, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMediaFile
|
||||||
|
//
|
||||||
|
// @Description Get media
|
||||||
|
// @Produce application/octet-stream
|
||||||
|
// @Success 200 {array} byte
|
||||||
|
// @Param widgetId path int true "Widget ID"
|
||||||
|
// @Param mediaType path string true "'background' or 'image' or 'audio'"
|
||||||
|
// @Router /api/widget/media/{mediaType}/get/{widgetID} [post]
|
||||||
|
func GetMediaFile(service FileGetter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
mediaType := request.Param("mediaType")
|
||||||
|
if mediaType != "background" && mediaType != "image" && mediaType != "audio" {
|
||||||
|
return echo.NewHTTPError(400, "Path parameter 'mediaType' is invalid")
|
||||||
|
}
|
||||||
|
widgetID, err := strconv.Atoi(request.Param("widgetID"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(400, "Path parameter 'widgetID' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := service.GetMediaFile(
|
||||||
|
ctx,
|
||||||
|
model.WidgetID(widgetID),
|
||||||
|
model.MediaType(mediaType),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "Get File is failed")
|
||||||
|
}
|
||||||
|
slog.Info("get " + mediaType + " file successfully")
|
||||||
|
return request.Blob(200, "application/octet-stream", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileUpdater interface {
|
||||||
|
UpdateMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
file model.UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateMediaFile(service FileUpdater) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
widgetID, err := strconv.Atoi(request.FormValue("widgetID"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(404, "Path parameter 'widgetID' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType := request.Param("mediaType")
|
||||||
|
|
||||||
|
file, err := request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(404, "Form parameter 'file' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "File is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service.UpdateMediaFile(
|
||||||
|
ctx,
|
||||||
|
model.WidgetID(widgetID),
|
||||||
|
model.MediaType(mediaType),
|
||||||
|
&src,
|
||||||
|
file.Filename,
|
||||||
|
file.Size,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "File update is failed")
|
||||||
|
}
|
||||||
|
slog.Info("update media file successfully")
|
||||||
|
return request.String(200, "Media successfully uploaded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UrlSetter interface {
|
||||||
|
SetMediaUrl(
|
||||||
|
ctx context.Context,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaURL model.MediaUrl,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
type SetRequest struct {
|
||||||
|
WidgetID model.WidgetID `json:"widgetID" validate:"required"`
|
||||||
|
MediaUrl model.MediaUrl `json:"mediaUrl" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMediaUrl
|
||||||
|
//
|
||||||
|
// @Description Set media URL
|
||||||
|
// @Param mediaType path string true "'background' or 'image' or 'audio'"
|
||||||
|
// @Router /api/widget/media/{mediaType}/set [post]
|
||||||
|
func SetMediaUrl(service UrlSetter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var backgroundData SetRequest
|
||||||
|
if err := request.Bind(&backgroundData); err != nil {
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType := request.Param("mediaType")
|
||||||
|
|
||||||
|
err := request.Validate(&backgroundData)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service.SetMediaUrl(
|
||||||
|
ctx,
|
||||||
|
model.MediaType(mediaType),
|
||||||
|
backgroundData.WidgetID,
|
||||||
|
backgroundData.MediaUrl,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(500, "Set MediaUrl is failed")
|
||||||
|
}
|
||||||
|
slog.Info("Set media url successfully")
|
||||||
|
return request.String(200, "Media URL successfully set")
|
||||||
|
}
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package widget
|
|
212
internal/api/http/handlers/widget/widget.go
Normal file
212
internal/api/http/handlers/widget/widget.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type widgetCreator interface {
|
||||||
|
CreateWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
streamerID model.StreamerID,
|
||||||
|
templateID model.TemplateID,
|
||||||
|
) (model.WidgetID, error)
|
||||||
|
}
|
||||||
|
type CreateWidgetRequest struct {
|
||||||
|
StreamerID model.StreamerID `json:"streamerID" validate:"required"`
|
||||||
|
TemplateID model.TemplateID `json:"templateID" validate:"required"`
|
||||||
|
}
|
||||||
|
type CreateWidgetResponse struct {
|
||||||
|
WidgetID model.WidgetID `json:"widgetID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateWidget
|
||||||
|
//
|
||||||
|
// @Description Create widget
|
||||||
|
// @Tags Widget
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param RegisterData body CreateWidgetRequest true "Create widget"
|
||||||
|
// @Success 200 {object} CreateWidgetResponse
|
||||||
|
// @Router /api/widget/create [post]
|
||||||
|
func CreateWidget(widgetService widgetCreator) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var widgetData CreateWidgetRequest
|
||||||
|
if err := request.Bind(&widgetData); err != nil {
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err := request.Validate(&widgetData)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
widgetID, err := widgetService.CreateWidget(
|
||||||
|
ctx,
|
||||||
|
widgetData.StreamerID,
|
||||||
|
widgetData.TemplateID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return request.JSON(422, "Create widget error")
|
||||||
|
}
|
||||||
|
|
||||||
|
response := CreateWidgetResponse{
|
||||||
|
WidgetID: widgetID,
|
||||||
|
}
|
||||||
|
slog.Info("Widget created")
|
||||||
|
return request.JSON(200, response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type widgetHTMLGetter interface {
|
||||||
|
GetWidgetHTML(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) (model.WidgetHTML, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidgetHTML @Description Get widget
|
||||||
|
//
|
||||||
|
// @Tags Widget
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200
|
||||||
|
// @Router /api/widget/html/{widgetID} [get]
|
||||||
|
func GetWidgetHTML(widgetService widgetHTMLGetter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
widgetID, err := strconv.Atoi(request.Param("widgetID"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(400, "Path parameter 'widgetID' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
widgetHTML, err := widgetService.GetWidgetHTML(
|
||||||
|
ctx,
|
||||||
|
model.WidgetID(widgetID),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return request.JSON(500, "Get widget HTML error")
|
||||||
|
}
|
||||||
|
slog.Info("Get widget HTML successfully")
|
||||||
|
return request.HTML(200, string(widgetHTML))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type widgetInfoGetter interface {
|
||||||
|
GetWidgetInfo(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) (*model.DonatAndWidget, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetInfoResponse struct {
|
||||||
|
AudioUrl model.MediaUrl `json:"audioUrl"`
|
||||||
|
ImageUrl model.MediaUrl `json:"imageUrl"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Amount model.DonatAmount `json:"amount"`
|
||||||
|
DonatUser string `json:"donatUser"`
|
||||||
|
Display model.Display `json:"display"`
|
||||||
|
Duration model.Duration `json:"duration"`
|
||||||
|
DonatID model.DonatID `json:"donatID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidgetInfo
|
||||||
|
//
|
||||||
|
// @Description Widget Info
|
||||||
|
// @Tags Widget
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param widgetID path int true "Widget ID"
|
||||||
|
// @Router /api/widget/info/{widgetID} [get]
|
||||||
|
func GetWidgetInfo(widgetService widgetInfoGetter) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
widgetID, err := strconv.Atoi(request.Param("widgetID"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(400, "Path parameter 'widgetID' is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
donatAndWidget, err := widgetService.GetWidgetInfo(ctx, model.WidgetID(widgetID))
|
||||||
|
if err != nil {
|
||||||
|
return request.JSON(422, "Get widget info error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !donatAndWidget.Display {
|
||||||
|
response := GetInfoResponse{
|
||||||
|
Display: donatAndWidget.Display,
|
||||||
|
}
|
||||||
|
slog.Info("Get widget info successfully")
|
||||||
|
return request.JSON(200, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := GetInfoResponse{
|
||||||
|
AudioUrl: donatAndWidget.Widget.AudioUrl,
|
||||||
|
ImageUrl: donatAndWidget.Widget.ImageUrl,
|
||||||
|
Text: donatAndWidget.Donat.Text,
|
||||||
|
Display: donatAndWidget.Display,
|
||||||
|
Duration: donatAndWidget.Widget.Duration,
|
||||||
|
DonatUser: donatAndWidget.Donat.DonatUser,
|
||||||
|
Amount: donatAndWidget.Donat.Amount,
|
||||||
|
DonatID: donatAndWidget.Donat.ID,
|
||||||
|
}
|
||||||
|
slog.Info("Get widget info successfully")
|
||||||
|
return request.JSON(200, response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type widgetDurationUpdater interface {
|
||||||
|
UpdateWidgetDuration(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
duration model.Duration,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateDurationRequest struct {
|
||||||
|
WidgetID model.WidgetID `json:"widgetID" validate:"required"`
|
||||||
|
Duration model.Duration `json:"duration" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDuration
|
||||||
|
//
|
||||||
|
// @Description UpdateDuration
|
||||||
|
// @Tags Widget
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param UpdateData body UpdateDurationRequest true "UpdateDuration"
|
||||||
|
// @Success 200 {string}
|
||||||
|
// @Router /api/widget/duration/update [post]
|
||||||
|
func UpdateDuration(widgetService widgetDurationUpdater) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var widgetData UpdateDurationRequest
|
||||||
|
if err := request.Bind(&widgetData); err != nil {
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err := request.Validate(&widgetData)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(400, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = widgetService.UpdateWidgetDuration(
|
||||||
|
ctx,
|
||||||
|
widgetData.WidgetID,
|
||||||
|
widgetData.Duration,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return request.JSON(422, "Update duration error")
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("Duration updated")
|
||||||
|
return request.JSON(200, "Update duration successfully")
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,6 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
_ "donat-widget/api/http"
|
|
||||||
"donat-widget/infrastructure/pg"
|
|
||||||
widgetHandler "donat-widget/internal/api/http/handlers/widget"
|
|
||||||
"donat-widget/internal/config"
|
|
||||||
"donat-widget/pkg/validator"
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/swaggo/echo-swagger"
|
"github.com/swaggo/echo-swagger"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
@ -14,7 +9,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"donat-widget/infrastructure/pg"
|
||||||
|
"donat-widget/infrastructure/weed"
|
||||||
|
"donat-widget/internal/config"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"donat-widget/pkg/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
import (
|
||||||
|
widgetHandler "donat-widget/internal/api/http/handlers/widget"
|
||||||
widgetService "donat-widget/internal/service/widget"
|
widgetService "donat-widget/internal/service/widget"
|
||||||
|
|
||||||
|
mediaHandler "donat-widget/internal/api/http/handlers/widget/media"
|
||||||
|
mediaService "donat-widget/internal/service/widget/media"
|
||||||
|
|
||||||
|
donatHandler "donat-widget/internal/api/http/handlers/widget/donat"
|
||||||
|
donatService "donat-widget/internal/service/widget/donat"
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
@ -23,12 +33,12 @@ type App struct {
|
|||||||
|
|
||||||
func NewApp() *echo.Echo {
|
func NewApp() *echo.Echo {
|
||||||
app := &App{}
|
app := &App{}
|
||||||
cfg := app.InitConfig()
|
_ = app.InitLogger()
|
||||||
pool := app.initDB(cfg)
|
app.Config = app.InitConfig()
|
||||||
log := app.InitLogger()
|
db := app.initDB()
|
||||||
|
storage := app.InitStorage()
|
||||||
server := InitHTTPServer()
|
server := InitHTTPServer()
|
||||||
InitHandlers(server, pool, log)
|
InitHandlers(server, db, storage)
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
@ -48,26 +58,89 @@ func (a *App) InitConfig() *config.Config {
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initDB(cfg *config.Config) *pg.Postgres {
|
|
||||||
pool := pg.NewPgPool(
|
|
||||||
context.Background(),
|
|
||||||
cfg.Database.Username,
|
|
||||||
cfg.Database.Password,
|
|
||||||
cfg.Database.Host,
|
|
||||||
cfg.Database.Port,
|
|
||||||
cfg.Database.DBName,
|
|
||||||
)
|
|
||||||
return pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitHandlers(server *echo.Echo, pool *pg.Postgres, log *slog.Logger) {
|
|
||||||
PREFIX := "/api/widget"
|
|
||||||
server.GET("/api/docs/*", echoSwagger.WrapHandler)
|
|
||||||
widgetSvc := widgetService.New(pool)
|
|
||||||
server.GET(PREFIX+"/create", widgetHandler.Create(widgetSvc, log))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) InitLogger() *slog.Logger {
|
func (a *App) InitLogger() *slog.Logger {
|
||||||
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
||||||
|
slog.SetDefault(logger)
|
||||||
return logger
|
return logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) InitStorage() *weed.Weed {
|
||||||
|
storage, err := weed.NewWeed(
|
||||||
|
a.Config.Storage.Filer,
|
||||||
|
a.Config.Storage.Master,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return storage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) initDB() *pg.Postgres {
|
||||||
|
|
||||||
|
db := pg.NewPgPool(
|
||||||
|
context.Background(),
|
||||||
|
a.Config.Db.Username,
|
||||||
|
a.Config.Db.Password,
|
||||||
|
a.Config.Db.Host,
|
||||||
|
a.Config.Db.Port,
|
||||||
|
a.Config.Db.DBName,
|
||||||
|
)
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitHandlers(
|
||||||
|
server *echo.Echo,
|
||||||
|
db *pg.Postgres,
|
||||||
|
storage model.Storage,
|
||||||
|
) {
|
||||||
|
PREFIX := "/api/widget"
|
||||||
|
server.GET(PREFIX+"/docs/*", echoSwagger.WrapHandler)
|
||||||
|
server.GET(PREFIX+"/table/create", CreateTale(db))
|
||||||
|
server.GET(PREFIX+"/table/drop", DropTale(db))
|
||||||
|
|
||||||
|
widgetSvc := widgetService.New(db)
|
||||||
|
server.GET(PREFIX+"/create", widgetHandler.CreateWidget(widgetSvc))
|
||||||
|
server.GET(PREFIX+"/html/:widgetID", widgetHandler.GetWidgetHTML(widgetSvc))
|
||||||
|
server.GET(PREFIX+"/info/:widgetID", widgetHandler.GetWidgetInfo(widgetSvc))
|
||||||
|
server.GET(PREFIX+"/duration/update", widgetHandler.UpdateDuration(widgetSvc))
|
||||||
|
|
||||||
|
mediaSvc := mediaService.New(db, storage)
|
||||||
|
server.POST(PREFIX+"/media/:mediaType/upload", mediaHandler.SetMediaFile(mediaSvc))
|
||||||
|
server.GET(PREFIX+"/media/:mediaType/get/:widgetID", mediaHandler.GetMediaFile(mediaSvc))
|
||||||
|
server.POST(PREFIX+"/media/:mediaType/set", mediaHandler.SetMediaUrl(mediaSvc))
|
||||||
|
|
||||||
|
donatSvc := donatService.New(db)
|
||||||
|
server.POST(PREFIX+"/donat/set", donatHandler.SetDonat(donatSvc))
|
||||||
|
server.DELETE(PREFIX+"/donat/delete/:donatID", donatHandler.DeleteDonat(donatSvc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTale(db *pg.Postgres) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err := db.CreateTable(ctx)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("db.CreateTable: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("Create table ok")
|
||||||
|
return request.String(200, "Create table ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DropTale(db *pg.Postgres) echo.HandlerFunc {
|
||||||
|
return func(request echo.Context) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err := db.DropTable(ctx)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("db.DropTable: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("Dropped table ok")
|
||||||
|
return request.String(200, "Dropped table ok")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,10 +6,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Database DatabaseConfig `yaml:"db"`
|
Db Database `yaml:"db"`
|
||||||
|
Storage Storage `yaml:"storage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DatabaseConfig struct {
|
type Database struct {
|
||||||
Username string `yaml:"username"`
|
Username string `yaml:"username"`
|
||||||
Password string `yaml:"password"`
|
Password string `yaml:"password"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
@ -17,6 +18,11 @@ type DatabaseConfig struct {
|
|||||||
DBName string `yaml:"dbname"`
|
DBName string `yaml:"dbname"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Storage struct {
|
||||||
|
Filer string `yaml:"filer"`
|
||||||
|
Master string `yaml:"master"`
|
||||||
|
}
|
||||||
|
|
||||||
func Init() *Config {
|
func Init() *Config {
|
||||||
data, err := os.ReadFile("internal/config/config.yaml")
|
data, err := os.ReadFile("internal/config/config.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
db:
|
db:
|
||||||
port: "31004"
|
port: "5432"
|
||||||
host: "92.63.193.151"
|
host: "80.87.195.79"
|
||||||
password: "FSefebvrebre"
|
password: "test"
|
||||||
username: "admin"
|
username: "test"
|
||||||
dbname: "user_db"
|
dbname: "test"
|
||||||
|
|
||||||
server:
|
server:
|
||||||
port: "8002"
|
port: "8002"
|
||||||
|
|
||||||
|
storage:
|
||||||
|
filer: "http://92.63.193.151:8111"
|
||||||
|
master: "http://92.63.193.151:9333"
|
110
internal/model/interfaces.go
Normal file
110
internal/model/interfaces.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgconn"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Storage interface {
|
||||||
|
Upload(
|
||||||
|
file UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) (FileData, error)
|
||||||
|
Download(
|
||||||
|
FileID FileID,
|
||||||
|
) (DownloadFile, error)
|
||||||
|
Update(
|
||||||
|
file UploadFile,
|
||||||
|
fileID FileID,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type WidgetRepo interface {
|
||||||
|
CreateWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
streamerID StreamerID,
|
||||||
|
templateId TemplateID,
|
||||||
|
) (WidgetID, error)
|
||||||
|
|
||||||
|
DeleteWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
) error
|
||||||
|
|
||||||
|
GetWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
) (*Widget, error)
|
||||||
|
|
||||||
|
UpdateWidgetDuration(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
duration Duration,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type DonatRepo interface {
|
||||||
|
SetDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
text string,
|
||||||
|
amount DonatAmount,
|
||||||
|
donatUser string,
|
||||||
|
) error
|
||||||
|
GetDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
) ([]*Donat, error)
|
||||||
|
DeleteDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
donatID DonatID,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaRepo interface {
|
||||||
|
SetMediaFile(
|
||||||
|
file UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) (FileID, error)
|
||||||
|
GetMediaFile(
|
||||||
|
fileID FileID,
|
||||||
|
) (DownloadFile, error)
|
||||||
|
GetMediaUrl(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
mediaType MediaType,
|
||||||
|
) (MediaUrl, error)
|
||||||
|
SetMediaUrl(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
mediaUrl MediaUrl,
|
||||||
|
mediaType MediaType,
|
||||||
|
) error
|
||||||
|
UpdateMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID WidgetID,
|
||||||
|
file UploadFile,
|
||||||
|
fileID FileID,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
mediaType MediaType,
|
||||||
|
) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error interface {
|
||||||
|
Error() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Db interface {
|
||||||
|
Exec(ctx context.Context, query string, args ...interface{}) (pgconn.CommandTag, error)
|
||||||
|
Query(ctx context.Context, query string, args ...interface{}) (pgx.Rows, error)
|
||||||
|
}
|
33
internal/model/models.go
Normal file
33
internal/model/models.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Widget struct {
|
||||||
|
ID WidgetID
|
||||||
|
StreamerID StreamerID
|
||||||
|
TemplateID TemplateID
|
||||||
|
BackgroundUrl MediaUrl
|
||||||
|
ImageUrl MediaUrl
|
||||||
|
AudioUrl MediaUrl
|
||||||
|
Duration Duration
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type Donat struct {
|
||||||
|
ID DonatID
|
||||||
|
WidgetID WidgetID
|
||||||
|
Text string
|
||||||
|
DonatUser string
|
||||||
|
Amount DonatAmount
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type DonatAndWidget struct {
|
||||||
|
Widget *Widget
|
||||||
|
Donat *Donat
|
||||||
|
Display Display
|
||||||
|
}
|
25
internal/model/types.go
Normal file
25
internal/model/types.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/linxGnu/goseaweedfs"
|
||||||
|
"mime/multipart"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StreamerID int
|
||||||
|
type WidgetID int
|
||||||
|
type TemplateID int
|
||||||
|
type Duration int
|
||||||
|
type MediaUrl string
|
||||||
|
type MediaType string
|
||||||
|
type Display bool
|
||||||
|
|
||||||
|
type Widgets []*Widget
|
||||||
|
type WidgetHTML string
|
||||||
|
|
||||||
|
type FileData *goseaweedfs.FilePart
|
||||||
|
type UploadFile *multipart.File
|
||||||
|
type DownloadFile []byte
|
||||||
|
type FileID string
|
||||||
|
|
||||||
|
type DonatAmount string
|
||||||
|
type DonatID int
|
124
internal/model/widget-templates.go
Normal file
124
internal/model/widget-templates.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func GetTemplate1(
|
||||||
|
widgetID WidgetID,
|
||||||
|
backgroundUrl MediaUrl,
|
||||||
|
) WidgetHTML {
|
||||||
|
|
||||||
|
style := fmt.Sprintf(`body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
background-image: url('%s');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
#content img {
|
||||||
|
width: 50vw;
|
||||||
|
height: 50vh;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content audio {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content p {
|
||||||
|
font-size: 60px;
|
||||||
|
}
|
||||||
|
`, backgroundUrl)
|
||||||
|
|
||||||
|
script := fmt.Sprintf(`let widgetID = '%v'
|
||||||
|
let baseUrl = 'http://localhost:8002/api/widget'
|
||||||
|
|
||||||
|
function delay(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getWidgetInfo() {
|
||||||
|
let response = await fetch(baseUrl + '/info/' + widgetID);
|
||||||
|
let widget = await response.json();
|
||||||
|
return widget
|
||||||
|
}
|
||||||
|
|
||||||
|
function addImage(imageUrl) {
|
||||||
|
img = document.createElement('img');
|
||||||
|
img.src = imageUrl + '?t=' + new Date().getTime();
|
||||||
|
contentDiv.appendChild(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addText(text) {
|
||||||
|
p = document.createElement('p');
|
||||||
|
p.innerHTML = text;
|
||||||
|
contentDiv.appendChild(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAudio(audioUrl) {
|
||||||
|
audio = document.createElement('audio');
|
||||||
|
audio.src = audioUrl;
|
||||||
|
audio.autoplay = true;
|
||||||
|
audio.controls = false;
|
||||||
|
contentDiv.appendChild(audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function endDonat(donatID) {
|
||||||
|
if (audio) {
|
||||||
|
audio.pause();
|
||||||
|
audio.remove();
|
||||||
|
}
|
||||||
|
while (contentDiv.firstChild) {
|
||||||
|
contentDiv.removeChild(contentDiv.firstChild);
|
||||||
|
}
|
||||||
|
let response = await fetch(baseUrl + '/donat/delete/' + String(donatID), {method: 'DELETE'});
|
||||||
|
}
|
||||||
|
|
||||||
|
let audio;
|
||||||
|
const contentDiv = document.getElementById('content');
|
||||||
|
|
||||||
|
async function widgetView() {
|
||||||
|
while (true) {
|
||||||
|
let widget = await getWidgetInfo()
|
||||||
|
console.log(widget);
|
||||||
|
if (!widget.display) {
|
||||||
|
await delay(5 * 1000);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addImage(widget.imageUrl)
|
||||||
|
addText(widget.text + widget.amount)
|
||||||
|
addAudio(widget.audioUrl)
|
||||||
|
|
||||||
|
await delay(widget.duration * 1000);
|
||||||
|
await endDonat(widget.donatID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
widgetView()`, widgetID)
|
||||||
|
|
||||||
|
template1 := fmt.Sprintf(`<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<style>
|
||||||
|
%s
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id='content'>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
%s
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>`, style, script)
|
||||||
|
return WidgetHTML(template1)
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package model
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1,32 +0,0 @@
|
|||||||
package widget
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
)
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Id int `json:"id"`
|
|
||||||
Login string `json:"login"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) Create(
|
|
||||||
ctx context.Context,
|
|
||||||
userId int,
|
|
||||||
) (int, error) {
|
|
||||||
query := `
|
|
||||||
INSERT INTO widgets (userId)
|
|
||||||
VALUES (@userId);
|
|
||||||
`
|
|
||||||
args := pgx.NamedArgs{
|
|
||||||
"userId": userId,
|
|
||||||
}
|
|
||||||
result, err := r.Exec(ctx, query, args)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
widgetId := 9
|
|
||||||
fmt.Println(result)
|
|
||||||
return widgetId, nil
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
package widget
|
|
95
internal/repository/widget/donat/donat.go
Normal file
95
internal/repository/widget/donat/donat.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package donat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"github.com/georgysavva/scany/v2/pgxscan"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db model.Db,
|
||||||
|
) *RepoDonat {
|
||||||
|
return &RepoDonat{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepoDonat struct {
|
||||||
|
db model.Db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoDonat *RepoDonat) SetDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
text string,
|
||||||
|
amount model.DonatAmount,
|
||||||
|
donatUser string,
|
||||||
|
) error {
|
||||||
|
query := `
|
||||||
|
INSERT INTO donats (widget_id, text, amount, donat_user)
|
||||||
|
VALUES (@widget_id, @text, @amount, @donat_user);
|
||||||
|
`
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"widget_id": widgetID,
|
||||||
|
"text": text,
|
||||||
|
"amount": amount,
|
||||||
|
"donat_user": donatUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := repoDonat.db.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoDonat.db.Query: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoDonat *RepoDonat) GetDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) ([]*model.Donat, error) {
|
||||||
|
query := `
|
||||||
|
SELECT * FROM donats WHERE widget_id = (@widget_id);
|
||||||
|
`
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"widget_id": widgetID,
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := repoDonat.db.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoDonat.db.Query: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var donats []*model.Donat
|
||||||
|
|
||||||
|
err = pgxscan.ScanAll(&donats, rows)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.pgxscan.ScanAll: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return donats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoDonat *RepoDonat) DeleteDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
donatID model.DonatID,
|
||||||
|
) error {
|
||||||
|
query := `
|
||||||
|
DELETE FROM donats WHERE id = (@id);
|
||||||
|
`
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"id": donatID,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := repoDonat.db.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoDonat.db.Query: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
package widget
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Pool interface {
|
|
||||||
Exec(ctx context.Context, query string, args ...interface{}) (interface{}, error)
|
|
||||||
Query(ctx context.Context, query string, args ...interface{}) (interface{}, error)
|
|
||||||
QueryRow(ctx context.Context, query string, args ...interface{}) interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Repository struct {
|
|
||||||
Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(pool Pool) *Repository {
|
|
||||||
return &Repository{pool}
|
|
||||||
}
|
|
169
internal/repository/widget/media/media.go
Normal file
169
internal/repository/widget/media/media.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package media
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/georgysavva/scany/v2/pgxscan"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db model.Db,
|
||||||
|
storage model.Storage,
|
||||||
|
) *RepoMedia {
|
||||||
|
return &RepoMedia{db, storage}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepoMedia struct {
|
||||||
|
db model.Db
|
||||||
|
storage model.Storage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoMedia *RepoMedia) SetMediaFile(
|
||||||
|
file model.UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) (model.FileID, error) {
|
||||||
|
fileData, err := repoMedia.storage.Upload(
|
||||||
|
file,
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
collection,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.storage.Upload: " + err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fileID := fileData.FileID
|
||||||
|
|
||||||
|
return model.FileID(fileID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoMedia *RepoMedia) GetMediaFile(
|
||||||
|
fileID model.FileID,
|
||||||
|
) (model.DownloadFile, error) {
|
||||||
|
file, err := repoMedia.storage.Download(fileID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.storage.Download: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return file, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoMedia *RepoMedia) UpdateMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
file model.UploadFile,
|
||||||
|
fileID model.FileID,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
) error {
|
||||||
|
err := repoMedia.storage.Update(
|
||||||
|
file,
|
||||||
|
fileID,
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
collection,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.storage.Update: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType = mediaType + "_url"
|
||||||
|
query := fmt.Sprintf(`
|
||||||
|
UPDATE widgets
|
||||||
|
SET %s = (@%s)
|
||||||
|
WHERE id = (@id)
|
||||||
|
`, mediaType, mediaType)
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
string(mediaType): model.MediaUrl(fileID),
|
||||||
|
"id": widgetID,
|
||||||
|
}
|
||||||
|
_, err = repoMedia.db.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.db.Query: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoMedia *RepoMedia) SetMediaUrl(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaUrl model.MediaUrl,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
) error {
|
||||||
|
mediaType = mediaType + "_url"
|
||||||
|
query := fmt.Sprintf(`
|
||||||
|
UPDATE widgets
|
||||||
|
SET %s = (@%s)
|
||||||
|
WHERE id = (@id)
|
||||||
|
`, mediaType, mediaType)
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
string(mediaType): mediaUrl,
|
||||||
|
"id": widgetID,
|
||||||
|
}
|
||||||
|
_, err := repoMedia.db.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.db.Query: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repoMedia *RepoMedia) GetMediaUrl(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
) (model.MediaUrl, error) {
|
||||||
|
mediaType = mediaType + "_url"
|
||||||
|
query := fmt.Sprintf(`
|
||||||
|
SELECT %s
|
||||||
|
FROM widgets
|
||||||
|
WHERE id = (@id)
|
||||||
|
`, mediaType)
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"id": widgetID,
|
||||||
|
}
|
||||||
|
|
||||||
|
var widgets []*model.Widget
|
||||||
|
rows, err := repoMedia.db.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.db.Query: " + err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pgxscan.ScanAll(&widgets, rows)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("repoMedia.pgxscan.ScanAll: " + err.Error())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(widgets) == 0 {
|
||||||
|
slog.Error("Widget does not exist")
|
||||||
|
return "", errors.New("widget does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
widget := widgets[0]
|
||||||
|
var mediaUrl model.MediaUrl
|
||||||
|
|
||||||
|
if mediaType == "background_url" {
|
||||||
|
mediaUrl = widget.BackgroundUrl
|
||||||
|
} else if mediaType == "image_url" {
|
||||||
|
mediaUrl = widget.ImageUrl
|
||||||
|
} else if mediaType == "audio_url" {
|
||||||
|
mediaUrl = widget.AudioUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
return mediaUrl, nil
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package widget
|
|
128
internal/repository/widget/widget.go
Normal file
128
internal/repository/widget/widget.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
"errors"
|
||||||
|
"github.com/georgysavva/scany/v2/pgxscan"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db model.Db,
|
||||||
|
) *RepoWidget {
|
||||||
|
return &RepoWidget{db}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepoWidget struct {
|
||||||
|
model.Db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetRepo *RepoWidget) CreateWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
streamerID model.StreamerID,
|
||||||
|
templateID model.TemplateID,
|
||||||
|
) (model.WidgetID, error) {
|
||||||
|
query := `
|
||||||
|
INSERT INTO widgets (streamer_id, template_id)
|
||||||
|
VALUES (@streamer_id, @template_id);
|
||||||
|
`
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"streamer_id": streamerID,
|
||||||
|
"template_id": templateID,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := widgetRepo.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetRepo.Query: " + err.Error())
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
widgetID := 9
|
||||||
|
return model.WidgetID(widgetID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetRepo *RepoWidget) GetWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) (*model.Widget, error) {
|
||||||
|
query := `
|
||||||
|
SELECT * FROM widgets
|
||||||
|
WHERE id = (@id);
|
||||||
|
`
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"id": widgetID,
|
||||||
|
}
|
||||||
|
|
||||||
|
var widgets []*model.Widget
|
||||||
|
rows, err := widgetRepo.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetRepo.Query: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pgxscan.ScanAll(&widgets, rows)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(widgets) == 0 {
|
||||||
|
slog.Error("Widget not found")
|
||||||
|
return nil, errors.New("widget not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
widget := widgets[0]
|
||||||
|
|
||||||
|
selfDomain := "http://localhost:8002/api/widget/media"
|
||||||
|
strWidgetID := strconv.Itoa(int(widgetID))
|
||||||
|
if !strings.Contains(string(widget.ImageUrl), "http") && widget.ImageUrl != "" {
|
||||||
|
widget.ImageUrl = model.MediaUrl(selfDomain + "/image/get/" + strWidgetID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(widget.BackgroundUrl), "http") && widget.BackgroundUrl != "" {
|
||||||
|
widget.BackgroundUrl = model.MediaUrl(selfDomain + "/background/get/" + strWidgetID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(widget.AudioUrl), "http") && widget.AudioUrl != "" {
|
||||||
|
widget.AudioUrl = model.MediaUrl(selfDomain + "/audio/get/" + strWidgetID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return widget, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetRepo *RepoWidget) DeleteWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) error {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetRepo *RepoWidget) UpdateWidgetDuration(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
duration model.Duration,
|
||||||
|
) error {
|
||||||
|
query := `
|
||||||
|
UPDATE widgets
|
||||||
|
SET duration = (@duration)
|
||||||
|
WHERE id = (@id)
|
||||||
|
`
|
||||||
|
|
||||||
|
args := pgx.NamedArgs{
|
||||||
|
"id": widgetID,
|
||||||
|
"duration": duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := widgetRepo.Query(ctx, query, args)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetRepo.Query: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1 +0,0 @@
|
|||||||
package content
|
|
@ -1,17 +0,0 @@
|
|||||||
package widget
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CreatorRepository interface {
|
|
||||||
Create(ctx context.Context, userId int) (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (service *Service) Create(ctx context.Context, userId int) (int, error) {
|
|
||||||
widgetId, err := service.repository.Create(ctx, userId)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return widgetId, nil
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package widget
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"donat-widget/infrastructure/pg"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Deleter interface {
|
|
||||||
Delete(ctx context.Context) (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteWidget(pool *pg.Postgres) func(ctx context.Context, repository Deleter) int {
|
|
||||||
return func(ctx context.Context, repository Deleter) int {
|
|
||||||
return 8
|
|
||||||
}
|
|
||||||
}
|
|
56
internal/service/widget/donat/donat.go
Normal file
56
internal/service/widget/donat/donat.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package donat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
mediaRepo "donat-widget/internal/repository/widget/donat"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceDonat struct {
|
||||||
|
donatRepo model.DonatRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db model.Db,
|
||||||
|
) *ServiceDonat {
|
||||||
|
return &ServiceDonat{
|
||||||
|
donatRepo: mediaRepo.New(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (donatService *ServiceDonat) SetDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
text string,
|
||||||
|
amount model.DonatAmount,
|
||||||
|
donatUser string,
|
||||||
|
) error {
|
||||||
|
err := donatService.donatRepo.SetDonat(
|
||||||
|
ctx,
|
||||||
|
widgetID,
|
||||||
|
text,
|
||||||
|
amount,
|
||||||
|
donatUser,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("donatService.donatRepo.SetDonat: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (donatService *ServiceDonat) DeleteDonat(
|
||||||
|
ctx context.Context,
|
||||||
|
donatID model.DonatID,
|
||||||
|
) error {
|
||||||
|
err := donatService.donatRepo.DeleteDonat(
|
||||||
|
ctx,
|
||||||
|
donatID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("donatService.donatRepo.DeleteDonat: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
package widget
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
widgetRepository "donat-widget/internal/repository/widget"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Repository interface {
|
|
||||||
Create(ctx context.Context, userId int) (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
repository Repository
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(pool widgetRepository.Pool) *Service {
|
|
||||||
repository := widgetRepository.New(pool)
|
|
||||||
return &Service{repository: repository}
|
|
||||||
}
|
|
135
internal/service/widget/media/media.go
Normal file
135
internal/service/widget/media/media.go
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package media
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
mediaRepo "donat-widget/internal/repository/widget/media"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceMedia struct {
|
||||||
|
mediaRepo model.MediaRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(
|
||||||
|
db model.Db,
|
||||||
|
storage model.Storage,
|
||||||
|
) *ServiceMedia {
|
||||||
|
return &ServiceMedia{
|
||||||
|
mediaRepo: mediaRepo.New(db, storage),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mediaService *ServiceMedia) SetMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
file model.UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) error {
|
||||||
|
fileID, err := mediaService.mediaRepo.SetMediaFile(
|
||||||
|
file,
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
collection,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.mediaRepo.SetMediaFile: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mediaService.SetMediaUrl(
|
||||||
|
ctx,
|
||||||
|
mediaType,
|
||||||
|
widgetID,
|
||||||
|
model.MediaUrl(fileID),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.SetMediaUrl: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mediaService *ServiceMedia) GetMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
) (model.DownloadFile, error) {
|
||||||
|
fileID, err := mediaService.mediaRepo.GetMediaUrl(
|
||||||
|
ctx,
|
||||||
|
widgetID,
|
||||||
|
mediaType,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.mediaRepo.GetMediaUrl: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := mediaService.mediaRepo.GetMediaFile(
|
||||||
|
model.FileID(fileID),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.mediaRepo.GetMediaFile: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mediaService *ServiceMedia) UpdateMediaFile(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
file model.UploadFile,
|
||||||
|
filename string,
|
||||||
|
size int64,
|
||||||
|
collection string,
|
||||||
|
) error {
|
||||||
|
fileID, err := mediaService.mediaRepo.GetMediaUrl(
|
||||||
|
ctx,
|
||||||
|
widgetID,
|
||||||
|
mediaType,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.mediaRepo.GetMediaUrl: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mediaService.mediaRepo.UpdateMediaFile(
|
||||||
|
ctx,
|
||||||
|
widgetID,
|
||||||
|
file,
|
||||||
|
model.FileID(fileID),
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
collection,
|
||||||
|
mediaType,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.mediaRepo.UpdateMediaFile: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mediaService *ServiceMedia) SetMediaUrl(
|
||||||
|
ctx context.Context,
|
||||||
|
mediaType model.MediaType,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
mediaUrl model.MediaUrl,
|
||||||
|
) error {
|
||||||
|
err := mediaService.mediaRepo.SetMediaUrl(
|
||||||
|
ctx,
|
||||||
|
widgetID,
|
||||||
|
mediaUrl,
|
||||||
|
mediaType,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("mediaService.mediaRepo.SetMediaUrl: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package widget
|
|
122
internal/service/widget/widget.go
Normal file
122
internal/service/widget/widget.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package widget
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"donat-widget/internal/model"
|
||||||
|
widgetRepo "donat-widget/internal/repository/widget"
|
||||||
|
donatRepo "donat-widget/internal/repository/widget/donat"
|
||||||
|
"log/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceWidget struct {
|
||||||
|
widgetRepo model.WidgetRepo
|
||||||
|
donatRepo model.DonatRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(db model.Db) *ServiceWidget {
|
||||||
|
return &ServiceWidget{
|
||||||
|
widgetRepo: widgetRepo.New(db),
|
||||||
|
donatRepo: donatRepo.New(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetService *ServiceWidget) CreateWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
streamerID model.StreamerID,
|
||||||
|
templateID model.TemplateID,
|
||||||
|
) (model.WidgetID, error) {
|
||||||
|
widgetID, err := widgetService.widgetRepo.CreateWidget(ctx, streamerID, templateID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetService.widgetRepo.CreateWidget: " + err.Error())
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return widgetID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetService *ServiceWidget) DeleteWidget(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) error {
|
||||||
|
err := widgetService.widgetRepo.DeleteWidget(ctx, widgetID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetService.widgetRepo.DeleteWidget: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetService *ServiceWidget) GetWidgetHTML(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) (model.WidgetHTML, error) {
|
||||||
|
var widgetHTML model.WidgetHTML
|
||||||
|
|
||||||
|
widget, err := widgetService.widgetRepo.GetWidget(ctx, widgetID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetService.widgetRepo.GetWidget: " + err.Error())
|
||||||
|
return widgetHTML, err
|
||||||
|
}
|
||||||
|
|
||||||
|
backgroundUrl := widget.BackgroundUrl
|
||||||
|
|
||||||
|
templateID := widget.TemplateID
|
||||||
|
|
||||||
|
if templateID == 1 {
|
||||||
|
widgetHTML = model.GetTemplate1(
|
||||||
|
widgetID,
|
||||||
|
backgroundUrl,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return widgetHTML, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetService *ServiceWidget) GetWidgetInfo(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
) (*model.DonatAndWidget, error) {
|
||||||
|
|
||||||
|
widget, err := widgetService.widgetRepo.GetWidget(ctx, widgetID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetService.widgetRepo.GetWidget: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
donats, err := widgetService.donatRepo.GetDonat(ctx, widgetID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetService.donatRepo.GetDonat: " + err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var donatAndWidget model.DonatAndWidget
|
||||||
|
if len(donats) == 0 {
|
||||||
|
donatAndWidget = model.DonatAndWidget{
|
||||||
|
Display: false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
donatAndWidget = model.DonatAndWidget{
|
||||||
|
Widget: widget,
|
||||||
|
Donat: donats[0],
|
||||||
|
Display: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &donatAndWidget, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widgetService *ServiceWidget) UpdateWidgetDuration(
|
||||||
|
ctx context.Context,
|
||||||
|
widgetID model.WidgetID,
|
||||||
|
duration model.Duration,
|
||||||
|
) error {
|
||||||
|
err := widgetService.widgetRepo.UpdateWidgetDuration(
|
||||||
|
ctx,
|
||||||
|
widgetID,
|
||||||
|
duration,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("widgetService.widgetRepo.UpdateWidgetDuration: " + err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user