Compare commits
3 Commits
33356f34e8
...
32d207a991
Author | SHA1 | Date | |
---|---|---|---|
32d207a991 | |||
ea718be066 | |||
d4c1cdb582 |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT folder_id FROM folders WHERE folder_id = $1 AND owner_id = $2",
|
||||
"query": "SELECT folder_id FROM files WHERE file_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -11,13 +11,12 @@
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int4"
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "dc98f1a609e67b642aed635b26239328e6456e69c12dc8561c474fff3dcd14d5"
|
||||
"hash": "09299172474d10a07387b74f4d714bf389b5422334bd1aa2a0e6f2d63ebdd623"
|
||||
}
|
36
.sqlx/query-347a486f9ea5183b1c4c16234a1833ea61970ea7f901dd57c0715ae3dbddd164.json
generated
Normal file
36
.sqlx/query-347a486f9ea5183b1c4c16234a1833ea61970ea7f901dd57c0715ae3dbddd164.json
generated
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE users SET username = $2, email = $3 WHERE user_id = $1 RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "347a486f9ea5183b1c4c16234a1833ea61970ea7f901dd57c0715ae3dbddd164"
|
||||
}
|
39
.sqlx/query-39b78c7f3266bea5e3e44aa372574319cb74dea6b3d0bc16d25e29ca28803317.json
generated
Normal file
39
.sqlx/query-39b78c7f3266bea5e3e44aa372574319cb74dea6b3d0bc16d25e29ca28803317.json
generated
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n username,\n permission_type as \"permission_type: PermissionRaw\"\nFROM\n permissions\n INNER JOIN users ON permissions.user_id = users.user_id\nWHERE\n folder_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "permission_type: PermissionRaw",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "permission",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"read",
|
||||
"write",
|
||||
"manage"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "39b78c7f3266bea5e3e44aa372574319cb74dea6b3d0bc16d25e29ca28803317"
|
||||
}
|
23
.sqlx/query-443854b9fb234840588e0100774d3ab51c4532b14d50e5ca3578fe6311e2017a.json
generated
Normal file
23
.sqlx/query-443854b9fb234840588e0100774d3ab51c4532b14d50e5ca3578fe6311e2017a.json
generated
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n EXISTS (\n SELECT\n file_name as name\n FROM\n files\n WHERE\n folder_id = $1\n AND file_name = $2\n UNION\n SELECT\n folder_name as name\n FROM\n folders\n WHERE\n parent_folder_id = $1\n AND folder_name = $2\n )",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "443854b9fb234840588e0100774d3ab51c4532b14d50e5ca3578fe6311e2017a"
|
||||
}
|
16
.sqlx/query-4c7c701a22c49eebb4ba31a21dab15a5dbe2eaba99036932790c7c09599d4cd7.json
generated
Normal file
16
.sqlx/query-4c7c701a22c49eebb4ba31a21dab15a5dbe2eaba99036932790c7c09599d4cd7.json
generated
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE files SET (sha512, file_size, updated_at) = ($2, $3, NOW()) WHERE file_id = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Bytea",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4c7c701a22c49eebb4ba31a21dab15a5dbe2eaba99036932790c7c09599d4cd7"
|
||||
}
|
27
.sqlx/query-595739c03acbe706107e34a3ebebec8c8f21f70ccc51b5366eff962d9af391d7.json
generated
Normal file
27
.sqlx/query-595739c03acbe706107e34a3ebebec8c8f21f70ccc51b5366eff962d9af391d7.json
generated
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH RECURSIVE folder_hierarchy AS (\n -- Start with the given directory\n SELECT \n folder_id \n FROM \n folders \n WHERE \n folder_id = $1\n\n UNION ALL\n\n -- Recursively find all subdirectories\n SELECT \n f.folder_id\n FROM \n folders f\n INNER JOIN \n folder_hierarchy fh ON f.parent_folder_id = fh.folder_id\n)\nINSERT INTO permissions(user_id, folder_id, permission_type)\nSELECT $2::integer as user_id, fh.folder_id::UUID as folder_id, $3\nFROM folder_hierarchy fh\nON CONFLICT (user_id, folder_id) DO UPDATE\nSET permission_type = $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int4",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "permission",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"read",
|
||||
"write",
|
||||
"manage"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "595739c03acbe706107e34a3ebebec8c8f21f70ccc51b5366eff962d9af391d7"
|
||||
}
|
34
.sqlx/query-61a26b3321bb5b58a0b90e61b2cdcacfb46a03eb0c0a89839c9b3eff53cb7e56.json
generated
Normal file
34
.sqlx/query-61a26b3321bb5b58a0b90e61b2cdcacfb46a03eb0c0a89839c9b3eff53cb7e56.json
generated
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n user_id, username, email\nFROM\n users\nORDER BY\n GREATEST (\n similarity (email, $1),\n similarity (username, $1)\n ) DESC",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "61a26b3321bb5b58a0b90e61b2cdcacfb46a03eb0c0a89839c9b3eff53cb7e56"
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO files(file_id, folder_id, owner_id, file_name, file_size, sha512) VALUES ($1, $2, $3, $4, $5, $6)",
|
||||
"query": "INSERT INTO files(file_id, folder_id, file_name, file_size, sha512) VALUES ($1, $2, $3, $4, $5)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Uuid",
|
||||
"Int4",
|
||||
"Varchar",
|
||||
"Int8",
|
||||
"Bytea"
|
||||
@ -15,5 +14,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9a70e24a3de68f4a66718124bd3ca959bd0a992e5e0dda3baae52b8cb545ce66"
|
||||
"hash": "6b58c84cdc19cea97ef025211a98879bb5cc80a934490125a19c960133f6d93d"
|
||||
}
|
34
.sqlx/query-87f7df91208438a35516604f57f0443e0f12db718e23acd374f6f7ace65f467d.json
generated
Normal file
34
.sqlx/query-87f7df91208438a35516604f57f0443e0f12db718e23acd374f6f7ace65f467d.json
generated
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n permission_type as \"permission_type: PermissionRaw\"\nFROM\n permissions\nWHERE\n folder_id = $1\n AND user_id = $2\nUNION\nSELECT\n 'manage' as \"permission_type: PermissionRaw\"\nFROM\n folders\nWHERE\n folder_id = $1\n AND owner_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "permission_type: PermissionRaw",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "permission",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"read",
|
||||
"write",
|
||||
"manage"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "87f7df91208438a35516604f57f0443e0f12db718e23acd374f6f7ace65f467d"
|
||||
}
|
15
.sqlx/query-948f13b631bcc7df1919a9639443f0ed932c4cb37f2ba5bf6f000eb84b265ae2.json
generated
Normal file
15
.sqlx/query-948f13b631bcc7df1919a9639443f0ed932c4cb37f2ba5bf6f000eb84b265ae2.json
generated
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH RECURSIVE folder_hierarchy AS (\n -- Start with the given directory\n SELECT \n folder_id \n FROM \n folders \n WHERE \n folder_id = $1\n\n UNION ALL\n\n -- Recursively find all subdirectories\n SELECT \n f.folder_id\n FROM \n folders f\n INNER JOIN \n folder_hierarchy fh ON f.parent_folder_id = fh.folder_id\n)\nDELETE FROM permissions WHERE user_id = $2 AND folder_id IN (SELECT folder_id FROM folder_hierarchy)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "948f13b631bcc7df1919a9639443f0ed932c4cb37f2ba5bf6f000eb84b265ae2"
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT file_id FROM files WHERE file_id = $1 AND owner_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "file_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "9a26dab9efbbbb92b7be27792b581a0156210fdc0aadd3756f7003186f428374"
|
||||
}
|
22
.sqlx/query-a54829e9cd90e55022c2f6dd413b797efaafd1c4793b60886140bfe9ea6df592.json
generated
Normal file
22
.sqlx/query-a54829e9cd90e55022c2f6dd413b797efaafd1c4793b60886140bfe9ea6df592.json
generated
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH\n deleted_files AS (\n DELETE FROM files USING folders\n WHERE\n files.folder_id = folders.folder_id\n AND folders.owner_id = $1 RETURNING files.file_id\n ),\n deleted_users AS (\n DELETE FROM users\n WHERE\n user_id = $1\n )\nSELECT\n *\nFROM\n deleted_files;",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "file_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a54829e9cd90e55022c2f6dd413b797efaafd1c4793b60886140bfe9ea6df592"
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT folder_id FROM folders WHERE parent_folder_id = $1 AND folder_name = $2)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "cd3591c61f3cc036158d8d55ec22a04adaf62ec4b05ba73da9253128b7bbb5b1"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT file_id, owner_id, file_name, file_size, sha512, created_at, updated_at FROM files WHERE folder_id = $1",
|
||||
"query": "SELECT file_id, file_name, file_size, encode(sha512, 'base64') as \"sha512!\", created_at, updated_at FROM files WHERE folder_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -10,31 +10,26 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "owner_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "file_name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"ordinal": 2,
|
||||
"name": "file_size",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "sha512",
|
||||
"type_info": "Bytea"
|
||||
"ordinal": 3,
|
||||
"name": "sha512!",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 4,
|
||||
"name": "created_at",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 5,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamp"
|
||||
}
|
||||
@ -48,11 +43,10 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "5a51ab540453327bdd75f49991f402fac6b1d8fb0a760d420236e2b41d3e7fcf"
|
||||
"hash": "e125c9f06cb89c6ddd2653ed45c576da3aecfb9fb74aabf202e83406fc8c8fff"
|
||||
}
|
22
.sqlx/query-f9e36f45f25dd2439a7a0b16b6df356a0a2a47e70b6e031ea5a0442adc86725b.json
generated
Normal file
22
.sqlx/query-f9e36f45f25dd2439a7a0b16b6df356a0a2a47e70b6e031ea5a0442adc86725b.json
generated
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH\n permitted as (\n SELECT\n folder_id\n FROM\n permissions\n WHERE\n user_id = $1\n )\nSELECT\n folder_id\nFROM\n folders\nWHERE\n folder_id IN (\n SELECT\n folder_id\n FROM\n permitted\n )\n AND parent_folder_id NOT IN (\n SELECT\n folder_id\n FROM\n permitted\n )",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "folder_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f9e36f45f25dd2439a7a0b16b6df356a0a2a47e70b6e031ea5a0442adc86725b"
|
||||
}
|
34
.sqlx/query-fd53e5f2c7e8aa87f3cf4e430a6ec3a632ce125fdb092dbd17630e952d4e0d9e.json
generated
Normal file
34
.sqlx/query-fd53e5f2c7e8aa87f3cf4e430a6ec3a632ce125fdb092dbd17630e952d4e0d9e.json
generated
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT user_id, username, email FROM users WHERE user_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "fd53e5f2c7e8aa87f3cf4e430a6ec3a632ce125fdb092dbd17630e952d4e0d9e"
|
||||
}
|
297
Cargo.lock
generated
297
Cargo.lock
generated
@ -26,7 +26,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
"zerocopy 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -107,7 +107,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -220,7 +220,7 @@ dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -321,9 +321,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
|
||||
checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
@ -572,21 +572,6 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
@ -663,7 +648,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1002,22 +987,6 @@ dependencies = [
|
||||
"webpki-roots 0.26.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.6"
|
||||
@ -1079,6 +1048,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1261,23 +1231,6 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@ -1396,50 +1349,6 @@ version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
@ -1523,7 +1432,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1573,12 +1482,35 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.19"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2288c0e17cc8d342c712bb43a257a80ebffce59cdb33d5000d8348f3ec02528b"
|
||||
checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
"zerocopy-derive",
|
||||
"zerocopy 0.6.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1612,6 +1544,8 @@ dependencies = [
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"utoipa",
|
||||
"utoipauto",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
@ -1811,7 +1745,6 @@ checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.4.5",
|
||||
@ -1820,13 +1753,11 @@ dependencies = [
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper-rustls 0.27.2",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
@ -1838,9 +1769,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.0",
|
||||
"tower-service",
|
||||
"url",
|
||||
@ -1995,15 +1924,6 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@ -2020,29 +1940,6 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.204"
|
||||
@ -2060,7 +1957,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2274,7 +2171,7 @@ dependencies = [
|
||||
"quote",
|
||||
"sqlx-core",
|
||||
"sqlx-macros-core",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2297,7 +2194,7 @@ dependencies = [
|
||||
"sqlx-mysql",
|
||||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"url",
|
||||
@ -2429,6 +2326,16 @@ version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
@ -2502,7 +2409,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2585,17 +2492,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2713,7 +2610,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2819,6 +2716,64 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"utoipa-gen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bf0e16c02bc4bf5322ab65f10ab1149bdbcaa782cba66dc7057370a3f8190be"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 2.0.72",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4713aabc5ed18aabcd594345b48983b112c0b5dab3d24754352e7f5cf924da03"
|
||||
dependencies = [
|
||||
"utoipauto-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto-core"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17e82ab96c5a55263b5bed151b8426410d93aa909a453acdbd4b6792b5af7d64"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto-macro"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b8338dc3c9526011ffaa2aa6bd60ddfda9d49d2123108690755c6e34844212"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
"utoipauto-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
@ -2889,7 +2844,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -2923,7 +2878,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -3159,14 +3114,34 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive 0.6.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
"zerocopy-derive 0.7.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3177,7 +3152,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.72",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -26,7 +26,11 @@ dotenvy = "0.15"
|
||||
futures = "0.3"
|
||||
jsonwebtoken = "9"
|
||||
oauth2 = "4"
|
||||
reqwest = { version = "0.12", features = ["http2", "rustls-tls", "json"] }
|
||||
reqwest = { version = "0.12", features = [
|
||||
"http2",
|
||||
"rustls-tls",
|
||||
"json",
|
||||
], default-features = false }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
sha2 = "0.10"
|
||||
sqlx = { version = "0.8", features = [
|
||||
@ -51,4 +55,6 @@ tracing-subscriber = { version = "0.3", features = [
|
||||
"parking_lot",
|
||||
"env-filter",
|
||||
] }
|
||||
uuid = { version = "1", features = ["serde", "v4"] }
|
||||
utoipa = { version = "4", features = ["axum_extras", "uuid", "chrono"] }
|
||||
utoipauto = "0.1"
|
||||
uuid = { version = "1", features = ["serde", "v7"] }
|
||||
|
@ -1,6 +1,6 @@
|
||||
services:
|
||||
db:
|
||||
image: postgres:alpine
|
||||
image: ghcr.io/fboulnois/pg_uuidv7:1.5.0
|
||||
environment:
|
||||
- POSTGRES_USER=tester
|
||||
- POSTGRES_PASSWORD=testing123!
|
||||
|
@ -1,3 +1,7 @@
|
||||
DROP EXTENSION IF EXISTS pg_trgm;
|
||||
|
||||
DROP EXTENSION IF EXISTS pg_uuidv7;
|
||||
|
||||
DROP TABLE permissions;
|
||||
|
||||
DROP TABLE files;
|
||||
|
@ -1,3 +1,7 @@
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS pg_uuidv7;
|
||||
|
||||
CREATE TABLE
|
||||
users (
|
||||
user_id SERIAL PRIMARY KEY,
|
||||
@ -7,7 +11,7 @@ CREATE TABLE
|
||||
|
||||
CREATE TABLE
|
||||
folders (
|
||||
folder_id UUID PRIMARY KEY DEFAULT gen_random_uuid (),
|
||||
folder_id UUID PRIMARY KEY DEFAULT uuid_generate_v7 (),
|
||||
parent_folder_id UUID REFERENCES folders (folder_id) ON DELETE CASCADE DEFAULT null,
|
||||
owner_id INT REFERENCES users (user_id) ON DELETE CASCADE NOT NULL,
|
||||
folder_name VARCHAR(255) NOT NULL,
|
||||
@ -16,7 +20,7 @@ CREATE TABLE
|
||||
|
||||
CREATE TABLE
|
||||
files (
|
||||
file_id UUID PRIMARY KEY DEFAULT gen_random_uuid (),
|
||||
file_id UUID PRIMARY KEY DEFAULT uuid_generate_v7 (),
|
||||
folder_id UUID REFERENCES folders (folder_id) ON DELETE CASCADE NOT NULL,
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
file_size BIGINT NOT NULL,
|
||||
|
16
sql/delete_user.sql
Normal file
16
sql/delete_user.sql
Normal file
@ -0,0 +1,16 @@
|
||||
WITH
|
||||
deleted_files AS (
|
||||
DELETE FROM files USING folders
|
||||
WHERE
|
||||
files.folder_id = folders.folder_id
|
||||
AND folders.owner_id = $1 RETURNING files.file_id
|
||||
),
|
||||
deleted_users AS (
|
||||
DELETE FROM users
|
||||
WHERE
|
||||
user_id = $1
|
||||
)
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
deleted_files;
|
18
sql/name_exists.sql
Normal file
18
sql/name_exists.sql
Normal file
@ -0,0 +1,18 @@
|
||||
SELECT
|
||||
EXISTS (
|
||||
SELECT
|
||||
file_name as name
|
||||
FROM
|
||||
files
|
||||
WHERE
|
||||
folder_id = $1
|
||||
AND file_name = $2
|
||||
UNION
|
||||
SELECT
|
||||
folder_name as name
|
||||
FROM
|
||||
folders
|
||||
WHERE
|
||||
parent_folder_id = $1
|
||||
AND folder_name = $2
|
||||
)
|
9
sql/search_for_user.sql
Normal file
9
sql/search_for_user.sql
Normal file
@ -0,0 +1,9 @@
|
||||
SELECT
|
||||
user_id, username, email
|
||||
FROM
|
||||
users
|
||||
ORDER BY
|
||||
GREATEST (
|
||||
similarity (email, $1),
|
||||
similarity (username, $1)
|
||||
) DESC
|
@ -1,6 +1,4 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use futures::TryStreamExt;
|
||||
use futures::{Stream, TryStreamExt};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{db::permissions::PermissionRaw, Pool};
|
||||
@ -19,12 +17,10 @@ pub async fn get_permissions(
|
||||
Ok(permission.into())
|
||||
}
|
||||
|
||||
pub async fn get_names(folder_id: Uuid, pool: &Pool) -> sqlx::Result<HashSet<String>> {
|
||||
pub fn get_names(folder_id: Uuid, pool: &Pool) -> impl Stream<Item = sqlx::Result<String>> + '_ {
|
||||
sqlx::query!("SELECT folder_name as name FROM folders WHERE parent_folder_id = $1 UNION SELECT file_name as name FROM files WHERE folder_id = $1", folder_id)
|
||||
.fetch(pool)
|
||||
.map_ok(|record| record.name.unwrap())
|
||||
.try_collect::<HashSet<String>>()
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_root(user_id: i32, pool: &Pool) -> sqlx::Result<Uuid> {
|
||||
@ -68,21 +64,11 @@ pub async fn get_folders(
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn exists_by_name(
|
||||
parent_folder_id: Uuid,
|
||||
folder_name: &str,
|
||||
pool: &Pool,
|
||||
) -> sqlx::Result<bool> {
|
||||
sqlx::query!(
|
||||
"SELECT EXISTS(SELECT folder_id FROM folders WHERE parent_folder_id = $1 AND folder_name = $2)",
|
||||
parent_folder_id,
|
||||
folder_name
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.and_then(|row| {
|
||||
row.exists.ok_or(sqlx::Error::RowNotFound)
|
||||
})
|
||||
pub async fn name_exists(parent_folder_id: Uuid, name: &str, pool: &Pool) -> sqlx::Result<bool> {
|
||||
sqlx::query_file!("sql/name_exists.sql", parent_folder_id, name)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map(|row| row.exists.unwrap_or(false))
|
||||
}
|
||||
|
||||
pub async fn insert(
|
||||
@ -101,10 +87,8 @@ pub async fn insert(
|
||||
.map(|record| record.folder_id)
|
||||
}
|
||||
|
||||
pub async fn delete(folder_id: Uuid, pool: &Pool) -> sqlx::Result<Vec<Uuid>> {
|
||||
pub fn delete(folder_id: Uuid, pool: &Pool) -> impl Stream<Item = sqlx::Result<Uuid>> + '_ {
|
||||
sqlx::query_file!("sql/delete_folder.sql", folder_id)
|
||||
.fetch(pool)
|
||||
.map_ok(|row| row.file_id)
|
||||
.try_collect()
|
||||
.await
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod file;
|
||||
pub mod folder;
|
||||
pub mod permissions;
|
||||
pub mod users;
|
||||
|
73
src/db/users.rs
Normal file
73
src/db/users.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use futures::{stream::BoxStream, Stream, TryStreamExt};
|
||||
use serde::Serialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::Pool;
|
||||
|
||||
/// Creates user and returns its id
|
||||
pub async fn create_user(user_name: &str, user_email: &str, pool: &Pool) -> sqlx::Result<i32> {
|
||||
let id = sqlx::query!(
|
||||
"INSERT INTO users(username, email) VALUES ($1, $2) RETURNING user_id",
|
||||
user_name,
|
||||
user_email
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
.user_id;
|
||||
sqlx::query!(
|
||||
"INSERT INTO folders(owner_id, folder_name) VALUES ($1, $2)",
|
||||
id,
|
||||
"ROOT"
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Deletes the user and returns the files that must be deleted
|
||||
pub fn delete_user(user_id: i32, pool: &Pool) -> impl Stream<Item = sqlx::Result<Uuid>> + '_ {
|
||||
sqlx::query_file!("sql/delete_user.sql", user_id)
|
||||
.fetch(pool)
|
||||
.map_ok(|record| record.file_id)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
pub struct UserInfo {
|
||||
user_id: i32,
|
||||
username: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
user_id: i32,
|
||||
username: &str,
|
||||
email: &str,
|
||||
pool: &Pool,
|
||||
) -> sqlx::Result<UserInfo> {
|
||||
sqlx::query_as!(
|
||||
UserInfo,
|
||||
"UPDATE users SET username = $2, email = $3 WHERE user_id = $1 RETURNING *",
|
||||
user_id,
|
||||
username,
|
||||
email
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get(user_id: i32, pool: &Pool) -> sqlx::Result<UserInfo> {
|
||||
sqlx::query_as!(
|
||||
UserInfo,
|
||||
"SELECT user_id, username, email FROM users WHERE user_id = $1",
|
||||
user_id
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn search_for_user<'a>(
|
||||
search_string: &str,
|
||||
pool: &'a Pool,
|
||||
) -> BoxStream<'a, sqlx::Result<UserInfo>> {
|
||||
sqlx::query_file_as!(UserInfo, "sql/search_for_user.sql", search_string).fetch(pool)
|
||||
}
|
@ -18,7 +18,7 @@ pub async fn modify(
|
||||
.handle_internal()?
|
||||
.can_write_guard()?;
|
||||
|
||||
// Very weird work around
|
||||
// Very weird work around to get the first file in multipart
|
||||
let mut field = loop {
|
||||
match multipart.next_field().await {
|
||||
Ok(Some(field)) if field.file_name().is_some() => break field,
|
||||
@ -34,13 +34,13 @@ pub async fn modify(
|
||||
.handle_internal()?
|
||||
.ok_or(StatusCode::NOT_FOUND)?;
|
||||
|
||||
let (hash, size) = match crate::FileStorage::write_to_file(&mut file, &mut field).await {
|
||||
Ok(values) => values,
|
||||
Err(err) => {
|
||||
let (hash, size) = crate::FileStorage::write_to_file(&mut file, &mut field)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
tracing::warn!(%err);
|
||||
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
};
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
|
||||
db::file::update(params.file_id, size, hash, &state.pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use axum::extract::multipart::{self, Multipart};
|
||||
use futures::TryStreamExt;
|
||||
use tokio::io::AsyncWrite;
|
||||
|
||||
use crate::prelude::*;
|
||||
@ -42,7 +43,8 @@ pub async fn upload(
|
||||
.handle_internal()?
|
||||
.can_write_guard()?;
|
||||
|
||||
let existing_names = db::folder::get_names(params.parent_folder, &state.pool)
|
||||
let existing_names: HashSet<String> = db::folder::get_names(params.parent_folder, &state.pool)
|
||||
.try_collect()
|
||||
.await
|
||||
.handle_internal()?;
|
||||
let mut result = HashMap::new();
|
||||
|
@ -7,19 +7,18 @@ pub struct Params {
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
State(state): State<AppState>,
|
||||
State(pool): State<Pool>,
|
||||
claims: Claims,
|
||||
Json(params): Json<Params>,
|
||||
) -> Result<Json<Uuid>, StatusCode> {
|
||||
db::folder::get_permissions(params.parent_folder_id, claims.user_id, &state.pool)
|
||||
db::folder::get_permissions(params.parent_folder_id, claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?
|
||||
.can_write_guard()?;
|
||||
|
||||
let exists =
|
||||
db::folder::exists_by_name(params.parent_folder_id, ¶ms.folder_name, &state.pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
let exists = db::folder::name_exists(params.parent_folder_id, ¶ms.folder_name, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
if exists {
|
||||
return Err(StatusCode::CONFLICT);
|
||||
}
|
||||
@ -28,7 +27,7 @@ pub async fn create(
|
||||
params.parent_folder_id,
|
||||
claims.user_id,
|
||||
¶ms.folder_name,
|
||||
&state.pool,
|
||||
&pool,
|
||||
)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
|
@ -1,3 +1,5 @@
|
||||
use futures::TryStreamExt;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
@ -22,14 +24,12 @@ pub async fn delete(
|
||||
.handle_internal()?
|
||||
.can_write_guard()?;
|
||||
|
||||
let files_to_delete = db::folder::delete(params.folder_id, &state.pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
let storage = &state.storage;
|
||||
futures::stream::iter(files_to_delete)
|
||||
.for_each_concurrent(5, |file| async move {
|
||||
db::folder::delete(params.folder_id, &state.pool)
|
||||
.try_for_each_concurrent(5, |file| async move {
|
||||
let _ = storage.delete(file).await;
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
Ok(())
|
||||
.await
|
||||
.handle_internal()
|
||||
}
|
||||
|
@ -16,17 +16,17 @@ pub struct Response {
|
||||
|
||||
pub async fn list(
|
||||
Query(params): Query<Params>,
|
||||
State(state): State<AppState>,
|
||||
State(pool): State<Pool>,
|
||||
claims: Claims,
|
||||
) -> Result<Json<Response>, StatusCode> {
|
||||
let folder_id = db::folder::get_by_id(params.folder_id, claims.user_id, &state.pool)
|
||||
let folder_id = db::folder::get_by_id(params.folder_id, claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?
|
||||
.ok_or(StatusCode::NOT_FOUND)?;
|
||||
|
||||
let (files, folders) = try_join!(
|
||||
db::file::get_files(folder_id, &state.pool),
|
||||
db::folder::get_folders(folder_id, &state.pool)
|
||||
db::file::get_files(folder_id, &pool),
|
||||
db::folder::get_folders(folder_id, &pool)
|
||||
)
|
||||
.handle_internal()?;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod file;
|
||||
pub mod folder;
|
||||
pub mod permissions;
|
||||
pub mod users;
|
||||
|
@ -7,18 +7,18 @@ pub struct Params {
|
||||
}
|
||||
|
||||
pub async fn delete(
|
||||
State(pool): State<Pool>,
|
||||
claims: Claims,
|
||||
State(state): State<AppState>,
|
||||
Json(params): Json<Params>,
|
||||
) -> Result<StatusCode, StatusCode> {
|
||||
if params.user_id != claims.user_id {
|
||||
db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
|
||||
db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?
|
||||
.can_manage_guard()?;
|
||||
}
|
||||
|
||||
db::permissions::delete_for_folder(params.folder_id, params.user_id, &state.pool)
|
||||
db::permissions::delete_for_folder(params.folder_id, params.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
|
||||
|
@ -10,16 +10,16 @@ pub struct Params {
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
State(pool): State<Pool>,
|
||||
Query(params): Query<Params>,
|
||||
claims: Claims,
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<HashMap<String, PermissionRaw>>, StatusCode> {
|
||||
db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
|
||||
db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?
|
||||
.can_manage_guard()?;
|
||||
|
||||
let permissions = db::permissions::get_all_for_folder(params.folder_id, &state.pool)
|
||||
let permissions = db::permissions::get_all_for_folder(params.folder_id, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
Ok(Json(permissions))
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn get_top_level(
|
||||
State(state): State<AppState>,
|
||||
State(pool): State<Pool>,
|
||||
claims: Claims,
|
||||
) -> Result<Json<Vec<Uuid>>, StatusCode> {
|
||||
let folders = db::permissions::get_top_level_permitted_folders(claims.user_id, &state.pool)
|
||||
let folders = db::permissions::get_top_level_permitted_folders(claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
Ok(Json(folders))
|
@ -1,4 +1,4 @@
|
||||
pub mod delete;
|
||||
pub mod get;
|
||||
pub mod get_top_level_permitted_folders;
|
||||
pub mod get_top_level;
|
||||
pub mod set;
|
||||
|
@ -11,17 +11,17 @@ pub struct Params {
|
||||
|
||||
pub async fn set(
|
||||
claims: Claims,
|
||||
State(state): State<AppState>,
|
||||
State(pool): State<Pool>,
|
||||
Json(params): Json<Params>,
|
||||
) -> Result<StatusCode, StatusCode> {
|
||||
let root = db::folder::get_root(claims.user_id, &state.pool)
|
||||
let root = db::folder::get_root(claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
if params.folder_id == root {
|
||||
return Err(StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
|
||||
db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?
|
||||
.can_manage_guard()?;
|
||||
@ -30,7 +30,7 @@ pub async fn set(
|
||||
params.user_id,
|
||||
params.folder_id,
|
||||
params.permission_type,
|
||||
&state.pool,
|
||||
&pool,
|
||||
)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
|
17
src/endpoints/users/create.rs
Normal file
17
src/endpoints/users/create.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Params {
|
||||
username: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
State(pool): State<Pool>,
|
||||
Json(params): Json<Params>,
|
||||
) -> Result<Json<i32>, StatusCode> {
|
||||
let id = db::users::create_user(¶ms.username, ¶ms.email, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
Ok(Json(id))
|
||||
}
|
16
src/endpoints/users/delete.rs
Normal file
16
src/endpoints/users/delete.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use futures::TryStreamExt;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub async fn delete(
|
||||
State(AppState { pool, ref storage }): State<AppState>,
|
||||
claims: Claims,
|
||||
) -> Result<(), StatusCode> {
|
||||
db::users::delete_user(claims.user_id, &pool)
|
||||
.try_for_each_concurrent(5, |file_id| async move {
|
||||
let _ = storage.delete(file_id).await;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
.handle_internal()
|
||||
}
|
16
src/endpoints/users/get.rs
Normal file
16
src/endpoints/users/get.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Params {
|
||||
user_id: i32,
|
||||
}
|
||||
|
||||
pub async fn get(
|
||||
State(pool): State<Pool>,
|
||||
Query(params): Query<Params>,
|
||||
) -> Result<Json<db::users::UserInfo>, StatusCode> {
|
||||
let info = db::users::get(params.user_id, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
Ok(Json(info))
|
||||
}
|
5
src/endpoints/users/mod.rs
Normal file
5
src/endpoints/users/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod create;
|
||||
pub mod delete;
|
||||
pub mod get;
|
||||
pub mod put;
|
||||
pub mod search;
|
18
src/endpoints/users/put.rs
Normal file
18
src/endpoints/users/put.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Params {
|
||||
username: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
pub async fn put(
|
||||
State(pool): State<Pool>,
|
||||
claims: Claims,
|
||||
Json(params): Json<Params>,
|
||||
) -> Result<Json<db::users::UserInfo>, StatusCode> {
|
||||
let info = db::users::update(claims.user_id, ¶ms.username, ¶ms.email, &pool)
|
||||
.await
|
||||
.handle_internal()?;
|
||||
Ok(Json(info))
|
||||
}
|
20
src/endpoints/users/search.rs
Normal file
20
src/endpoints/users/search.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use futures::TryStreamExt;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Params {
|
||||
search_string: String,
|
||||
}
|
||||
|
||||
pub async fn search(
|
||||
State(pool): State<Pool>,
|
||||
Query(params): Query<Params>,
|
||||
) -> sqlx::Result<Json<Vec<db::users::UserInfo>>, StatusCode> {
|
||||
let users = db::users::search_for_user(¶ms.search_string, &pool)
|
||||
.take(20)
|
||||
.try_collect()
|
||||
.await
|
||||
.handle_internal()?;
|
||||
Ok(Json(users))
|
||||
}
|
@ -21,7 +21,7 @@ impl FileStorage {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let var = env::var("DRIVE_STORAGE_PATH");
|
||||
let path_str = match var {
|
||||
Ok(ref string) => string,
|
||||
Ok(ref string) => string.trim(),
|
||||
Err(err) => {
|
||||
tracing::info!(
|
||||
%err,
|
||||
@ -55,7 +55,7 @@ impl FileStorage {
|
||||
pub async fn create(&self) -> anyhow::Result<(Uuid, impl tokio::io::AsyncWrite)> {
|
||||
let mut error = anyhow::anyhow!("Error creating a file");
|
||||
for _ in 0..3 {
|
||||
let file_id = Uuid::new_v4();
|
||||
let file_id = Uuid::now_v7();
|
||||
match self.create_inner(file_id).await {
|
||||
Ok(file) => return Ok((file_id, file)),
|
||||
Err(err) => error = error.context(err),
|
||||
|
51
src/main.rs
51
src/main.rs
@ -7,7 +7,7 @@ mod prelude;
|
||||
|
||||
use std::{env, net::Ipv4Addr};
|
||||
|
||||
use axum::Router;
|
||||
use axum::{extract::FromRef, Router};
|
||||
use file_storage::FileStorage;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
@ -19,26 +19,13 @@ struct AppState {
|
||||
storage: FileStorage,
|
||||
}
|
||||
|
||||
async fn create_user(user_name: &str, user_email: &str, pool: &Pool) -> anyhow::Result<i32> {
|
||||
let id = sqlx::query!(
|
||||
"INSERT INTO users(username, email) VALUES ($1, $2) RETURNING user_id",
|
||||
user_name,
|
||||
user_email
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
.user_id;
|
||||
sqlx::query!(
|
||||
"INSERT INTO folders(owner_id, folder_name) VALUES ($1, $2)",
|
||||
id,
|
||||
"ROOT"
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(id)
|
||||
impl FromRef<AppState> for Pool {
|
||||
fn from_ref(input: &AppState) -> Self {
|
||||
input.pool.clone()
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_debug_users(pool: &Pool) -> anyhow::Result<()> {
|
||||
async fn create_test_users(pool: &Pool) -> anyhow::Result<()> {
|
||||
let count = sqlx::query!("SELECT count(user_id) FROM users")
|
||||
.fetch_one(pool)
|
||||
.await?
|
||||
@ -49,8 +36,8 @@ async fn create_debug_users(pool: &Pool) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
tokio::try_join!(
|
||||
create_user("Test1", "test1@example.com", pool),
|
||||
create_user("Test2", "test2@example.com", pool)
|
||||
db::users::create_user("Test1", "test1@example.com", pool),
|
||||
db::users::create_user("Test2", "test2@example.com", pool)
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@ -68,11 +55,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
Err(err) => anyhow::bail!("Error getting database url: {err}"),
|
||||
};
|
||||
sqlx::migrate!().run(&pool).await?;
|
||||
create_debug_users(&pool).await?;
|
||||
if let Ok("1") = env::var("DEVELOPMENT").as_deref().map(str::trim_ascii) {
|
||||
create_test_users(&pool).await?;
|
||||
}
|
||||
|
||||
let storage = file_storage::FileStorage::new()?;
|
||||
|
||||
let state = AppState { pool, storage };
|
||||
let state = AppState {
|
||||
pool,
|
||||
storage: FileStorage::new()?,
|
||||
};
|
||||
|
||||
let router = app(state);
|
||||
let addr = (Ipv4Addr::UNSPECIFIED, 3000);
|
||||
@ -87,7 +77,8 @@ fn app(state: AppState) -> Router {
|
||||
use axum::{http::header, routing::get};
|
||||
use endpoints::{
|
||||
file, folder,
|
||||
permissions::{self, get_top_level_permitted_folders::get_top_level},
|
||||
permissions::{self, get_top_level::get_top_level},
|
||||
users,
|
||||
};
|
||||
use tower_http::ServiceBuilderExt as _;
|
||||
|
||||
@ -123,6 +114,14 @@ fn app(state: AppState) -> Router {
|
||||
"/permissions/get_top_level_permitted_folders",
|
||||
get(get_top_level),
|
||||
)
|
||||
.route(
|
||||
"/users",
|
||||
get(users::get::get)
|
||||
.post(users::create::create)
|
||||
.delete(users::delete::delete)
|
||||
.put(users::put::put),
|
||||
)
|
||||
.route("/users/search", get(users::search::search))
|
||||
.layer(middleware)
|
||||
.with_state(state)
|
||||
}
|
||||
|
Reference in New Issue
Block a user