From 7eca62ee16eac2e4ac9345cfe263f26620b4814a Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Wed, 11 Dec 2024 13:29:24 +0100 Subject: [PATCH 01/10] Rewrote queries to use GORM --- go.mod | 15 +- go.sum | 58 +++- share/model.go | 209 +++++++++++++++ share/sql/sql.go | 676 +++++++++++++++++------------------------------ 4 files changed, 507 insertions(+), 451 deletions(-) create mode 100644 share/model.go diff --git a/go.mod b/go.mod index 51b7381..f916b3a 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/cs3org/go-cs3apis v0.0.0-20240802083356-d617314e1795 github.com/cs3org/reva v1.27.0 github.com/disintegration/imaging v1.6.2 - github.com/go-chi/chi/v5 v5.0.12 - github.com/go-sql-driver/mysql v1.8.0 + github.com/go-chi/chi/v5 v5.1.0 + github.com/go-sql-driver/mysql v1.8.1 github.com/gomodule/redigo v1.9.2 github.com/juliangruber/go-intersect v1.1.0 github.com/mitchellh/mapstructure v1.5.0 @@ -17,6 +17,9 @@ require ( github.com/rs/zerolog v1.32.0 google.golang.org/genproto v0.0.0-20240314234333-6e1732d8331c google.golang.org/grpc v1.65.0 + gorm.io/datatypes v1.2.4 + gorm.io/driver/mysql v1.5.7 + gorm.io/gorm v1.25.12 ) require ( @@ -41,6 +44,8 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.16 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -53,9 +58,9 @@ require ( golang.org/x/crypto v0.23.0 // indirect golang.org/x/image v0.13.0 // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect google.golang.org/protobuf v1.34.1 // indirect ) diff --git a/go.sum b/go.sum index 15195f5..ab0bd75 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,8 @@ github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9 h1:3um08ooi0/lyR github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9/go.mod h1:EJaddanP+JfU3UkVvn0rYYF3b/gD7eZRejbTHqiQExA= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -51,13 +51,18 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4= -github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s= @@ -71,6 +76,18 @@ github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +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/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= +github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/juliangruber/go-intersect v1.1.0 h1:sc+y5dCjMMx0pAdYk/N6KBm00tD/f3tq+Iox7dYDUrY= github.com/juliangruber/go-intersect v1.1.0/go.mod h1:WMau+1kAmnlQnKiikekNJbtGtfmILU/mMU6H7AgKbWQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -89,6 +106,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= +github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= github.com/mileusna/useragent v1.3.4 h1:MiuRRuvGjEie1+yZHO88UBYg8YBC/ddF6T7F56i3PCk= github.com/mileusna/useragent v1.3.4/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -156,8 +177,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -170,8 +191,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -183,8 +204,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -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/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -193,8 +214,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -212,5 +233,18 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= +gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4= +gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI= +gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= +gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= +gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= +gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= +gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= +gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= +gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= diff --git a/share/model.go b/share/model.go new file mode 100644 index 0000000..040fa3f --- /dev/null +++ b/share/model.go @@ -0,0 +1,209 @@ +package share + +import ( + "strconv" + "time" + + grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" + userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" + resourcespb "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" + link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + conversions "github.com/cs3org/reva/pkg/cbox/utils" + + "gorm.io/datatypes" + "gorm.io/gorm" +) + +// +---------------------------------+-----------------+------+-----+---------+----------------+ +// | Field | Type | Null | Key | Default | Extra | +// +---------------------------------+-----------------+------+-----+---------+----------------+ +// | id | int | NO | PRI | NULL | auto_increment | +// | share_type | smallint | NO | | 0 | | +// | share_with | varchar(255) | YES | | NULL | | +// | uid_owner | varchar(64) | NO | | | | +// | uid_initiator | varchar(64) | YES | | NULL | | +// | parent | int | YES | | NULL | | +// | item_type | varchar(64) | NO | MUL | | | +// | item_source | varchar(255) | YES | | NULL | | +// | item_target | varchar(255) | YES | | NULL | | +// | file_source | bigint unsigned | YES | MUL | NULL | | +// | file_target | varchar(512) | YES | | NULL | | +// | permissions | smallint | NO | | 0 | | +// | stime | bigint | NO | | 0 | | +// | accepted | smallint | NO | | 0 | | +// | expiration | datetime | YES | | NULL | | +// | token | varchar(32) | YES | MUL | NULL | | +// | mail_send | smallint | NO | | 0 | | +// | fileid_prefix | varchar(255) | YES | | NULL | | +// | orphan | tinyint | YES | | NULL | | +// | share_name | varchar(255) | YES | | NULL | | +// | quicklink | tinyint(1) | NO | | 0 | | +// | description | varchar(1024) | NO | | | | +// | internal | tinyint(1) | NO | MUL | 0 | | +// | notify_uploads | tinyint(1) | NO | | 0 | | +// | notify_uploads_extra_recipients | varchar(2048) | YES | | NULL | | +// +---------------------------------+-----------------+------+-----+---------+----------------+ + +type protoShare struct { + // Including gorm.Model will embed a number of gorm-default fields + // such as creation_time, id etc + gorm.Model + UIDOwner string + UIDInitiator string + ItemType string // file | folder + InitialPath string + Inode string + FileSource int64 + FileTarget string + Permissions uint8 + Instance string + Orphan bool + Description string + Expiration datatypes.Null[datatypes.Date] +} + +type Share struct { + protoShare + ShareWith string + SharedWithIsGroup bool +} + +type PublicLink struct { + protoShare + Token string + // Enforce uniqueness in db re: Itemsource + Quicklink bool + NotifyUploads bool + NotifyUploadsExtraRecipients string + Password string + // Users can give a name to a share + ShareName string +} + +// Unique index on combo of (shareid, user) +type ShareState struct { + gorm.Model + ShareId uint //foreign key to share + // Can not be uid because of lw accs + User string + Synced bool + Hidden bool +} + +func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { + ts := &typespb.Timestamp{ + Seconds: uint64(s.CreatedAt.Unix()), + } + return &collaboration.Share{ + Id: &collaboration.ShareId{ + OpaqueId: strconv.Itoa(int(s.ID)), + }, + //ResourceId: &provider.Reference{StorageId: s.Prefix, NodeId: s.ItemSource}, + ResourceId: &provider.ResourceId{ + StorageId: s.Instance, + OpaqueId: s.Inode, + }, + Permissions: &collaboration.SharePermissions{Permissions: conversions.IntTosharePerm(int(s.Permissions), s.ItemType)}, + Grantee: extractGrantee(s.SharedWithIsGroup, s.ShareWith, granteeType), + Owner: conversions.MakeUserID(s.UIDOwner), + Creator: conversions.MakeUserID(s.UIDInitiator), + Ctime: ts, + Mtime: ts, + } +} + +func (s *Share) AsCS3ReceivedShare(state *ShareState, granteeType userpb.UserType) *collaboration.ReceivedShare { + return &collaboration.ReceivedShare{ + Share: s.AsCS3Share(granteeType), + State: resourcespb.ShareState_SHARE_STATE_ACCEPTED, + Hidden: state.Hidden, + } +} + +func (p *PublicLink) AsCS3PublicShare() *link.PublicShare { + ts := &typespb.Timestamp{ + Seconds: uint64(p.CreatedAt.Unix()), + } + pwd := false + if p.Password != "" { + pwd = true + } + var expires *typespb.Timestamp + if p.Expiration.Valid { + exp, err := p.Expiration.V.Value() + expiration := exp.(time.Time) + if err == nil { + expires = &typespb.Timestamp{ + Seconds: uint64(expiration.Unix()), + } + } + + } + return &link.PublicShare{ + Id: &link.PublicShareId{ + OpaqueId: strconv.Itoa(int(p.ID)), + }, + ResourceId: &provider.ResourceId{ + StorageId: p.Instance, + OpaqueId: p.Inode, + }, + Permissions: &link.PublicSharePermissions{Permissions: conversions.IntTosharePerm(int(p.Permissions), p.ItemType)}, + Owner: conversions.MakeUserID(p.UIDOwner), + Creator: conversions.MakeUserID(p.UIDInitiator), + Token: p.Token, + DisplayName: p.ShareName, + PasswordProtected: pwd, + Expiration: expires, + Ctime: ts, + Mtime: ts, + Quicklink: p.Quicklink, + Description: p.Description, + NotifyUploads: p.NotifyUploads, + NotifyUploadsExtraRecipients: p.NotifyUploadsExtraRecipients, + } +} + +// The package 'conversions' is currently internal in Reva +// It should become public so we can use it here +// Since it generates CS3ResourcePermissions I'm not sure why it would be private + +// IntTosharePerm retrieves read/write permissions from an integer. +func intTosharePerm(p int, itemType string) *provider.ResourcePermissions { + switch p { + case 1: + return conversions.NewViewerRole().CS3ResourcePermissions() + case 15: + if itemType == "folder" { + return conversions.NewEditorRole().CS3ResourcePermissions() + } + return conversions.NewFileEditorRole().CS3ResourcePermissions() + case 4: + return conversions.NewUploaderRole().CS3ResourcePermissions() + default: + // TODO we may have other options, for now this is a denial + return &provider.ResourcePermissions{} + } +} + +// ExtractGrantee retrieves the CS3API Grantee from a grantee type and username/groupname. +// The grantee userType is relevant only for users. +func extractGrantee(sharedWithIsGroup bool, g string, gtype userpb.UserType) *provider.Grantee { + var grantee provider.Grantee + if sharedWithIsGroup { + grantee.Type = provider.GranteeType_GRANTEE_TYPE_USER + grantee.Id = &provider.Grantee_UserId{UserId: &userpb.UserId{ + OpaqueId: g, + Type: gtype, + }} + } else { + grantee.Type = provider.GranteeType_GRANTEE_TYPE_GROUP + grantee.Id = &provider.Grantee_GroupId{GroupId: &grouppb.GroupId{ + OpaqueId: g, + }} + } + + return &grantee +} diff --git a/share/sql/sql.go b/share/sql/sql.go index 285b84a..a1c12a8 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -1,4 +1,4 @@ -// Copyright 2018-2023 CERN +// Copyright 2018-2024 CERN // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,29 +20,29 @@ package sql import ( "context" - "database/sql" "fmt" - "path" "strconv" "strings" - "time" + model "github.com/cernbox/reva-plugins/share" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" - typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/cs3org/reva" "github.com/cs3org/reva/pkg/appctx" conversions "github.com/cs3org/reva/pkg/cbox/utils" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/rgrpc/status" "github.com/cs3org/reva/pkg/rgrpc/todo/pool" - "github.com/cs3org/reva/pkg/share" + revashare "github.com/cs3org/reva/pkg/share" "github.com/cs3org/reva/pkg/sharedconf" "github.com/cs3org/reva/pkg/utils" "github.com/cs3org/reva/pkg/utils/cfg" + "gorm.io/driver/mysql" + "gorm.io/gorm" + // Provides mysql drivers. _ "github.com/go-sql-driver/mysql" "github.com/pkg/errors" @@ -50,9 +50,6 @@ import ( ) const ( - shareTypeUser = 0 - shareTypeGroup = 1 - projectInstancesPrefix = "newproject" projectSpaceGroupsPrefix = "cernbox-project-" projectSpaceAdminGroupsSuffix = "-admins" @@ -80,8 +77,9 @@ type config struct { } type mgr struct { - c *config - db *sql.DB + c *config + //db *sql.DB + db *gorm.DB } func (c *config) ApplyDefaults() { @@ -89,17 +87,22 @@ func (c *config) ApplyDefaults() { } // New returns a new share manager. -func New(ctx context.Context, m map[string]interface{}) (share.Manager, error) { +func New(ctx context.Context, m map[string]interface{}) (revashare.Manager, error) { var c config if err := cfg.Decode(m, &c); err != nil { return nil, err } - db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName)) + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName) + db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) + // db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName)) if err != nil { return nil, err } + // Migrate schemas + db.AutoMigrate(&model.Share{}, &model.PublicLink{}, &model.ShareState{}) + return &mgr{ c: &c, db: db, @@ -129,119 +132,93 @@ func (m *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collabora return nil, errtypes.AlreadyExists(key.String()) } - now := time.Now().Unix() - ts := &typespb.Timestamp{ - Seconds: uint64(now), + share := &model.Share{ + ShareWith: conversions.FormatUserID(g.Grantee.GetUserId()), + SharedWithIsGroup: g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP, } + share.UIDOwner = conversions.FormatUserID(md.Owner) + share.UIDInitiator = conversions.FormatUserID(user.Id) + share.InitialPath = md.Path + share.ItemType = conversions.ResourceTypeToItem(md.Type) + share.Inode = md.Id.OpaqueId + share.Instance = md.Id.StorageId + share.Permissions = uint8(conversions.SharePermToInt(g.Permissions.Permissions)) + share.Orphan = false - shareType, shareWith := conversions.FormatGrantee(g.Grantee) - itemType := conversions.ResourceTypeToItem(md.Type) - targetPath := path.Join("/", path.Base(md.Path)) - permissions := conversions.SharePermToInt(g.Permissions.Permissions) - prefix := md.Id.StorageId - itemSource := md.Id.OpaqueId - fileSource, err := strconv.ParseUint(itemSource, 10, 64) - if err != nil { - // it can be the case that the item source may be a character string - // we leave fileSource blank in that case - fileSource = 0 - } - - stmtString := "insert into oc_share set share_type=?,uid_owner=?,uid_initiator=?,item_type=?,fileid_prefix=?,item_source=?,file_source=?,permissions=?,stime=?,share_with=?,file_target=?" - stmtValues := []interface{}{shareType, conversions.FormatUserID(md.Owner), conversions.FormatUserID(user.Id), itemType, prefix, itemSource, fileSource, permissions, now, shareWith, targetPath} - - stmt, err := m.db.Prepare(stmtString) - if err != nil { - return nil, err - } - result, err := stmt.Exec(stmtValues...) - if err != nil { - return nil, err - } - lastID, err := result.LastInsertId() - if err != nil { - return nil, err + res := m.db.Save(&share) + if res.Error != nil { + return nil, res.Error } - return &collaboration.Share{ - Id: &collaboration.ShareId{ - OpaqueId: strconv.FormatInt(lastID, 10), - }, - ResourceId: md.Id, - Permissions: g.Permissions, - Grantee: g.Grantee, - Owner: md.Owner, - Creator: user.Id, - Ctime: ts, - Mtime: ts, - }, nil + granteeType, _ := m.getUserType(ctx, share.ShareWith) + return share.AsCS3Share(granteeType), nil } -func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId, checkOwner bool) (*collaboration.Share, error) { - uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) - s := conversions.DBShare{ID: id.OpaqueId} - query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, lower(coalesce(share_with, '')) as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, stime, permissions, share_type FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND id=?" - params := []interface{}{id.OpaqueId} - if checkOwner { - query += " AND (uid_owner=? or uid_initiator=?)" - params = append(params, uid, uid) - } - if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.STime, &s.Permissions, &s.ShareType); err != nil { - if err == sql.ErrNoRows { - return nil, errtypes.NotFound(id.OpaqueId) - } - return nil, err +// Get Share by ID. Does not return orphans. +func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId) (*model.Share, error) { + var share model.Share + res := m.db.First(&share, id.OpaqueId) + + if res.RowsAffected == 0 || share.Orphan { + return nil, errtypes.NotFound(id.OpaqueId) } - // the grantee type is resolved afterwards when needed - return conversions.ConvertToCS3Share(s, userpb.UserType_USER_TYPE_INVALID), nil + + return &share, nil } -func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey, checkOwner bool) (*collaboration.Share, error) { +// Get Share by Key. Does not return orphans. +func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey, checkOwner bool) (*model.Share, error) { owner := conversions.FormatUserID(key.Owner) uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) - s := conversions.DBShare{} + var share model.Share shareType, shareWith := conversions.FormatGrantee(key.Grantee) - query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, lower(coalesce(share_with, '')) as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, id, stime, permissions, share_type FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND uid_owner=? AND fileid_prefix=? AND item_source=? AND share_type=? AND lower(share_with)=lower(?)" - params := []interface{}{owner, key.ResourceId.StorageId, key.ResourceId.OpaqueId, shareType, shareWith} + + query := m.db.Model(&share). + Where("orphan = ?", false). + Where("uid_owner = ?", owner). + Where("fileid_prefix = ?", key.ResourceId.StorageId). + Where("item_source = ?", key.ResourceId.OpaqueId). + Where("share_type = ?", shareType). + Where("share_with = ?", strings.ToLower(shareWith)) + if checkOwner { - query += " AND (uid_owner=? or uid_initiator=?)" - params = append(params, uid, uid) + query = query. + Where("uid_owner = ? or uid_initiator = ?", uid, uid) } - if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil { - if err == sql.ErrNoRows { - return nil, errtypes.NotFound(key.String()) - } - return nil, err + + res := query.First(&share) + + if res.RowsAffected == 0 { + return nil, errtypes.NotFound(key.String()) } - // the grantee type is resolved afterwards when needed - return conversions.ConvertToCS3Share(s, userpb.UserType_USER_TYPE_INVALID), nil + + return &share, nil } -func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) { - var s *collaboration.Share +func (m *mgr) getShare(ctx context.Context, ref *collaboration.ShareReference) (*model.Share, error) { + var s *model.Share var err error switch { case ref.GetId() != nil: - s, err = m.getByID(ctx, ref.GetId(), false) + s, err = m.getByID(ctx, ref.GetId()) if err != nil { return nil, err } case ref.GetKey() != nil: + //s, err = m.getByKey(ctx, ref.GetKey(), userpb.UserType_USER_TYPE_INVALID, false) s, err = m.getByKey(ctx, ref.GetKey(), false) if err != nil { return nil, err } default: - err = errtypes.NotFound(ref.String()) - } - - // resolve grantee's user type if applicable - if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER { - s.Grantee.GetUserId().Type, _ = m.getUserType(ctx, s.Grantee.GetUserId().OpaqueId) + return nil, errtypes.NotFound(ref.String()) } - path, err := m.getPath(ctx, s.ResourceId) + path, err := m.getPath(ctx, &provider.ResourceId{ + StorageId: s.Instance, + OpaqueId: s.Inode, + }) if err != nil { return nil, err } @@ -251,94 +228,46 @@ func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) ( return s, nil } - if s.Owner.OpaqueId == user.Id.OpaqueId && s.Creator.OpaqueId == user.Id.OpaqueId { + if s.UIDOwner == user.Id.OpaqueId && s.UIDInitiator == user.Id.OpaqueId { return s, nil } - return s, errtypes.NotFound("share not found") + return s, nil } -func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error { - var query string - params := []interface{}{} - switch { - case ref.GetId() != nil: - query = "delete from oc_share where id=?" - params = append(params, ref.GetId().OpaqueId) - case ref.GetKey() != nil: - key := ref.GetKey() - shareType, shareWith := conversions.FormatGrantee(key.Grantee) - owner := conversions.FormatUserID(key.Owner) - query = "delete from oc_share where uid_owner=? AND fileid_prefix=? AND item_source=? AND share_type=? AND lower(share_with)=lower(?)" - params = append(params, owner, key.ResourceId.StorageId, key.ResourceId.OpaqueId, shareType, shareWith) - default: - return errtypes.NotFound(ref.String()) - } - - ctx, err := m.addPathIntoCtx(ctx, ref) +func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) { + share, err := m.getShare(ctx, ref) if err != nil { - return err + return nil, err } - query, params, err = m.appendUidOwnerFilters(ctx, query, params) - if err != nil { - return err - } + granteeType, _ := m.getUserType(ctx, share.ShareWith) + cs3share := share.AsCS3Share(granteeType) - stmt, err := m.db.Prepare(query) - if err != nil { - return err - } - res, err := stmt.Exec(params...) - if err != nil { - return err - } + return cs3share, nil +} - rowCnt, err := res.RowsAffected() +func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error { + share, err := m.GetShare(ctx, ref) if err != nil { return err } - if rowCnt == 0 { - return errtypes.NotFound(ref.String()) - } - return nil + res := m.db.Delete(&share) + return res.Error } func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions) (*collaboration.Share, error) { permissions := conversions.SharePermToInt(p.Permissions) - - var query string - params := []interface{}{} - switch { - case ref.GetId() != nil: - query = "update oc_share set permissions=?,stime=? where id=?" - params = append(params, permissions, time.Now().Unix(), ref.GetId().OpaqueId) - case ref.GetKey() != nil: - key := ref.GetKey() - shareType, shareWith := conversions.FormatGrantee(key.Grantee) - owner := conversions.FormatUserID(key.Owner) - query = "update oc_share set permissions=?,stime=? where (uid_owner=? or uid_initiator=?) AND fileid_prefix=? AND item_source=? AND share_type=? AND lower(share_with)=lower(?)" - params = append(params, permissions, time.Now().Unix(), owner, owner, key.ResourceId.StorageId, key.ResourceId.OpaqueId, shareType, shareWith) - default: - return nil, errtypes.NotFound(ref.String()) - } - - ctx, err := m.addPathIntoCtx(ctx, ref) + share, err := m.getShare(ctx, ref) if err != nil { return nil, err } - query, params, err = m.appendUidOwnerFilters(ctx, query, params) - if err != nil { - return nil, err - } + share.Permissions = uint8(permissions) - stmt, err := m.db.Prepare(query) - if err != nil { - return nil, err - } - if _, err = stmt.Exec(params...); err != nil { - return nil, err + res := m.db.Save(&share) + if res.Error != nil { + return nil, res.Error } return m.GetShare(ctx, ref) @@ -361,39 +290,6 @@ func (m *mgr) getPath(ctx context.Context, resID *provider.ResourceId) (string, return res.GetPath(), nil } -func (m *mgr) addPathIntoCtx(ctx context.Context, ref *collaboration.ShareReference) (context.Context, error) { - var path string - var err error - switch { - case ref.GetId() != nil: - share, err := m.getByID(ctx, ref.GetId(), false) - if err != nil { - return nil, err - } - - path, err = m.getPath(ctx, share.ResourceId) - if err != nil { - return nil, err - } - case ref.GetKey() != nil: - key := ref.GetKey() - - path, err = m.getPath(ctx, key.ResourceId) - if err != nil { - return nil, err - } - } - return appctx.ContextSetResourcePath(ctx, path), nil -} - -func (m *mgr) isProjectAdminFromCtx(ctx context.Context, u *userpb.User) bool { - path, ok := appctx.ContextGetResourcePath(ctx) - if !ok { - return false - } - return m.isProjectAdmin(u, path) -} - func (m *mgr) isProjectAdmin(u *userpb.User, path string) bool { if strings.HasPrefix(path, projectPathPrefix) { // The path will look like /eos/project/c/cernbox, we need to extract the project name @@ -423,169 +319,125 @@ func (m *mgr) isProjectAdmin(u *userpb.User, path string) bool { } func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) { - query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, lower(coalesce(share_with, '')) as share_with, - coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, - id, stime, permissions, share_type - FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND (share_type=? OR share_type=?)` - params := []interface{}{shareTypeUser, shareTypeGroup} - - groupedFilters := share.GroupFiltersByType(filters) - if len(groupedFilters) > 0 { - filterQuery, filterParams, err := translateFilters(groupedFilters) - if err != nil { - return nil, err - } - params = append(params, filterParams...) - if filterQuery != "" { - query = fmt.Sprintf("%s AND (%s)", query, filterQuery) - } - } + var share model.Share + uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) - query, params, err := m.appendUidOwnerFilters(ctx, query, params) - if err != nil { - return nil, err - } + query := m.db.Model(&share). + Where("uid_owner = ? or uid_initiator = ?", uid, uid). + Where("orphan = ?", false) - rows, err := m.db.Query(query, params...) - if err != nil { - return nil, err - } - defer rows.Close() + // Append filters + m.appendFiltersToQuery(query, filters) - var s conversions.DBShare - shares := []*collaboration.Share{} - for rows.Next() { - if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil { - continue - } - gtype, _ := m.getUserType(ctx, s.ShareWith) - // if err != nil { - // failed to resolve grantee's user type, TODO Log - // } - shares = append(shares, conversions.ConvertToCS3Share(s, gtype)) + var shares []model.Share + var cs3shares []*collaboration.Share + res := query.Find(&shares) + if res.Error != nil { + return nil, res.Error } - if err = rows.Err(); err != nil { - return nil, err + + for _, s := range shares { + granteeType, _ := m.getUserType(ctx, s.ShareWith) + cs3shares = append(cs3shares, share.AsCS3Share(granteeType)) } - return shares, nil + return cs3shares, nil } // we list the shares that are targeted to the user in context or to the user groups. func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) { + var share model.Share user := appctx.ContextMustGetUser(ctx) - uid := conversions.FormatUserID(user.Id) - params := []interface{}{uid, uid, uid, uid} - for _, v := range user.Groups { - params = append(params, v) - } + query := m.db.Model(&share). + Where("orphan = ?", false) - query := `SELECT coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, lower(coalesce(share_with, '')) as share_with, - coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, - ts.id, stime, permissions, share_type, coalesce(tr.state, 0) as state - FROM oc_share ts LEFT JOIN oc_share_status tr ON (ts.id = tr.id AND tr.recipient = ?) - WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner != ? AND uid_initiator != ?)` - if len(user.Groups) > 0 { - query += " AND ((lower(share_with)=lower(?) AND share_type = 0) OR (share_type = 1 AND lower(share_with) in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))" - } else { - query += " AND (lower(share_with)=lower(?) AND share_type = 0)" + // Also search by all the groups the user is a member of + innerQuery := m.db.Where("share_with = ? and shared_with_is_group = ?", user.Username, false) + for _, group := range user.Groups { + innerQuery = innerQuery.Or("share_with = ? and shared_with_is_group = ?", group, true) } + query = query.Where(innerQuery) - groupedFilters := share.GroupFiltersByType(filters) - filterQuery, filterParams, err := translateFilters(groupedFilters) - if err != nil { - return nil, err - } - params = append(params, filterParams...) + // Append filters + m.appendFiltersToQuery(query, filters) - if filterQuery != "" { - query = fmt.Sprintf("%s AND (%s)", query, filterQuery) + // Get the shares + var shares []model.Share + res := query.Find(&shares) + if res.Error != nil { + return nil, res.Error } - rows, err := m.db.Query(query, params...) - if err != nil { - return nil, err - } - defer rows.Close() + // Now that we have the shares, we fetch the share state for every share + var receivedShares []*collaboration.ReceivedShare - var s conversions.DBShare - shares := []*collaboration.ReceivedShare{} - for rows.Next() { - if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil { - continue + for _, s := range shares { + shareId := &collaboration.ShareId{ + OpaqueId: strconv.Itoa(int(s.ID)), + } + shareState, err := m.getShareState(ctx, shareId, user) + if err != nil { + return nil, err } - gtype, _ := m.getUserType(ctx, s.ShareWith) - // if err != nil { - // failed to resolve grantee's user type, TODO Log - // } - shares = append(shares, conversions.ConvertToCS3ReceivedShare(s, gtype)) + + granteeType, _ := m.getUserType(ctx, s.ShareWith) + + receivedShares = append(receivedShares, share.AsCS3ReceivedShare(shareState, granteeType)) } - if err = rows.Err(); err != nil { - return nil, err + + return receivedShares, nil +} + +func (m *mgr) getShareState(ctx context.Context, shareId *collaboration.ShareId, user *userpb.User) (*model.ShareState, error) { + var shareState model.ShareState + query := m.db.Model(&shareState). + Where("share_id = ?", shareId.OpaqueId). + Where("user = ?", user.Username) + + res := query.First(&shareState) + + if res.RowsAffected == 0 { + return nil, errtypes.NotFound(shareId.OpaqueId) } - return shares, nil + return &shareState, nil } func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId, gtype userpb.UserType) (*collaboration.ReceivedShare, error) { user := appctx.ContextMustGetUser(ctx) - uid := conversions.FormatUserID(user.Id) - - params := []interface{}{uid, id.OpaqueId, uid} - for _, v := range user.Groups { - params = append(params, v) - } - - s := conversions.DBShare{ID: id.OpaqueId} - query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, lower(coalesce(share_with, '')) as share_with, - coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, - stime, permissions, share_type, coalesce(tr.state, 0) as state - FROM oc_share ts LEFT JOIN oc_share_status tr ON (ts.id = tr.id AND tr.recipient = ?) - WHERE (orphan = 0 or orphan IS NULL) AND ts.id=?` - if len(user.Groups) > 0 { - query += " AND ((lower(share_with)=lower(?) AND share_type = 0) OR (share_type = 1 AND lower(share_with) in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))" - } else { - query += " AND (lower(share_with)=lower(?) AND share_type = 0)" - } - if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil { - if err == sql.ErrNoRows { - return nil, errtypes.NotFound(id.OpaqueId) - } + share, err := m.getByID(ctx, id) + if err != nil { return nil, err } - return conversions.ConvertToCS3ReceivedShare(s, gtype), nil + + shareState, err := m.getShareState(ctx, id, user) + if err != nil { + return nil, err + } + + receivedShare := share.AsCS3ReceivedShare(shareState, gtype) + return receivedShare, nil } func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey, gtype userpb.UserType) (*collaboration.ReceivedShare, error) { user := appctx.ContextMustGetUser(ctx) - uid := conversions.FormatUserID(user.Id) + share, err := m.getByKey(ctx, key, false) + if err != nil { + return nil, err + } - shareType, shareWith := conversions.FormatGrantee(key.Grantee) - params := []interface{}{uid, conversions.FormatUserID(key.Owner), key.ResourceId.StorageId, key.ResourceId.OpaqueId, shareType, shareWith, shareWith} - for _, v := range user.Groups { - params = append(params, v) - } - - s := conversions.DBShare{} - query := `select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, lower(coalesce(share_with, '')) as share_with, - coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, - ts.id, stime, permissions, share_type, coalesce(tr.state, 0) as state - FROM oc_share ts LEFT JOIN oc_share_status tr ON (ts.id = tr.id AND tr.recipient = ?) - WHERE (orphan = 0 or orphan IS NULL) AND uid_owner=? AND fileid_prefix=? AND item_source=? AND share_type=? AND lower(share_with)=lower(?)` - if len(user.Groups) > 0 { - query += " AND ((lower(share_with)=lower(?) AND share_type = 0) OR (share_type = 1 AND lower(share_with) in (?" + strings.Repeat(",?", len(user.Groups)-1) + ")))" - } else { - query += " AND (lower(share_with)=lower(?) AND share_type = 0)" - } - - if err := m.db.QueryRow(query, params...).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil { - if err == sql.ErrNoRows { - return nil, errtypes.NotFound(key.String()) - } + shareId := &collaboration.ShareId{ + OpaqueId: strconv.Itoa(int(share.ID)), + } + + shareState, err := m.getShareState(ctx, shareId, user) + if err != nil { return nil, err } - return conversions.ConvertToCS3ReceivedShare(s, gtype), nil + + receivedShare := share.AsCS3ReceivedShare(shareState, gtype) + return receivedShare, nil } func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) { @@ -613,131 +465,42 @@ func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareRefe } func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) { - user := appctx.ContextMustGetUser(ctx) + + // user := appctx.ContextMustGetUser(ctx) rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Share.Id}}) if err != nil { return nil, err } - for i := range fieldMask.Paths { - switch fieldMask.Paths[i] { - case "state": - rs.State = share.State - default: - return nil, errtypes.NotSupported("updating " + fieldMask.Paths[i] + " is not supported") - } - } + // TODO: do actual update based on FieldMask - state := 0 - switch rs.GetState() { - case collaboration.ShareState_SHARE_STATE_REJECTED: - state = -1 - case collaboration.ShareState_SHARE_STATE_ACCEPTED: - state = 1 - } - - params := []interface{}{rs.Share.Id.OpaqueId, conversions.FormatUserID(user.Id), state, state} - query := "insert into oc_share_status(id, recipient, state) values(?, ?, ?) ON DUPLICATE KEY UPDATE state = ?" - - stmt, err := m.db.Prepare(query) - if err != nil { - return nil, err - } - _, err = stmt.Exec(params...) - if err != nil { - return nil, err + res := m.db.Save(&rs.State) + if res.Error != nil { + return nil, res.Error } return rs, nil -} - -func (m *mgr) appendUidOwnerFilters(ctx context.Context, query string, params []interface{}) (string, []interface{}, error) { - uidOwnersQuery, uidOwnersParams, err := m.uidOwnerFilters(ctx) - if err != nil { - return "", nil, err - } - - params = append(params, uidOwnersParams...) - if uidOwnersQuery != "" { - query = fmt.Sprintf("%s AND (%s)", query, uidOwnersQuery) - } - - return query, params, nil -} - -func (m *mgr) uidOwnerFilters(ctx context.Context) (string, []interface{}, error) { - user := appctx.ContextMustGetUser(ctx) - uid := conversions.FormatUserID(user.Id) - - query := "uid_owner=? or uid_initiator=?" - params := []interface{}{uid, uid} - - if m.isProjectAdminFromCtx(ctx, user) { - return "", []interface{}{}, nil - } - - return query, params, nil -} - -func granteeTypeToShareType(granteeType provider.GranteeType) int { - switch granteeType { - case provider.GranteeType_GRANTEE_TYPE_USER: - return shareTypeUser - case provider.GranteeType_GRANTEE_TYPE_GROUP: - return shareTypeGroup - } - return -1 -} - -// translateFilters translates the filters to sql queries. -func translateFilters(filters map[collaboration.Filter_Type][]*collaboration.Filter) (string, []interface{}, error) { - var ( - filterQuery string - params []interface{} - ) - - // If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator. - // That is why the filters got grouped by type. - // For every given filter type, iterate over the filters and if there are more than one combine them. - // Combine the different filter types using `AND` - var filterCounter = 0 - for filterType, currFilters := range filters { - switch filterType { - case collaboration.Filter_TYPE_RESOURCE_ID: - filterQuery += "(" - for i, f := range currFilters { - filterQuery += "(fileid_prefix =? AND item_source=?)" - params = append(params, f.GetResourceId().StorageId, f.GetResourceId().OpaqueId) - if i != len(currFilters)-1 { - filterQuery += " OR " - } - } - filterQuery += ")" - case collaboration.Filter_TYPE_GRANTEE_TYPE: - filterQuery += "(" - for i, f := range currFilters { - filterQuery += "share_type=?" - params = append(params, granteeTypeToShareType(f.GetGranteeType())) - - if i != len(currFilters)-1 { - filterQuery += " OR " - } - } - filterQuery += ")" - case collaboration.Filter_TYPE_EXCLUDE_DENIALS: - // TODO this may change once the mapping of permission to share types is completed (cf. pkg/cbox/utils/conversions.go) - filterQuery += "(permissions > 0)" - default: - return "", nil, fmt.Errorf("filter type is not supported") - } - if filterCounter != len(filters)-1 { - filterQuery += " AND " - } - filterCounter++ - } - return filterQuery, params, nil + // for i := range fieldMask.Paths { + // switch fieldMask.Paths[i] { + // case "state": + // rs.State = share.State + // default: + // return nil, errtypes.NotSupported("updating " + fieldMask.Paths[i] + " is not supported") + // } + // } + + // state := 0 + // switch rs.GetState() { + // case collaboration.ShareState_SHARE_STATE_REJECTED: + // state = -1 + // case collaboration.ShareState_SHARE_STATE_ACCEPTED: + // state = 1 + // } + + // params := []interface{}{rs.Share.Id.OpaqueId, conversions.FormatUserID(user.Id), state, state} + // query := "insert into oc_share_status(id, recipient, state) values(?, ?, ?) ON DUPLICATE KEY UPDATE state = ?" } func (m *mgr) getUserType(ctx context.Context, username string) (userpb.UserType, error) { @@ -758,3 +521,48 @@ func (m *mgr) getUserType(ctx context.Context, username string) (userpb.UserType return userRes.GetUser().Id.Type, nil } + +func (m *mgr) appendFiltersToQuery(query *gorm.DB, filters []*collaboration.Filter) { + // We want to chain filters of different types with AND + // and filters of the same type with OR + // Therefore, we group them by type + groupedFilters := revashare.GroupFiltersByType(filters) + + for filtertype, filters := range groupedFilters { + switch filtertype { + case collaboration.Filter_TYPE_RESOURCE_ID: + innerQuery := m.db + for i, filter := range filters { + if i == 0 { + innerQuery = innerQuery.Where("instance = ? and inode = ?", filter.GetResourceId().StorageId, filter.GetResourceId().OpaqueId) + } else { + innerQuery = innerQuery.Or("instance = ? and inode = ?", filter.GetResourceId().StorageId, filter.GetResourceId().OpaqueId) + } + } + query = query.Where(innerQuery) + case collaboration.Filter_TYPE_EXCLUDE_DENIALS: + query = query.Where("permissions > ?", 0) + case collaboration.Filter_TYPE_CREATOR: + break + case collaboration.Filter_TYPE_OWNER: + break + case collaboration.Filter_TYPE_STATE: + break + case collaboration.Filter_TYPE_SPACE_ID: + break + case collaboration.Filter_TYPE_GRANTEE_TYPE: + innerQuery := m.db + for i, filter := range filters { + isGroup := filter.GetGranteeType() == provider.GranteeType_GRANTEE_TYPE_GROUP + if i == 0 { + innerQuery = innerQuery.Where("shared_with_is_group = ?", isGroup) + } else { + innerQuery = innerQuery.Or("shared_with_is_group = ? ", isGroup) + } + } + query = query.Where(innerQuery) + default: + break + } + } +} From 2cf6e37223615de303cb30f56f519982e07bfa7b Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Mon, 16 Dec 2024 15:34:45 +0100 Subject: [PATCH 02/10] Fixed bugs, implemented unit tests for sharing --- go.mod | 16 +- go.sum | 32 +- share/model.go | 57 ++-- share/sql/sql.go | 144 +++++---- share/sql/sql_test.go | 669 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 805 insertions(+), 113 deletions(-) create mode 100644 share/sql/sql_test.go diff --git a/go.mod b/go.mod index f916b3a..d25d1f3 100644 --- a/go.mod +++ b/go.mod @@ -14,18 +14,19 @@ require ( github.com/juliangruber/go-intersect v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 - github.com/rs/zerolog v1.32.0 + github.com/rs/zerolog v1.33.0 google.golang.org/genproto v0.0.0-20240314234333-6e1732d8331c google.golang.org/grpc v1.65.0 gorm.io/datatypes v1.2.4 gorm.io/driver/mysql v1.5.7 + gorm.io/driver/sqlite v1.5.7 gorm.io/gorm v1.25.12 ) require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/BurntSushi/toml v1.3.2 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect @@ -50,19 +51,20 @@ require ( github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.24 // indirect github.com/mileusna/useragent v1.3.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect go.step.sm/crypto v0.43.1 // indirect - golang.org/x/crypto v0.23.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/image v0.13.0 // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/protobuf v1.34.1 // indirect + google.golang.org/protobuf v1.35.2 // indirect ) replace github.com/cs3org/reva => ../reva diff --git a/go.sum b/go.sum index ab0bd75..3627cb2 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -125,8 +125,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN 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/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= -github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -150,8 +150,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= @@ -177,8 +177,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -191,8 +191,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -204,8 +204,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -225,8 +225,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -239,8 +239,8 @@ gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U= gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A= -gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= -gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= +gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= +gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/share/model.go b/share/model.go index 040fa3f..8621398 100644 --- a/share/model.go +++ b/share/model.go @@ -47,7 +47,7 @@ import ( // | notify_uploads_extra_recipients | varchar(2048) | YES | | NULL | | // +---------------------------------+-----------------+------+-----+---------+----------------+ -type protoShare struct { +type ProtoShare struct { // Including gorm.Model will embed a number of gorm-default fields // such as creation_time, id etc gorm.Model @@ -66,13 +66,16 @@ type protoShare struct { } type Share struct { - protoShare + // Including gorm.Model will embed a number of gorm-default fields + // such as creation_time, id etc + + ProtoShare ShareWith string SharedWithIsGroup bool } type PublicLink struct { - protoShare + ProtoShare Token string // Enforce uniqueness in db re: Itemsource Quicklink bool @@ -86,7 +89,7 @@ type PublicLink struct { // Unique index on combo of (shareid, user) type ShareState struct { gorm.Model - ShareId uint //foreign key to share + ShareID uint //foreign key to share // Can not be uid because of lw accs User string Synced bool @@ -99,7 +102,7 @@ func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { } return &collaboration.Share{ Id: &collaboration.ShareId{ - OpaqueId: strconv.Itoa(int(s.ID)), + OpaqueId: strconv.FormatUint(uint64(s.ID), 10), }, //ResourceId: &provider.Reference{StorageId: s.Prefix, NodeId: s.ItemSource}, ResourceId: &provider.ResourceId{ @@ -116,9 +119,18 @@ func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { } func (s *Share) AsCS3ReceivedShare(state *ShareState, granteeType userpb.UserType) *collaboration.ReceivedShare { + // Currently, some implementations still rely on the ShareState to determine whether a file is hidden + // instead of using the field + var rsharestate resourcespb.ShareState + if state.Hidden { + rsharestate = resourcespb.ShareState_SHARE_STATE_REJECTED + } else { + rsharestate = resourcespb.ShareState_SHARE_STATE_ACCEPTED + } + return &collaboration.ReceivedShare{ Share: s.AsCS3Share(granteeType), - State: resourcespb.ShareState_SHARE_STATE_ACCEPTED, + State: rsharestate, Hidden: state.Hidden, } } @@ -166,44 +178,21 @@ func (p *PublicLink) AsCS3PublicShare() *link.PublicShare { } } -// The package 'conversions' is currently internal in Reva -// It should become public so we can use it here -// Since it generates CS3ResourcePermissions I'm not sure why it would be private - -// IntTosharePerm retrieves read/write permissions from an integer. -func intTosharePerm(p int, itemType string) *provider.ResourcePermissions { - switch p { - case 1: - return conversions.NewViewerRole().CS3ResourcePermissions() - case 15: - if itemType == "folder" { - return conversions.NewEditorRole().CS3ResourcePermissions() - } - return conversions.NewFileEditorRole().CS3ResourcePermissions() - case 4: - return conversions.NewUploaderRole().CS3ResourcePermissions() - default: - // TODO we may have other options, for now this is a denial - return &provider.ResourcePermissions{} - } -} - // ExtractGrantee retrieves the CS3API Grantee from a grantee type and username/groupname. // The grantee userType is relevant only for users. func extractGrantee(sharedWithIsGroup bool, g string, gtype userpb.UserType) *provider.Grantee { var grantee provider.Grantee if sharedWithIsGroup { - grantee.Type = provider.GranteeType_GRANTEE_TYPE_USER - grantee.Id = &provider.Grantee_UserId{UserId: &userpb.UserId{ + grantee.Type = provider.GranteeType_GRANTEE_TYPE_GROUP + grantee.Id = &provider.Grantee_GroupId{GroupId: &grouppb.GroupId{ OpaqueId: g, - Type: gtype, }} } else { - grantee.Type = provider.GranteeType_GRANTEE_TYPE_GROUP - grantee.Id = &provider.Grantee_GroupId{GroupId: &grouppb.GroupId{ + grantee.Type = provider.GranteeType_GRANTEE_TYPE_USER + grantee.Id = &provider.Grantee_UserId{UserId: &userpb.UserId{ OpaqueId: g, + Type: gtype, }} } - return &grantee } diff --git a/share/sql/sql.go b/share/sql/sql.go index a1c12a8..4f3924f 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -41,6 +41,7 @@ import ( "github.com/cs3org/reva/pkg/utils/cfg" "gorm.io/driver/mysql" + "gorm.io/driver/sqlite" "gorm.io/gorm" // Provides mysql drivers. @@ -68,6 +69,7 @@ func (mgr) RevaPlugin() reva.PluginInfo { } type config struct { + Engine string `mapstructure:"engine"` // mysql | sqlite DBUsername string `mapstructure:"db_username"` DBPassword string `mapstructure:"db_password"` DBHost string `mapstructure:"db_host"` @@ -93,9 +95,17 @@ func New(ctx context.Context, m map[string]interface{}) (revashare.Manager, erro return nil, err } - dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName) - db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) - // db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName)) + var db *gorm.DB + var err error + switch c.Engine { + case "mysql": + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName) + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + case "sqlite": + db, err = gorm.Open(sqlite.Open(c.DBName), &gorm.Config{}) + default: + return nil, errors.New("ShareManager SQL: unsupported database type " + c.Engine) + } if err != nil { return nil, err } @@ -126,14 +136,24 @@ func (m *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collabora Grantee: g.Grantee, } _, err := m.getByKey(ctx, key, true) - // share already exists + // TODO stricter error checking if err == nil { - return nil, errtypes.AlreadyExists(key.String()) + return nil, errors.New(errtypes.AlreadyExists(key.String()).Error()) + } + + var shareWith string + if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER { + shareWith = conversions.FormatUserID(g.Grantee.GetUserId()) + } else if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP { + // ShareWith is a group + shareWith = g.Grantee.GetGroupId().OpaqueId + } else { + return nil, errors.New("Unsuppored grantee type passed to Share()") } share := &model.Share{ - ShareWith: conversions.FormatUserID(g.Grantee.GetUserId()), + ShareWith: shareWith, SharedWithIsGroup: g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP, } share.UIDOwner = conversions.FormatUserID(md.Owner) @@ -172,14 +192,14 @@ func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey, checkOw uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) var share model.Share - shareType, shareWith := conversions.FormatGrantee(key.Grantee) + _, shareWith := conversions.FormatGrantee(key.Grantee) query := m.db.Model(&share). Where("orphan = ?", false). Where("uid_owner = ?", owner). - Where("fileid_prefix = ?", key.ResourceId.StorageId). - Where("item_source = ?", key.ResourceId.OpaqueId). - Where("share_type = ?", shareType). + Where("instance = ?", key.ResourceId.StorageId). + Where("inode = ?", key.ResourceId.OpaqueId). + Where("shared_with_is_group = ?", key.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP). Where("share_with = ?", strings.ToLower(shareWith)) if checkOwner { @@ -206,7 +226,6 @@ func (m *mgr) getShare(ctx context.Context, ref *collaboration.ShareReference) ( return nil, err } case ref.GetKey() != nil: - //s, err = m.getByKey(ctx, ref.GetKey(), userpb.UserType_USER_TYPE_INVALID, false) s, err = m.getByKey(ctx, ref.GetKey(), false) if err != nil { return nil, err @@ -215,6 +234,11 @@ func (m *mgr) getShare(ctx context.Context, ref *collaboration.ShareReference) ( return nil, errtypes.NotFound(ref.String()) } + user := appctx.ContextMustGetUser(ctx) + if s.UIDOwner == user.Id.OpaqueId && s.UIDInitiator == user.Id.OpaqueId { + return s, nil + } + path, err := m.getPath(ctx, &provider.ResourceId{ StorageId: s.Instance, OpaqueId: s.Inode, @@ -223,15 +247,10 @@ func (m *mgr) getShare(ctx context.Context, ref *collaboration.ShareReference) ( return nil, err } - user := appctx.ContextMustGetUser(ctx) if m.isProjectAdmin(user, path) { return s, nil } - if s.UIDOwner == user.Id.OpaqueId && s.UIDInitiator == user.Id.OpaqueId { - return s, nil - } - return s, nil } @@ -248,7 +267,7 @@ func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) ( } func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error { - share, err := m.GetShare(ctx, ref) + share, err := m.getShare(ctx, ref) if err != nil { return err } @@ -319,10 +338,9 @@ func (m *mgr) isProjectAdmin(u *userpb.User, path string) bool { } func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) { - var share model.Share uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) - query := m.db.Model(&share). + query := m.db.Model(&model.Share{}). Where("uid_owner = ? or uid_initiator = ?", uid, uid). Where("orphan = ?", false) @@ -338,7 +356,12 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ( for _, s := range shares { granteeType, _ := m.getUserType(ctx, s.ShareWith) - cs3shares = append(cs3shares, share.AsCS3Share(granteeType)) + cs3share := s.AsCS3Share(granteeType) + cs3shares = append(cs3shares, cs3share) + } + + if len(shares) > 0 { + fmt.Printf("First cs3share has id %s\n", cs3shares[0].Id.OpaqueId) } return cs3shares, nil @@ -346,10 +369,9 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ( // we list the shares that are targeted to the user in context or to the user groups. func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) { - var share model.Share user := appctx.ContextMustGetUser(ctx) - query := m.db.Model(&share). + query := m.db.Model(&model.Share{}). Where("orphan = ?", false) // Also search by all the groups the user is a member of @@ -374,7 +396,7 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F for _, s := range shares { shareId := &collaboration.ShareId{ - OpaqueId: strconv.Itoa(int(s.ID)), + OpaqueId: strconv.FormatUint(uint64(s.ID), 10), } shareState, err := m.getShareState(ctx, shareId, user) if err != nil { @@ -383,7 +405,7 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F granteeType, _ := m.getUserType(ctx, s.ShareWith) - receivedShares = append(receivedShares, share.AsCS3ReceivedShare(shareState, granteeType)) + receivedShares = append(receivedShares, s.AsCS3ReceivedShare(shareState, granteeType)) } return receivedShares, nil @@ -398,7 +420,20 @@ func (m *mgr) getShareState(ctx context.Context, shareId *collaboration.ShareId, res := query.First(&shareState) if res.RowsAffected == 0 { - return nil, errtypes.NotFound(shareId.OpaqueId) + shareIdInt, err := strconv.Atoi(shareId.OpaqueId) + if err != nil { + return nil, errors.New("Failed to fetch shareState, and failed to create one (share_id is not an int)") + } + // If no share state has been created yet, we create it now using these defaults + shareState = model.ShareState{ + ShareID: uint(shareIdInt), + Hidden: false, + Synced: false, + User: user.Username, + } + // Does not really matter if it fails, next time the user + // lists his shares this will just be called again + m.db.Save(&shareState) } return &shareState, nil @@ -466,41 +501,46 @@ func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareRefe func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) { - // user := appctx.ContextMustGetUser(ctx) + user := appctx.ContextMustGetUser(ctx) rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Share.Id}}) if err != nil { return nil, err } - // TODO: do actual update based on FieldMask + shareState, err := m.getShareState(ctx, share.Share.Id, user) + if err != nil { + return nil, err + } + + // FieldMask determines which parts of the share we actually update + // Right now, only updating the state is supported + for _, path := range fieldMask.Paths { + switch path { + case "state": + rs.State = share.State + case "hidden": + rs.Hidden = share.Hidden + default: + return nil, errtypes.NotSupported("updating " + path + " is not supported") + } + } + + // Now we do the actual update to the db model + switch rs.State { + case collaboration.ShareState_SHARE_STATE_ACCEPTED: + shareState.Hidden = false + case collaboration.ShareState_SHARE_STATE_REJECTED: + fmt.Printf("Updating share state to hidden\n") + shareState.Hidden = true + } - res := m.db.Save(&rs.State) + res := m.db.Save(&shareState) if res.Error != nil { return nil, res.Error } return rs, nil - - // for i := range fieldMask.Paths { - // switch fieldMask.Paths[i] { - // case "state": - // rs.State = share.State - // default: - // return nil, errtypes.NotSupported("updating " + fieldMask.Paths[i] + " is not supported") - // } - // } - - // state := 0 - // switch rs.GetState() { - // case collaboration.ShareState_SHARE_STATE_REJECTED: - // state = -1 - // case collaboration.ShareState_SHARE_STATE_ACCEPTED: - // state = 1 - // } - - // params := []interface{}{rs.Share.Id.OpaqueId, conversions.FormatUserID(user.Id), state, state} - // query := "insert into oc_share_status(id, recipient, state) values(?, ?, ?) ON DUPLICATE KEY UPDATE state = ?" } func (m *mgr) getUserType(ctx context.Context, username string) (userpb.UserType, error) { @@ -542,14 +582,6 @@ func (m *mgr) appendFiltersToQuery(query *gorm.DB, filters []*collaboration.Filt query = query.Where(innerQuery) case collaboration.Filter_TYPE_EXCLUDE_DENIALS: query = query.Where("permissions > ?", 0) - case collaboration.Filter_TYPE_CREATOR: - break - case collaboration.Filter_TYPE_OWNER: - break - case collaboration.Filter_TYPE_STATE: - break - case collaboration.Filter_TYPE_SPACE_ID: - break case collaboration.Filter_TYPE_GRANTEE_TYPE: innerQuery := m.db for i, filter := range filters { diff --git a/share/sql/sql_test.go b/share/sql/sql_test.go new file mode 100644 index 0000000..c85d5a3 --- /dev/null +++ b/share/sql/sql_test.go @@ -0,0 +1,669 @@ +package sql + +import ( + "context" + "log" + "os" + "testing" + "time" + + groupv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" + userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/pkg/appctx" + conversions "github.com/cs3org/reva/pkg/cbox/utils" + revashare "github.com/cs3org/reva/pkg/share" + "google.golang.org/genproto/protobuf/field_mask" +) + +// =========================== +// Helper functions for tests +// =========================== + +// You can use testing.T, if you want to test the code without benchmarking +func setupSuite(tb testing.TB) (revashare.Manager, error, func(tb testing.TB)) { + ctx := context.Background() + dbName := "test_db.sqlite" + cfg := map[string]interface{}{ + "engine": "sqlite", + "db_name": dbName, + } + mgr, err := New(ctx, cfg) + if err != nil { + return nil, err, nil + } + + // Return a function to teardown the test + return mgr, nil, func(tb testing.TB) { + log.Println("teardown suite") + os.Remove(dbName) + } +} + +func getRandomFile(owner *userpb.User) *provider.ResourceInfo { + return &provider.ResourceInfo{ + Id: &provider.ResourceId{ + StorageId: "project-b", + OpaqueId: "45468401564", + }, + Type: provider.ResourceType_RESOURCE_TYPE_FILE, + Path: "/eos/project/b/myfile", + Owner: owner.Id, + Mtime: &typesv1beta1.Timestamp{Seconds: uint64(time.Now().Unix())}, + } +} + +// Return context populated with user info +func getUserContext(id string) context.Context { + user := &userpb.User{ + Id: &userpb.UserId{ + OpaqueId: id, + Type: userpb.UserType_USER_TYPE_APPLICATION, + }, + Username: id, + Mail: "myuser@cern.ch", + MailVerified: true, + } + ctx := appctx.ContextSetUser(context.Background(), user) + return ctx +} + +func getUserShareGrant(shareeId, resourcetype string) *collaboration.ShareGrant { + sharee := &provider.Grantee{ + Type: provider.GranteeType_GRANTEE_TYPE_USER, + Id: &provider.Grantee_UserId{ + UserId: &userpb.UserId{ + Type: userpb.UserType_USER_TYPE_APPLICATION, + OpaqueId: shareeId, + }, + }, + } + + sharegrant := &collaboration.ShareGrant{ + Grantee: sharee, + Permissions: &collaboration.SharePermissions{ + Permissions: conversions.IntTosharePerm(1, resourcetype), + }, + } + return sharegrant +} + +func getGroupShareGrant(shareeId, resourcetype string) *collaboration.ShareGrant { + sharee := &provider.Grantee{ + Type: provider.GranteeType_GRANTEE_TYPE_GROUP, + Id: &provider.Grantee_GroupId{ + GroupId: &groupv1beta1.GroupId{ + OpaqueId: shareeId, + }, + }, + } + return &collaboration.ShareGrant{ + Grantee: sharee, + Permissions: &collaboration.SharePermissions{ + Permissions: conversions.IntTosharePerm(1, resourcetype), + }, + } +} + +// =========================== +// Actual tests +// =========================== + +func TestGetShareById(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + retrievedshare, err := mgr.GetShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + if retrievedshare.Id.OpaqueId != share.Id.OpaqueId { + t.Errorf("Retrieved share does not match created share, expected %s, got %s", share.Id.OpaqueId, retrievedshare.Id.OpaqueId) + } +} + +func TestGetShareByKey(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + key := &collaboration.ShareKey{ + Owner: user.Id, + ResourceId: file.Id, + Grantee: sharegrant.Grantee, + } + + retrievedshare, err := mgr.GetShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Key{ + Key: key, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + if retrievedshare.Id.OpaqueId != share.Id.OpaqueId { + t.Errorf("Retrieved share does not match created share, expected %s, got %s", share.Id.OpaqueId, retrievedshare.Id.OpaqueId) + } +} + +func TestGetReceivedShareById(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + receivedshare, err := mgr.GetReceivedShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + if receivedshare.Share.Id.OpaqueId != share.Id.OpaqueId { + t.Errorf("Retrieved received share does not match created share, expected %s, got %s", share.Id.OpaqueId, receivedshare.Share.Id.OpaqueId) + } +} + +func TestGetReceivedShareByKey(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + receivingUserCtx := getUserContext("1000") + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + key := &collaboration.ShareKey{ + Owner: user.Id, + ResourceId: file.Id, + Grantee: sharegrant.Grantee, + } + + receivedshare, err := mgr.GetReceivedShare(receivingUserCtx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Key{ + Key: key, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + if receivedshare.Share.Id.OpaqueId != share.Id.OpaqueId { + t.Errorf("Retrieved received share does not match created share, expected %s, got %s", share.Id.OpaqueId, receivedshare.Share.Id.OpaqueId) + } +} + +func TestDoNotCreateSameShareTwice(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + sharee := &provider.Grantee{ + Type: provider.GranteeType_GRANTEE_TYPE_USER, + Id: &provider.Grantee_UserId{ + UserId: &userpb.UserId{ + Type: userpb.UserType_USER_TYPE_APPLICATION, + OpaqueId: "1000", + }, + }, + } + sharegrant := &collaboration.ShareGrant{ + Grantee: sharee, + Permissions: &collaboration.SharePermissions{ + Permissions: conversions.IntTosharePerm(1, "file"), + }, + } + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + + _, err = mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + _, err = mgr.Share(userctx, file, sharegrant) + if err == nil { + t.Log("Creating same share succeeded, while it should have failed") + t.FailNow() + } +} + +func TestListShares(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + res, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + shares, err := mgr.ListShares(userctx, nil) + if err != nil { + t.Error(err) + t.FailNow() + } + + if len(shares) != 1 { + t.Errorf("Expected 1 share, got %d", len(shares)) + t.FailNow() + } + + if shares[0].Id.OpaqueId != res.Id.OpaqueId { + t.Errorf("Expected share with id %s, got %s", res.Id.OpaqueId, shares[0].Id.OpaqueId) + } +} + +func TestListReceivedShares(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + receivingUserCtx := getUserContext("1000") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + res, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + receivedShares, err := mgr.ListReceivedShares(receivingUserCtx, nil) + if err != nil { + t.Error(err) + t.FailNow() + } + + if len(receivedShares) != 1 { + t.Errorf("Expected 1 received share, got %d", len(receivedShares)) + } + + if receivedShares[0].Share.Id.OpaqueId != res.Id.OpaqueId { + t.Errorf("Expected share with id %s, got %s", res.Id.OpaqueId, receivedShares[0].Share.Id.OpaqueId) + } +} + +func TestListSharesWithFilters(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + res, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + filters := []*collaboration.Filter{ + { + Type: collaboration.Filter_TYPE_RESOURCE_ID, + Term: &collaboration.Filter_ResourceId{ + ResourceId: &provider.ResourceId{ + StorageId: "project-b", + OpaqueId: "45468401564", + }, + }, + }, + } + + shares, err := mgr.ListShares(userctx, filters) + if err != nil { + t.Error(err) + t.FailNow() + } + + if len(shares) != 1 { + t.Errorf("Expected 1 share, got %d", len(shares)) + } + + if shares[0].Id.OpaqueId != res.Id.OpaqueId { + t.Errorf("Expected share with id %s, got %s", res.Id.OpaqueId, shares[0].Id.OpaqueId) + } +} + +func TestDeleteShare(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + err = mgr.Unshare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + _, err = mgr.GetShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }) + if err == nil { + t.Errorf("Expected share to be deleted, but it was not") + } +} + +func TestUpdateShare(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + newPermissions := 15 + + updatedShare, err := mgr.UpdateShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }, &collaboration.SharePermissions{ + Permissions: conversions.IntTosharePerm(newPermissions, "file"), + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + retrievedPerms := conversions.SharePermToInt(updatedShare.Permissions.Permissions) + if retrievedPerms != newPermissions { + t.Errorf("Expected share permissions to be updated, but they were not: got %d instead of %d", retrievedPerms, newPermissions) + } +} + +func TestUpdateReceivedShare(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + share, err := mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + receivedShare, err := mgr.GetReceivedShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + // Update the received share state + receivedShare.State = collaboration.ShareState_SHARE_STATE_REJECTED + + _, err = mgr.UpdateReceivedShare(userctx, receivedShare, &field_mask.FieldMask{ + Paths: []string{"state"}, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + updatedReceivedShare, err := mgr.GetReceivedShare(userctx, &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{ + Id: share.Id, + }, + }) + if err != nil { + t.Error(err) + t.FailNow() + } + + if updatedReceivedShare.State != collaboration.ShareState_SHARE_STATE_REJECTED { + t.Errorf("Expected received share state to be updated, but it was not") + } +} + +func TestShareWithGroup(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getGroupShareGrant("myegroup", "file") + + _, err = mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + shares, err := mgr.ListShares(userctx, nil) + if err != nil { + t.Error(err) + t.FailNow() + } + + if len(shares) != 1 { + t.Errorf("Expected 1 share, got %d", len(shares)) + } + + if shares[0].Grantee.Type != provider.GranteeType_GRANTEE_TYPE_GROUP { + t.Errorf("Expected share to be with a group, but it was not") + } +} + +func TestListSharesWithGranteeTypeFilter(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getGroupShareGrant("myegroup", "file") + + _, err = mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + filters := []*collaboration.Filter{ + { + Type: collaboration.Filter_TYPE_GRANTEE_TYPE, + Term: &collaboration.Filter_GranteeType{ + GranteeType: provider.GranteeType_GRANTEE_TYPE_GROUP, + }, + }, + } + + shares, err := mgr.ListShares(userctx, filters) + if err != nil { + t.Error(err) + t.FailNow() + } + + if len(shares) != 1 { + t.Errorf("Expected 1 share, got %d", len(shares)) + } +} + +func TestListSharesWithMultipleFilters(t *testing.T) { + mgr, err, teardown := setupSuite(t) + defer teardown(t) + + if err != nil { + t.Error(err) + } + + userctx := getUserContext("123456") + user, _ := appctx.ContextGetUser(userctx) + file := getRandomFile(user) + sharegrant := getUserShareGrant("1000", "file") + + _, err = mgr.Share(userctx, file, sharegrant) + if err != nil { + t.Error(err) + t.FailNow() + } + + filters := []*collaboration.Filter{ + { + Type: collaboration.Filter_TYPE_RESOURCE_ID, + Term: &collaboration.Filter_ResourceId{ResourceId: &provider.ResourceId{ + StorageId: "project-b", + OpaqueId: "45468401564", + }}, + }, + { + Type: collaboration.Filter_TYPE_GRANTEE_TYPE, + Term: &collaboration.Filter_GranteeType{ + GranteeType: provider.GranteeType_GRANTEE_TYPE_USER, + }, + }, + } + + shares, err := mgr.ListShares(userctx, filters) + if err != nil { + t.Error(err) + t.FailNow() + } + + if len(shares) != 1 { + t.Errorf("Expected 1 share, got %d", len(shares)) + } +} From d2f446e4f5ea4119509e535ca6c22be05e0ea562 Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Thu, 9 Jan 2025 14:06:43 +0100 Subject: [PATCH 03/10] resolving comments on PR --- go.mod | 2 +- share/model.go | 56 +++++++++++++++--------------------------------- share/sql/sql.go | 22 ++++++------------- 3 files changed, 25 insertions(+), 55 deletions(-) diff --git a/go.mod b/go.mod index d25d1f3..e691c45 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/cernbox/reva-plugins -go 1.21.0 +go 1.22.7 require ( github.com/Masterminds/sprig v2.22.0+incompatible diff --git a/share/model.go b/share/model.go index 8621398..56d4609 100644 --- a/share/model.go +++ b/share/model.go @@ -17,43 +17,25 @@ import ( "gorm.io/gorm" ) -// +---------------------------------+-----------------+------+-----+---------+----------------+ -// | Field | Type | Null | Key | Default | Extra | -// +---------------------------------+-----------------+------+-----+---------+----------------+ -// | id | int | NO | PRI | NULL | auto_increment | -// | share_type | smallint | NO | | 0 | | -// | share_with | varchar(255) | YES | | NULL | | -// | uid_owner | varchar(64) | NO | | | | -// | uid_initiator | varchar(64) | YES | | NULL | | -// | parent | int | YES | | NULL | | -// | item_type | varchar(64) | NO | MUL | | | -// | item_source | varchar(255) | YES | | NULL | | -// | item_target | varchar(255) | YES | | NULL | | -// | file_source | bigint unsigned | YES | MUL | NULL | | -// | file_target | varchar(512) | YES | | NULL | | -// | permissions | smallint | NO | | 0 | | -// | stime | bigint | NO | | 0 | | -// | accepted | smallint | NO | | 0 | | -// | expiration | datetime | YES | | NULL | | -// | token | varchar(32) | YES | MUL | NULL | | -// | mail_send | smallint | NO | | 0 | | -// | fileid_prefix | varchar(255) | YES | | NULL | | -// | orphan | tinyint | YES | | NULL | | -// | share_name | varchar(255) | YES | | NULL | | -// | quicklink | tinyint(1) | NO | | 0 | | -// | description | varchar(1024) | NO | | | | -// | internal | tinyint(1) | NO | MUL | 0 | | -// | notify_uploads | tinyint(1) | NO | | 0 | | -// | notify_uploads_extra_recipients | varchar(2048) | YES | | NULL | | -// +---------------------------------+-----------------+------+-----+---------+----------------+ +type ItemType string + +const ( + ItemTypeFile ItemType = "file" + ItemTypeFolder ItemType = "folder" + ItemTypeReference ItemType = "reference" + ItemTypeSymlink ItemType = "symlink" +) + +func (i ItemType) String() string { + return string(i) +} type ProtoShare struct { // Including gorm.Model will embed a number of gorm-default fields - // such as creation_time, id etc gorm.Model UIDOwner string UIDInitiator string - ItemType string // file | folder + ItemType ItemType // file | folder | reference | symlink InitialPath string Inode string FileSource int64 @@ -66,9 +48,6 @@ type ProtoShare struct { } type Share struct { - // Including gorm.Model will embed a number of gorm-default fields - // such as creation_time, id etc - ProtoShare ShareWith string SharedWithIsGroup bool @@ -86,10 +65,9 @@ type PublicLink struct { ShareName string } -// Unique index on combo of (shareid, user) type ShareState struct { gorm.Model - ShareID uint //foreign key to share + Share Share // Can not be uid because of lw accs User string Synced bool @@ -109,7 +87,7 @@ func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { StorageId: s.Instance, OpaqueId: s.Inode, }, - Permissions: &collaboration.SharePermissions{Permissions: conversions.IntTosharePerm(int(s.Permissions), s.ItemType)}, + Permissions: &collaboration.SharePermissions{Permissions: conversions.IntTosharePerm(int(s.Permissions), s.ItemType.String())}, Grantee: extractGrantee(s.SharedWithIsGroup, s.ShareWith, granteeType), Owner: conversions.MakeUserID(s.UIDOwner), Creator: conversions.MakeUserID(s.UIDInitiator), @@ -146,8 +124,8 @@ func (p *PublicLink) AsCS3PublicShare() *link.PublicShare { var expires *typespb.Timestamp if p.Expiration.Valid { exp, err := p.Expiration.V.Value() - expiration := exp.(time.Time) if err == nil { + expiration := exp.(time.Time) expires = &typespb.Timestamp{ Seconds: uint64(expiration.Unix()), } @@ -162,7 +140,7 @@ func (p *PublicLink) AsCS3PublicShare() *link.PublicShare { StorageId: p.Instance, OpaqueId: p.Inode, }, - Permissions: &link.PublicSharePermissions{Permissions: conversions.IntTosharePerm(int(p.Permissions), p.ItemType)}, + Permissions: &link.PublicSharePermissions{Permissions: conversions.IntTosharePerm(int(p.Permissions), p.ItemType.String())}, Owner: conversions.MakeUserID(p.UIDOwner), Creator: conversions.MakeUserID(p.UIDInitiator), Token: p.Token, diff --git a/share/sql/sql.go b/share/sql/sql.go index 4f3924f..dd8d443 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -159,7 +159,7 @@ func (m *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collabora share.UIDOwner = conversions.FormatUserID(md.Owner) share.UIDInitiator = conversions.FormatUserID(user.Id) share.InitialPath = md.Path - share.ItemType = conversions.ResourceTypeToItem(md.Type) + share.ItemType = model.ItemType(conversions.ResourceTypeToItem(md.Type)) share.Inode = md.Id.OpaqueId share.Instance = md.Id.StorageId share.Permissions = uint8(conversions.SharePermToInt(g.Permissions.Permissions)) @@ -189,7 +189,6 @@ func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId) (*model.Sh // Get Share by Key. Does not return orphans. func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey, checkOwner bool) (*model.Share, error) { owner := conversions.FormatUserID(key.Owner) - uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) var share model.Share _, shareWith := conversions.FormatGrantee(key.Grantee) @@ -203,6 +202,7 @@ func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey, checkOw Where("share_with = ?", strings.ToLower(shareWith)) if checkOwner { + uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) query = query. Where("uid_owner = ? or uid_initiator = ?", uid, uid) } @@ -222,16 +222,13 @@ func (m *mgr) getShare(ctx context.Context, ref *collaboration.ShareReference) ( switch { case ref.GetId() != nil: s, err = m.getByID(ctx, ref.GetId()) - if err != nil { - return nil, err - } case ref.GetKey() != nil: s, err = m.getByKey(ctx, ref.GetKey(), false) - if err != nil { - return nil, err - } default: - return nil, errtypes.NotFound(ref.String()) + err = errtypes.NotFound(ref.String()) + } + if err != nil { + return nil, err } user := appctx.ContextMustGetUser(ctx) @@ -251,7 +248,7 @@ func (m *mgr) getShare(ctx context.Context, ref *collaboration.ShareReference) ( return s, nil } - return s, nil + return nil, errtypes.NotFound(ref.String()) } func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) { @@ -360,10 +357,6 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ( cs3shares = append(cs3shares, cs3share) } - if len(shares) > 0 { - fmt.Printf("First cs3share has id %s\n", cs3shares[0].Id.OpaqueId) - } - return cs3shares, nil } @@ -531,7 +524,6 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.Rece case collaboration.ShareState_SHARE_STATE_ACCEPTED: shareState.Hidden = false case collaboration.ShareState_SHARE_STATE_REJECTED: - fmt.Printf("Updating share state to hidden\n") shareState.Hidden = true } From 5391b342a9b2a7232e0039e66d39d3e4180ed578 Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Fri, 10 Jan 2025 16:38:56 +0100 Subject: [PATCH 04/10] ListReceivedShares now uses a JOIN --- share/model.go | 3 +- share/sql/sql.go | 100 +++++++++++++++++++++--------------------- share/sql/sql_test.go | 1 + 3 files changed, 53 insertions(+), 51 deletions(-) diff --git a/share/model.go b/share/model.go index 56d4609..ac65af2 100644 --- a/share/model.go +++ b/share/model.go @@ -67,7 +67,8 @@ type PublicLink struct { type ShareState struct { gorm.Model - Share Share + ShareID uint `gorm:"foreignKey:ShareID;references:ID"` // Define the foreign key field + Share Share // Define the association // Can not be uid because of lw accs User string Synced bool diff --git a/share/sql/sql.go b/share/sql/sql.go index dd8d443..71b227d 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -201,10 +201,10 @@ func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey, checkOw Where("shared_with_is_group = ?", key.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP). Where("share_with = ?", strings.ToLower(shareWith)) - if checkOwner { - uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) - query = query. - Where("uid_owner = ? or uid_initiator = ?", uid, uid) + uid := conversions.FormatUserID(appctx.ContextMustGetUser(ctx).Id) + // In case the user is not the owner (i.e. in the case of projects) + if checkOwner && owner != uid { + query = query.Where("uid_initiator = ?", uid) } res := query.First(&share) @@ -319,14 +319,6 @@ func (m *mgr) isProjectAdmin(u *userpb.User, path string) bool { if g == adminGroup { // User belongs to the admin group, list all shares for the resource - // TODO: this only works if shares for a single project are requested. - // If shares for multiple projects are requested, then we're not checking if the - // user is an admin for all of those. We can append the query ` or uid_owner=?` - // for all the project owners, which works fine for new reva - // but won't work for revaold since there, we store the uid of the share creator as uid_owner. - // For this to work across the two versions, this change would have to be made in revaold - // but it won't be straightforward as there, the storage provider doesn't return the - // resource owners. return true } } @@ -364,65 +356,67 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ( func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) { user := appctx.ContextMustGetUser(ctx) - query := m.db.Model(&model.Share{}). - Where("orphan = ?", false) + // We need to do this to parse the result + // Normally, GORM would be able to fill in the Share that is referenced in ShareState + // However, in GORM's docs: "Join Preload will loads association data using left join" + // Because we do a RIGHT JOIN, GORM cannot load the data into shareState.Share (in case that ShareState is empty) + // So we load them both separately, and then set ShareState.Share = Share ourselves + var results []struct { + model.ShareState + model.Share + } + + query := m.db.Model(&model.ShareState{}). + Select("share_states.*, shares.*"). + Joins("RIGHT OUTER JOIN shares ON shares.id = share_states.share_id"). + Where("shares.orphan = ?", false) // Also search by all the groups the user is a member of - innerQuery := m.db.Where("share_with = ? and shared_with_is_group = ?", user.Username, false) + innerQuery := m.db.Where("shares.share_with = ? and shares.shared_with_is_group = ?", user.Username, false) for _, group := range user.Groups { - innerQuery = innerQuery.Or("share_with = ? and shared_with_is_group = ?", group, true) + innerQuery = innerQuery.Or("shares.share_with = ? and shares.shared_with_is_group = ?", group, true) } query = query.Where(innerQuery) // Append filters m.appendFiltersToQuery(query, filters) - // Get the shares - var shares []model.Share - res := query.Find(&shares) + // Get the shares + states + res := query.Find(&results) if res.Error != nil { return nil, res.Error } - // Now that we have the shares, we fetch the share state for every share var receivedShares []*collaboration.ReceivedShare - for _, s := range shares { - shareId := &collaboration.ShareId{ - OpaqueId: strconv.FormatUint(uint64(s.ID), 10), - } - shareState, err := m.getShareState(ctx, shareId, user) - if err != nil { - return nil, err - } + // Now we parse everything into the CS3 definition of a CS3ReceivedShare + for _, res := range results { + shareState := res.ShareState + shareState.Share = res.Share + granteeType, _ := m.getUserType(ctx, res.Share.ShareWith) - granteeType, _ := m.getUserType(ctx, s.ShareWith) - - receivedShares = append(receivedShares, s.AsCS3ReceivedShare(shareState, granteeType)) + receivedShares = append(receivedShares, res.Share.AsCS3ReceivedShare(&shareState, granteeType)) } return receivedShares, nil } -func (m *mgr) getShareState(ctx context.Context, shareId *collaboration.ShareId, user *userpb.User) (*model.ShareState, error) { +// shareId *collaboration.ShareId +func (m *mgr) getShareState(ctx context.Context, share *model.Share, user *userpb.User) (*model.ShareState, error) { var shareState model.ShareState query := m.db.Model(&shareState). - Where("share_id = ?", shareId.OpaqueId). + Where("share_id = ?", share.ID). Where("user = ?", user.Username) res := query.First(&shareState) if res.RowsAffected == 0 { - shareIdInt, err := strconv.Atoi(shareId.OpaqueId) - if err != nil { - return nil, errors.New("Failed to fetch shareState, and failed to create one (share_id is not an int)") - } // If no share state has been created yet, we create it now using these defaults shareState = model.ShareState{ - ShareID: uint(shareIdInt), - Hidden: false, - Synced: false, - User: user.Username, + Share: *share, + Hidden: false, + Synced: false, + User: user.Username, } // Does not really matter if it fails, next time the user // lists his shares this will just be called again @@ -439,7 +433,7 @@ func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId, gt return nil, err } - shareState, err := m.getShareState(ctx, id, user) + shareState, err := m.getShareState(ctx, share, user) if err != nil { return nil, err } @@ -455,11 +449,7 @@ func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey, return nil, err } - shareId := &collaboration.ShareId{ - OpaqueId: strconv.Itoa(int(share.ID)), - } - - shareState, err := m.getShareState(ctx, shareId, user) + shareState, err := m.getShareState(ctx, share, user) if err != nil { return nil, err } @@ -496,18 +486,28 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.Rece user := appctx.ContextMustGetUser(ctx) - rs, err := m.GetReceivedShare(ctx, &collaboration.ShareReference{Spec: &collaboration.ShareReference_Id{Id: share.Share.Id}}) + rs, err := m.getReceivedByID(ctx, share.Share.Id, user.Id.Type) + if err != nil { + return nil, err + } + + shareId, err := strconv.Atoi(share.Share.Id.OpaqueId) if err != nil { return nil, err } - shareState, err := m.getShareState(ctx, share.Share.Id, user) + shareState, err := m.getShareState(ctx, &model.Share{ + ProtoShare: model.ProtoShare{ + Model: gorm.Model{ + ID: uint(shareId), + }, + }, + }, user) if err != nil { return nil, err } // FieldMask determines which parts of the share we actually update - // Right now, only updating the state is supported for _, path := range fieldMask.Paths { switch path { case "state": diff --git a/share/sql/sql_test.go b/share/sql/sql_test.go index c85d5a3..dbe738a 100644 --- a/share/sql/sql_test.go +++ b/share/sql/sql_test.go @@ -363,6 +363,7 @@ func TestListReceivedShares(t *testing.T) { if len(receivedShares) != 1 { t.Errorf("Expected 1 received share, got %d", len(receivedShares)) + t.FailNow() } if receivedShares[0].Share.Id.OpaqueId != res.Id.OpaqueId { From ad9587a01d28aa17fcb2af5517ccdcc091cd0cc3 Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Mon, 13 Jan 2025 09:01:39 +0100 Subject: [PATCH 05/10] Resolving more comments on PR --- share/model.go | 2 -- share/sql/sql.go | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/share/model.go b/share/model.go index ac65af2..7807a0d 100644 --- a/share/model.go +++ b/share/model.go @@ -38,8 +38,6 @@ type ProtoShare struct { ItemType ItemType // file | folder | reference | symlink InitialPath string Inode string - FileSource int64 - FileTarget string Permissions uint8 Instance string Orphan bool diff --git a/share/sql/sql.go b/share/sql/sql.go index 71b227d..c12bce9 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -264,7 +264,21 @@ func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) ( } func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error { - share, err := m.getShare(ctx, ref) + var share *model.Share + var err error + if id := ref.GetId(); id != nil { + var intId int + intId, err = strconv.Atoi(id.OpaqueId) + share = &model.Share{ + ProtoShare: model.ProtoShare{ + Model: gorm.Model{ + ID: uint(intId), + }, + }, + } + } else { + share, err = m.getShare(ctx, ref) + } if err != nil { return err } @@ -273,15 +287,27 @@ func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) er } func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions) (*collaboration.Share, error) { - permissions := conversions.SharePermToInt(p.Permissions) - share, err := m.getShare(ctx, ref) + var share *model.Share + var err error + if id := ref.GetId(); id != nil { + var intId int + intId, err = strconv.Atoi(id.OpaqueId) + share = &model.Share{ + ProtoShare: model.ProtoShare{ + Model: gorm.Model{ + ID: uint(intId), + }, + }, + } + } else { + share, err = m.getShare(ctx, ref) + } if err != nil { return nil, err } - share.Permissions = uint8(permissions) - - res := m.db.Save(&share) + permissions := conversions.SharePermToInt(p.Permissions) + res := m.db.Model(&share).Update("permissions", uint8(permissions)) if res.Error != nil { return nil, res.Error } From af4e08dff17cca2a9b710366925ddcbd27d2aa66 Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Mon, 13 Jan 2025 13:32:51 +0100 Subject: [PATCH 06/10] Better error handling --- share/sql/sql.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/share/sql/sql.go b/share/sql/sql.go index c12bce9..40f686d 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -329,7 +329,12 @@ func (m *mgr) getPath(ctx context.Context, resID *provider.ResourceId) (string, return "", err } - return res.GetPath(), nil + if res.Status.Code == rpc.Code_CODE_OK { + return res.GetPath(), nil + } else if res.Status.Code == rpc.Code_CODE_NOT_FOUND { + return "", errtypes.NotFound(resID.OpaqueId) + } + return "", errors.New(res.Status.Code.String() + ": " + res.Status.Message) } func (m *mgr) isProjectAdmin(u *userpb.User, path string) bool { From 9cc87e94cd5b45a19e068bb8cfadea78faa5f97b Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Tue, 21 Jan 2025 09:19:01 +0100 Subject: [PATCH 07/10] Add alias field to ShareState --- go.mod | 35 ++++++------- go.sum | 140 ++++++++++++++++++++++++++++++++++--------------- share/model.go | 1 + 3 files changed, 116 insertions(+), 60 deletions(-) diff --git a/go.mod b/go.mod index e691c45..3dbfc41 100644 --- a/go.mod +++ b/go.mod @@ -5,18 +5,18 @@ go 1.22.7 require ( github.com/Masterminds/sprig v2.22.0+incompatible github.com/bluele/gcache v0.0.2 - github.com/cs3org/go-cs3apis v0.0.0-20240802083356-d617314e1795 + github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 github.com/cs3org/reva v1.27.0 github.com/disintegration/imaging v1.6.2 - github.com/go-chi/chi/v5 v5.1.0 + github.com/go-chi/chi/v5 v5.2.0 github.com/go-sql-driver/mysql v1.8.1 github.com/gomodule/redigo v1.9.2 github.com/juliangruber/go-intersect v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 - google.golang.org/genproto v0.0.0-20240314234333-6e1732d8331c - google.golang.org/grpc v1.65.0 + google.golang.org/genproto v0.0.0-20241209162323-e6fa225c2576 + google.golang.org/grpc v1.69.2 gorm.io/datatypes v1.2.4 gorm.io/driver/mysql v1.5.7 gorm.io/driver/sqlite v1.5.7 @@ -30,20 +30,20 @@ require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect - github.com/cern-eos/go-eosgrpc v0.0.0-20240812132646-f105d2304f38 // indirect - github.com/creasty/defaults v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/cern-eos/go-eosgrpc v0.0.0-20240909164147-ad693be93181 // indirect + github.com/creasty/defaults v1.8.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect - github.com/go-ldap/ldap/v3 v3.4.6 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect + github.com/go-ldap/ldap/v3 v3.4.9 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.19.0 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/huandu/xstrings v1.4.0 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -52,19 +52,18 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.24 // indirect - github.com/mileusna/useragent v1.3.4 // indirect + github.com/mileusna/useragent v1.3.5 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect - go.step.sm/crypto v0.43.1 // indirect + go.step.sm/crypto v0.55.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/image v0.13.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.33.0 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/protobuf v1.35.2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect + google.golang.org/protobuf v1.36.1 // indirect ) replace github.com/cs3org/reva => ../reva diff --git a/go.sum b/go.sum index 3627cb2..f44a273 100644 --- a/go.sum +++ b/go.sum @@ -12,45 +12,49 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/ReneKroon/ttlcache/v2 v2.11.0 h1:OvlcYFYi941SBN3v9dsDcC2N8vRxyHcCmJb3Vl4QMoM= github.com/ReneKroon/ttlcache/v2 v2.11.0/go.mod h1:mBxvsNY+BT8qLLd6CuAJubbKo6r0jh3nb5et22bbfGY= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/cern-eos/go-eosgrpc v0.0.0-20240812132646-f105d2304f38 h1:+81ss4Vut1khzEhl7ximWF/V+EadspY47V4JrQkwlI4= -github.com/cern-eos/go-eosgrpc v0.0.0-20240812132646-f105d2304f38/go.mod h1:ZiIzbg4sDO2MwYlspcnauUR2dfwZHUzxker+HP9k+20= +github.com/cern-eos/go-eosgrpc v0.0.0-20240909164147-ad693be93181 h1:2ZK/g0kTWuO98hM8uCuGnFwtljWhjI3k6nTQJLYj8vE= +github.com/cern-eos/go-eosgrpc v0.0.0-20240909164147-ad693be93181/go.mod h1:ZiIzbg4sDO2MwYlspcnauUR2dfwZHUzxker+HP9k+20= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= -github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= -github.com/cs3org/go-cs3apis v0.0.0-20240802083356-d617314e1795 h1:8WkweBxMQ1W6IhcK0X3eWY+aQCjEktGwVt/4KLrtOZ8= -github.com/cs3org/go-cs3apis v0.0.0-20240802083356-d617314e1795/go.mod h1:yyP8PRo0EZou3nSH7H4qjlzQwaydPeIRNgX50npQHpE= +github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= +github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= +github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 h1:RU6LT6mkD16xZs011+8foU7T3LrPvTTSWeTQ9OgfhkA= +github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= -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.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= +github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U= github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM= github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9 h1:3um08ooi0/lyRmK2eE1XTKmRQHDzPu0IvpCPMljyMZ8= github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9/go.mod h1:EJaddanP+JfU3UkVvn0rYYF3b/gD7eZRejbTHqiQExA= -github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= -github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= -github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= -github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= +github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= +github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-ldap/ldap/v3 v3.4.9 h1:KxX9eO44/MpqPXVVMPJDB+k/35GEePHE/Jfvl7oRMUo= +github.com/go-ldap/ldap/v3 v3.4.9/go.mod h1:+CE/4PPOOdEPGTi2B7qXKQOq+pNBvXZtlBNcVZY0AWI= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 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/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/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= -github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= +github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= @@ -69,11 +73,15 @@ github.com/gomodule/redigo v1.9.2 h1:HrutZBLhSIU8abiSfW8pj8mPhOyMYjZT/wcA4/L9L9s github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -84,6 +92,18 @@ github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= 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/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= @@ -91,9 +111,8 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/juliangruber/go-intersect v1.1.0 h1:sc+y5dCjMMx0pAdYk/N6KBm00tD/f3tq+Iox7dYDUrY= github.com/juliangruber/go-intersect v1.1.0/go.mod h1:WMau+1kAmnlQnKiikekNJbtGtfmILU/mMU6H7AgKbWQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -110,8 +129,8 @@ github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBW github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= -github.com/mileusna/useragent v1.3.4 h1:MiuRRuvGjEie1+yZHO88UBYg8YBC/ddF6T7F56i3PCk= -github.com/mileusna/useragent v1.3.4/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= +github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws= +github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -122,8 +141,6 @@ 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/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/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -131,25 +148,41 @@ github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -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/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o= github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.step.sm/crypto v0.43.1 h1:18Z/M49SnFDPXvFbfoN/ugE1i0J7phLWARhSQs/XSDI= -go.step.sm/crypto v0.43.1/go.mod h1:9n90D/SWjH1hTyQn1hgviUGyK8YRv743S8UZHYbt4BU= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.step.sm/crypto v0.55.0 h1:575Q7NahuM/ZRxUVN1GkO2e1aDYQJqIIg+nbfOajQJk= +go.step.sm/crypto v0.55.0/go.mod h1:MgEmD1lgwsuzZwTgI0GwKapHjKVEQLVggSvHuf3bYnU= go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -162,21 +195,33 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -191,19 +236,28 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -214,19 +268,21 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240314234333-6e1732d8331c h1:1AVpelW1Ld8u6QbfPlwh00uAsR3xrnfn6FIJsCags3k= -google.golang.org/genproto v0.0.0-20240314234333-6e1732d8331c/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto v0.0.0-20241209162323-e6fa225c2576 h1:k48HcZ4FE6in0o8IflZCkc1lTc2u37nhGd8P+fo4r24= +google.golang.org/genproto v0.0.0-20241209162323-e6fa225c2576/go.mod h1:DV2u3tCn/AcVjjmGYZKt6HyvY4w4y3ipAdHkMbe/0i4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/share/model.go b/share/model.go index 7807a0d..2cc5933 100644 --- a/share/model.go +++ b/share/model.go @@ -71,6 +71,7 @@ type ShareState struct { User string Synced bool Hidden bool + Alias string } func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { From 265f5694a890710f24a1f4ee9e79a7fb396191f0 Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Fri, 24 Jan 2025 13:38:08 +0100 Subject: [PATCH 08/10] Resolving more PR comments --- share/model.go | 22 ++++++++------- share/sql/sql.go | 72 ++++++++++++++++++++---------------------------- 2 files changed, 42 insertions(+), 52 deletions(-) diff --git a/share/model.go b/share/model.go index 2cc5933..1e35aff 100644 --- a/share/model.go +++ b/share/model.go @@ -38,17 +38,17 @@ type ProtoShare struct { ItemType ItemType // file | folder | reference | symlink InitialPath string Inode string - Permissions uint8 Instance string + Permissions uint8 Orphan bool - Description string - Expiration datatypes.Null[datatypes.Date] + Expiration datatypes.NullTime } type Share struct { ProtoShare ShareWith string SharedWithIsGroup bool + Description string } type PublicLink struct { @@ -60,7 +60,7 @@ type PublicLink struct { NotifyUploadsExtraRecipients string Password string // Users can give a name to a share - ShareName string + LinkName string } type ShareState struct { @@ -75,9 +75,12 @@ type ShareState struct { } func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { - ts := &typespb.Timestamp{ + creationTs := &typespb.Timestamp{ Seconds: uint64(s.CreatedAt.Unix()), } + updateTs := &typespb.Timestamp{ + Seconds: uint64(s.UpdatedAt.Unix()), + } return &collaboration.Share{ Id: &collaboration.ShareId{ OpaqueId: strconv.FormatUint(uint64(s.ID), 10), @@ -91,8 +94,8 @@ func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { Grantee: extractGrantee(s.SharedWithIsGroup, s.ShareWith, granteeType), Owner: conversions.MakeUserID(s.UIDOwner), Creator: conversions.MakeUserID(s.UIDInitiator), - Ctime: ts, - Mtime: ts, + Ctime: creationTs, + Mtime: updateTs, } } @@ -123,7 +126,7 @@ func (p *PublicLink) AsCS3PublicShare() *link.PublicShare { } var expires *typespb.Timestamp if p.Expiration.Valid { - exp, err := p.Expiration.V.Value() + exp, err := p.Expiration.Value() if err == nil { expiration := exp.(time.Time) expires = &typespb.Timestamp{ @@ -144,13 +147,12 @@ func (p *PublicLink) AsCS3PublicShare() *link.PublicShare { Owner: conversions.MakeUserID(p.UIDOwner), Creator: conversions.MakeUserID(p.UIDInitiator), Token: p.Token, - DisplayName: p.ShareName, + DisplayName: p.LinkName, PasswordProtected: pwd, Expiration: expires, Ctime: ts, Mtime: ts, Quicklink: p.Quicklink, - Description: p.Description, NotifyUploads: p.NotifyUploads, NotifyUploadsExtraRecipients: p.NotifyUploadsExtraRecipients, } diff --git a/share/sql/sql.go b/share/sql/sql.go index 40f686d..57c302f 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -79,8 +79,7 @@ type config struct { } type mgr struct { - c *config - //db *sql.DB + c *config db *gorm.DB } @@ -267,15 +266,7 @@ func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) er var share *model.Share var err error if id := ref.GetId(); id != nil { - var intId int - intId, err = strconv.Atoi(id.OpaqueId) - share = &model.Share{ - ProtoShare: model.ProtoShare{ - Model: gorm.Model{ - ID: uint(intId), - }, - }, - } + share, err = emptyShareWithId(id.OpaqueId) } else { share, err = m.getShare(ctx, ref) } @@ -290,15 +281,7 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference var share *model.Share var err error if id := ref.GetId(); id != nil { - var intId int - intId, err = strconv.Atoi(id.OpaqueId) - share = &model.Share{ - ProtoShare: model.ProtoShare{ - Model: gorm.Model{ - ID: uint(intId), - }, - }, - } + share, err = emptyShareWithId(id.OpaqueId) } else { share, err = m.getShare(ctx, ref) } @@ -432,7 +415,6 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F return receivedShares, nil } -// shareId *collaboration.ShareId func (m *mgr) getShareState(ctx context.Context, share *model.Share, user *userpb.User) (*model.ShareState, error) { var shareState model.ShareState query := m.db.Model(&shareState). @@ -449,14 +431,26 @@ func (m *mgr) getShareState(ctx context.Context, share *model.Share, user *userp Synced: false, User: user.Username, } - // Does not really matter if it fails, next time the user - // lists his shares this will just be called again - m.db.Save(&shareState) } return &shareState, nil } +func emptyShareWithId(id string) (*model.Share, error) { + intId, err := strconv.Atoi(id) + if err != nil { + return nil, err + } + share := &model.Share{ + ProtoShare: model.ProtoShare{ + Model: gorm.Model{ + ID: uint(intId), + }, + }, + } + return share, nil +} + func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId, gtype userpb.UserType) (*collaboration.ReceivedShare, error) { user := appctx.ContextMustGetUser(ctx) share, err := m.getByID(ctx, id) @@ -513,27 +507,21 @@ func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareRefe return s, nil } -func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) { +func (m *mgr) UpdateReceivedShare(ctx context.Context, recvShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) { user := appctx.ContextMustGetUser(ctx) - rs, err := m.getReceivedByID(ctx, share.Share.Id, user.Id.Type) + rs, err := m.getReceivedByID(ctx, recvShare.Share.Id, user.Id.Type) if err != nil { return nil, err } - shareId, err := strconv.Atoi(share.Share.Id.OpaqueId) + share, err := emptyShareWithId(recvShare.Share.Id.OpaqueId) if err != nil { return nil, err } - shareState, err := m.getShareState(ctx, &model.Share{ - ProtoShare: model.ProtoShare{ - Model: gorm.Model{ - ID: uint(shareId), - }, - }, - }, user) + shareState, err := m.getShareState(ctx, share, user) if err != nil { return nil, err } @@ -542,21 +530,21 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, share *collaboration.Rece for _, path := range fieldMask.Paths { switch path { case "state": - rs.State = share.State + rs.State = recvShare.State + switch rs.State { + case collaboration.ShareState_SHARE_STATE_ACCEPTED: + shareState.Hidden = false + case collaboration.ShareState_SHARE_STATE_REJECTED: + shareState.Hidden = true + } case "hidden": - rs.Hidden = share.Hidden + rs.Hidden = recvShare.Hidden default: return nil, errtypes.NotSupported("updating " + path + " is not supported") } } // Now we do the actual update to the db model - switch rs.State { - case collaboration.ShareState_SHARE_STATE_ACCEPTED: - shareState.Hidden = false - case collaboration.ShareState_SHARE_STATE_REJECTED: - shareState.Hidden = true - } res := m.db.Save(&shareState) if res.Error != nil { From 1ba26d6dd4776f13e0220069b6d4bb8d6f01d3dd Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Wed, 29 Jan 2025 10:38:36 +0100 Subject: [PATCH 09/10] Include new fields stemming from upgraded CS3APIs --- go.mod | 2 +- go.sum | 12 ++++++------ share/model.go | 2 ++ share/sql/sql.go | 6 +++++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 3dbfc41..19dd495 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.7 require ( github.com/Masterminds/sprig v2.22.0+incompatible github.com/bluele/gcache v0.0.2 - github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 + github.com/cs3org/go-cs3apis v0.0.0-20250128143938-cc671934a7a1 github.com/cs3org/reva v1.27.0 github.com/disintegration/imaging v1.6.2 github.com/go-chi/chi/v5 v5.2.0 diff --git a/go.sum b/go.sum index f44a273..3327963 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= -github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 h1:RU6LT6mkD16xZs011+8foU7T3LrPvTTSWeTQ9OgfhkA= -github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ= +github.com/cs3org/go-cs3apis v0.0.0-20250128143938-cc671934a7a1 h1:/WqyxkOGmocjx9ryVNGpwY3h+Fsm2VeQWweARkk0Svw= +github.com/cs3org/go-cs3apis v0.0.0-20250128143938-cc671934a7a1/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -154,8 +154,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o= github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -270,8 +270,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/share/model.go b/share/model.go index 1e35aff..1aa7267 100644 --- a/share/model.go +++ b/share/model.go @@ -96,6 +96,7 @@ func (s *Share) AsCS3Share(granteeType userpb.UserType) *collaboration.Share { Creator: conversions.MakeUserID(s.UIDInitiator), Ctime: creationTs, Mtime: updateTs, + Description: s.Description, } } @@ -113,6 +114,7 @@ func (s *Share) AsCS3ReceivedShare(state *ShareState, granteeType userpb.UserTyp Share: s.AsCS3Share(granteeType), State: rsharestate, Hidden: state.Hidden, + Alias: state.Alias, } } diff --git a/share/sql/sql.go b/share/sql/sql.go index 57c302f..ad132b7 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -110,7 +110,11 @@ func New(ctx context.Context, m map[string]interface{}) (revashare.Manager, erro } // Migrate schemas - db.AutoMigrate(&model.Share{}, &model.PublicLink{}, &model.ShareState{}) + err = db.AutoMigrate(&model.Share{}, &model.PublicLink{}, &model.ShareState{}) + + if err != nil { + return nil, err + } return &mgr{ c: &c, From 2bdd79825dfd29044332eff9a05d8b6fca18de59 Mon Sep 17 00:00:00 2001 From: Jesse Geens Date: Thu, 30 Jan 2025 17:01:20 +0100 Subject: [PATCH 10/10] Default db engine is mysql --- share/sql/sql.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/share/sql/sql.go b/share/sql/sql.go index ad132b7..7e60fd6 100644 --- a/share/sql/sql.go +++ b/share/sql/sql.go @@ -97,13 +97,14 @@ func New(ctx context.Context, m map[string]interface{}) (revashare.Manager, erro var db *gorm.DB var err error switch c.Engine { - case "mysql": - dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName) - db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) case "sqlite": db, err = gorm.Open(sqlite.Open(c.DBName), &gorm.Config{}) - default: - return nil, errors.New("ShareManager SQL: unsupported database type " + c.Engine) + case "mysql": + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName) + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + default: // default is mysql + dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName) + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) } if err != nil { return nil, err