mirror of
https://github.com/flibusta-apps/users_settings_server.git
synced 2025-12-06 06:35:39 +01:00
Move to sqlx
This commit is contained in:
@@ -1,2 +0,0 @@
|
|||||||
[alias]
|
|
||||||
prisma = "run -p prisma-cli --"
|
|
||||||
22
.sqlx/query-26c34e5d30ff234865930fd193ab0925cfd59304709dd089135c1918ad5fc060.json
generated
Normal file
22
.sqlx/query-26c34e5d30ff234865930fd193ab0925cfd59304709dd089135c1918ad5fc060.json
generated
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "SELECT sended FROM chat_donate_notifications WHERE chat_id = $1",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "sended",
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "26c34e5d30ff234865930fd193ab0925cfd59304709dd089135c1918ad5fc060"
|
||||||
|
}
|
||||||
15
.sqlx/query-35e8006d09cf49b6a09dd13da0e76fdede08fad31248937d1fff4fc26e07acc0.json
generated
Normal file
15
.sqlx/query-35e8006d09cf49b6a09dd13da0e76fdede08fad31248937d1fff4fc26e07acc0.json
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n INSERT INTO users_languages (\"user\", language)\n SELECT $1, id\n FROM languages\n WHERE code = ANY($2)\n ON CONFLICT DO NOTHING\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int4",
|
||||||
|
"TextArray"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "35e8006d09cf49b6a09dd13da0e76fdede08fad31248937d1fff4fc26e07acc0"
|
||||||
|
}
|
||||||
58
.sqlx/query-3c2ba9baa71516e4f4e3b594fcb940f6ffb66a91ff6368f6b640636d3f955590.json
generated
Normal file
58
.sqlx/query-3c2ba9baa71516e4f4e3b594fcb940f6ffb66a91ff6368f6b640636d3f955590.json
generated
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n SELECT\n user_settings.id,\n user_settings.user_id,\n user_settings.last_name,\n user_settings.first_name,\n user_settings.username,\n user_settings.source,\n ARRAY_AGG((\n languages.id,\n languages.label,\n languages.code\n )) AS \"allowed_langs: Vec<UserLanguage>\"\n FROM user_settings\n LEFT JOIN users_languages ON user_settings.id = users_languages.user\n LEFT JOIN languages ON users_languages.language = languages.id\n WHERE user_settings.id = $1\n GROUP BY user_settings.id\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "user_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "last_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 3,
|
||||||
|
"name": "first_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
|
"name": "username",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 5,
|
||||||
|
"name": "source",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 6,
|
||||||
|
"name": "allowed_langs: Vec<UserLanguage>",
|
||||||
|
"type_info": "RecordArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int4"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "3c2ba9baa71516e4f4e3b594fcb940f6ffb66a91ff6368f6b640636d3f955590"
|
||||||
|
}
|
||||||
34
.sqlx/query-3f6c9d18ee09cfe5597a6f3d08fc77cb20c5e414388ebb70d100648d29a975c6.json
generated
Normal file
34
.sqlx/query-3f6c9d18ee09cfe5597a6f3d08fc77cb20c5e414388ebb70d100648d29a975c6.json
generated
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "SELECT id, label, code FROM languages WHERE code = $1",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "label",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "code",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Text"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "3f6c9d18ee09cfe5597a6f3d08fc77cb20c5e414388ebb70d100648d29a975c6"
|
||||||
|
}
|
||||||
52
.sqlx/query-468d4e044e88a95969f77dc74c6e1c17907571e5119bf240e4facefef508b510.json
generated
Normal file
52
.sqlx/query-468d4e044e88a95969f77dc74c6e1c17907571e5119bf240e4facefef508b510.json
generated
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n SELECT id, user_id, last_name, first_name, username, source\n FROM user_settings\n WHERE user_id = $1\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "user_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "last_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 3,
|
||||||
|
"name": "first_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
|
"name": "username",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 5,
|
||||||
|
"name": "source",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "468d4e044e88a95969f77dc74c6e1c17907571e5119bf240e4facefef508b510"
|
||||||
|
}
|
||||||
56
.sqlx/query-51d29079e7c27eb0a59d309255e37fd595887cc3faf60a93533e9eadadcab1da.json
generated
Normal file
56
.sqlx/query-51d29079e7c27eb0a59d309255e37fd595887cc3faf60a93533e9eadadcab1da.json
generated
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n INSERT INTO user_settings (user_id, last_name, first_name, username, source)\n VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (user_id) DO UPDATE\n SET last_name = $2, first_name = $3, username = $4, source = $5\n RETURNING id, user_id, last_name, first_name, username, source\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "user_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "last_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 3,
|
||||||
|
"name": "first_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
|
"name": "username",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 5,
|
||||||
|
"name": "source",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8",
|
||||||
|
"Varchar",
|
||||||
|
"Varchar",
|
||||||
|
"Varchar",
|
||||||
|
"Varchar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "51d29079e7c27eb0a59d309255e37fd595887cc3faf60a93533e9eadadcab1da"
|
||||||
|
}
|
||||||
58
.sqlx/query-544c1f2457ed9c7e971901c3dd35535b3772caa29e9c2c48a60a669544eb3a98.json
generated
Normal file
58
.sqlx/query-544c1f2457ed9c7e971901c3dd35535b3772caa29e9c2c48a60a669544eb3a98.json
generated
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n SELECT\n user_settings.id,\n user_settings.user_id,\n user_settings.last_name,\n user_settings.first_name,\n user_settings.username,\n user_settings.source,\n ARRAY_AGG((\n languages.id,\n languages.label,\n languages.code\n )) AS \"allowed_langs: Vec<UserLanguage>\"\n FROM user_settings\n LEFT JOIN users_languages ON user_settings.id = users_languages.user\n LEFT JOIN languages ON users_languages.language = languages.id\n WHERE user_settings.user_id = $1\n GROUP BY user_settings.id\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "user_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "last_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 3,
|
||||||
|
"name": "first_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
|
"name": "username",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 5,
|
||||||
|
"name": "source",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 6,
|
||||||
|
"name": "allowed_langs: Vec<UserLanguage>",
|
||||||
|
"type_info": "RecordArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "544c1f2457ed9c7e971901c3dd35535b3772caa29e9c2c48a60a669544eb3a98"
|
||||||
|
}
|
||||||
14
.sqlx/query-6bce140f0cdead4d9d2742dfdf6ddaf23bade20582e42eb37ca19f6c206fe2e6.json
generated
Normal file
14
.sqlx/query-6bce140f0cdead4d9d2742dfdf6ddaf23bade20582e42eb37ca19f6c206fe2e6.json
generated
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n INSERT INTO user_activity (\"user\", updated)\n VALUES ($1, NOW())\n ON CONFLICT (\"user\") DO UPDATE\n SET updated = NOW()\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int4"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "6bce140f0cdead4d9d2742dfdf6ddaf23bade20582e42eb37ca19f6c206fe2e6"
|
||||||
|
}
|
||||||
32
.sqlx/query-71173e6712c4eb17baa451f7c002a3fd1649727e77a6252fc1465747f6c97503.json
generated
Normal file
32
.sqlx/query-71173e6712c4eb17baa451f7c002a3fd1649727e77a6252fc1465747f6c97503.json
generated
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "SELECT id, label, code FROM languages",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "label",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "code",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": []
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "71173e6712c4eb17baa451f7c002a3fd1649727e77a6252fc1465747f6c97503"
|
||||||
|
}
|
||||||
23
.sqlx/query-bb8185bf6377bb163d439876e8741c3eff2e982469693108e127d27cb0202172.json
generated
Normal file
23
.sqlx/query-bb8185bf6377bb163d439876e8741c3eff2e982469693108e127d27cb0202172.json
generated
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "INSERT INTO chat_donate_notifications (chat_id, sended) VALUES ($1, $2)\n ON CONFLICT (chat_id) DO UPDATE SET sended = EXCLUDED.sended\n RETURNING sended",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "sended",
|
||||||
|
"type_info": "Timestamp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8",
|
||||||
|
"Timestamp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "bb8185bf6377bb163d439876e8741c3eff2e982469693108e127d27cb0202172"
|
||||||
|
}
|
||||||
15
.sqlx/query-c0ff30d71783bdbdd69900e75d46a0b4ab41da1679ce9849525415bd4b697974.json
generated
Normal file
15
.sqlx/query-c0ff30d71783bdbdd69900e75d46a0b4ab41da1679ce9849525415bd4b697974.json
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n DELETE FROM users_languages\n WHERE \"user\" = $1 AND language NOT IN (\n SELECT id FROM languages WHERE code = ANY($2)\n )\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int4",
|
||||||
|
"TextArray"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "c0ff30d71783bdbdd69900e75d46a0b4ab41da1679ce9849525415bd4b697974"
|
||||||
|
}
|
||||||
59
.sqlx/query-d4af7cbdc7cd903023f022779f5e41d7dc772c484006a0f1a51889b31dc1d1a0.json
generated
Normal file
59
.sqlx/query-d4af7cbdc7cd903023f022779f5e41d7dc772c484006a0f1a51889b31dc1d1a0.json
generated
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n SELECT\n user_settings.id,\n user_settings.user_id,\n user_settings.last_name,\n user_settings.first_name,\n user_settings.username,\n user_settings.source,\n ARRAY_AGG((\n languages.id,\n languages.label,\n languages.code\n )) AS \"allowed_langs: Vec<UserLanguage>\"\n FROM user_settings\n LEFT JOIN users_languages ON user_settings.id = users_languages.user\n LEFT JOIN languages ON users_languages.language = languages.id\n GROUP BY user_settings.id\n ORDER BY user_settings.id ASC\n OFFSET $1\n LIMIT $2\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "user_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "last_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 3,
|
||||||
|
"name": "first_name",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
|
"name": "username",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 5,
|
||||||
|
"name": "source",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 6,
|
||||||
|
"name": "allowed_langs: Vec<UserLanguage>",
|
||||||
|
"type_info": "RecordArray"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8",
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "d4af7cbdc7cd903023f022779f5e41d7dc772c484006a0f1a51889b31dc1d1a0"
|
||||||
|
}
|
||||||
3419
Cargo.lock
generated
3419
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
29
Cargo.toml
29
Cargo.toml
@@ -3,26 +3,21 @@ name = "users_settings_server"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
|
||||||
members = [
|
|
||||||
"prisma-cli"
|
|
||||||
]
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
once_cell = "1.20.1"
|
once_cell = "1.20.2"
|
||||||
|
|
||||||
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.11", default-features = false, features = ["postgresql"] }
|
serde = { version = "1.0.216", features = ["derive"] }
|
||||||
serde = { version = "1.0.210", features = ["derive"] }
|
|
||||||
|
|
||||||
tokio = { version = "1.40.0", features = ["full"] }
|
tokio = { version = "1.42.0", features = ["full"] }
|
||||||
axum = { version = "0.7.7", features = ["json"] }
|
axum = { version = "0.7.9", features = ["json"] }
|
||||||
axum-prometheus = "0.7.0"
|
axum-prometheus = "0.7.0"
|
||||||
chrono = "0.4.38"
|
chrono = { version = "0.4.39", features = ["serde"] }
|
||||||
sentry = { version = "0.34.0", features = ["debug-images"] }
|
sentry = { version = "0.35.0", features = ["debug-images"] }
|
||||||
|
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.41"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"]}
|
tracing-subscriber = { version = "0.3.19", features = ["env-filter"]}
|
||||||
sentry-tracing = "0.34.0"
|
sentry-tracing = "0.35.0"
|
||||||
tower-http = { version = "0.6.1", features = ["trace"] }
|
tower-http = { version = "0.6.2", features = ["trace"] }
|
||||||
|
|
||||||
|
sqlx = { version = "0.8.2", features = ["runtime-tokio", "postgres", "macros", "chrono"] }
|
||||||
|
|||||||
3
prisma-cli/.gitignore
vendored
3
prisma-cli/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
# Keep environment variables out of version control
|
|
||||||
.env
|
|
||||||
3195
prisma-cli/Cargo.lock
generated
3195
prisma-cli/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "prisma-cli"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust", tag = "0.6.11", default-features = false, features = ["postgresql"] }
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
prisma_client_rust_cli::run();
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
generator client {
|
|
||||||
provider = "cargo prisma"
|
|
||||||
output = "../src/prisma.rs"
|
|
||||||
}
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgresql"
|
|
||||||
url = env("DATABASE_URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserSettings {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
user_id BigInt @unique
|
|
||||||
last_name String @db.VarChar(64)
|
|
||||||
first_name String @db.VarChar(64)
|
|
||||||
username String @db.VarChar(32)
|
|
||||||
source String @db.VarChar(32)
|
|
||||||
user_activity UserActivity?
|
|
||||||
languages LanguageToUser[]
|
|
||||||
|
|
||||||
@@map("user_settings")
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChatDonateNotifications {
|
|
||||||
id BigInt @id @default(autoincrement())
|
|
||||||
chat_id BigInt @unique
|
|
||||||
sended DateTime @db.Timestamp(6)
|
|
||||||
|
|
||||||
@@map("chat_donate_notifications")
|
|
||||||
}
|
|
||||||
|
|
||||||
model Language {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
label String @db.VarChar(16)
|
|
||||||
code String @unique @db.VarChar(4)
|
|
||||||
users LanguageToUser[]
|
|
||||||
|
|
||||||
@@map("languages")
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserActivity {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
user_id Int @unique @map("user")
|
|
||||||
updated DateTime @db.Timestamp(6)
|
|
||||||
user UserSettings @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_user_activity_user_settings_id_user")
|
|
||||||
|
|
||||||
@@map("user_activity")
|
|
||||||
}
|
|
||||||
|
|
||||||
model LanguageToUser {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
language_id Int @map("language")
|
|
||||||
user_id Int @map("user")
|
|
||||||
language Language @relation(fields: [language_id], references: [id], onDelete: Cascade, map: "fk_users_languages_languages_language_id")
|
|
||||||
user UserSettings @relation(fields: [user_id], references: [id], onDelete: Cascade, map: "fk_users_languages_user_settings_user_id")
|
|
||||||
|
|
||||||
@@map("users_languages")
|
|
||||||
}
|
|
||||||
15
src/db.rs
15
src/db.rs
@@ -1,8 +1,10 @@
|
|||||||
use crate::{config::CONFIG, prisma::PrismaClient};
|
use crate::config::CONFIG;
|
||||||
|
|
||||||
pub async fn get_prisma_client() -> PrismaClient {
|
use sqlx::{postgres::PgPoolOptions, PgPool};
|
||||||
|
|
||||||
|
pub async fn get_prisma_client() -> PgPool {
|
||||||
let database_url: String = format!(
|
let database_url: String = format!(
|
||||||
"postgresql://{}:{}@{}:{}/{}?connection_limit=10&pool_timeout=300",
|
"postgresql://{}:{}@{}:{}/{}",
|
||||||
CONFIG.postgres_user,
|
CONFIG.postgres_user,
|
||||||
CONFIG.postgres_password,
|
CONFIG.postgres_password,
|
||||||
CONFIG.postgres_host,
|
CONFIG.postgres_host,
|
||||||
@@ -10,9 +12,10 @@ pub async fn get_prisma_client() -> PrismaClient {
|
|||||||
CONFIG.postgres_db
|
CONFIG.postgres_db
|
||||||
);
|
);
|
||||||
|
|
||||||
PrismaClient::_builder()
|
PgPoolOptions::new()
|
||||||
.with_url(database_url)
|
.max_connections(10)
|
||||||
.build()
|
.acquire_timeout(std::time::Duration::from_secs(300))
|
||||||
|
.connect(&database_url)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod prisma;
|
|
||||||
pub mod views;
|
pub mod views;
|
||||||
|
|
||||||
use sentry::{integrations::debug_images::DebugImagesIntegration, types::Dsn, ClientOptions};
|
use sentry::{integrations::debug_images::DebugImagesIntegration, types::Dsn, ClientOptions};
|
||||||
|
|||||||
5213
src/prisma.rs
5213
src/prisma.rs
File diff suppressed because one or more lines are too long
@@ -8,10 +8,13 @@ use axum::{
|
|||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::prisma::chat_donate_notifications;
|
|
||||||
|
|
||||||
use super::Database;
|
use super::Database;
|
||||||
|
|
||||||
|
#[derive(sqlx::FromRow)]
|
||||||
|
struct ChatDonateNotification {
|
||||||
|
pub sended: chrono::NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct IsNeedSendQuery {
|
struct IsNeedSendQuery {
|
||||||
is_private: bool,
|
is_private: bool,
|
||||||
@@ -25,12 +28,14 @@ async fn is_need_send(
|
|||||||
const NOTIFICATION_DELTA_DAYS_PRIVATE: i64 = 60;
|
const NOTIFICATION_DELTA_DAYS_PRIVATE: i64 = 60;
|
||||||
const NOTIFICATION_DELTA_DAYS: i64 = 7;
|
const NOTIFICATION_DELTA_DAYS: i64 = 7;
|
||||||
|
|
||||||
let notification = db
|
let notification = sqlx::query_as!(
|
||||||
.chat_donate_notifications()
|
ChatDonateNotification,
|
||||||
.find_unique(chat_donate_notifications::chat_id::equals(chat_id))
|
r#"SELECT sended FROM chat_donate_notifications WHERE chat_id = $1"#,
|
||||||
.exec()
|
chat_id
|
||||||
.await
|
)
|
||||||
.unwrap();
|
.fetch_optional(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let delta_days = if query.is_private {
|
let delta_days = if query.is_private {
|
||||||
NOTIFICATION_DELTA_DAYS_PRIVATE
|
NOTIFICATION_DELTA_DAYS_PRIVATE
|
||||||
@@ -40,7 +45,7 @@ async fn is_need_send(
|
|||||||
|
|
||||||
match notification {
|
match notification {
|
||||||
Some(notification) => {
|
Some(notification) => {
|
||||||
let result = notification.sended.naive_local() + Duration::days(delta_days)
|
let result = notification.sended + Duration::days(delta_days)
|
||||||
<= chrono::offset::Local::now().naive_local();
|
<= chrono::offset::Local::now().naive_local();
|
||||||
Json(result).into_response()
|
Json(result).into_response()
|
||||||
}
|
}
|
||||||
@@ -49,17 +54,17 @@ async fn is_need_send(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn mark_sent(Path(chat_id): Path<i64>, db: Database) -> impl IntoResponse {
|
async fn mark_sent(Path(chat_id): Path<i64>, db: Database) -> impl IntoResponse {
|
||||||
let _ = db
|
sqlx::query_as!(
|
||||||
.chat_donate_notifications()
|
ChatDonateNotification,
|
||||||
.upsert(
|
r#"INSERT INTO chat_donate_notifications (chat_id, sended) VALUES ($1, $2)
|
||||||
chat_donate_notifications::chat_id::equals(chat_id),
|
ON CONFLICT (chat_id) DO UPDATE SET sended = EXCLUDED.sended
|
||||||
chat_donate_notifications::create(chat_id, chrono::offset::Local::now().into(), vec![]),
|
RETURNING sended"#,
|
||||||
vec![chat_donate_notifications::sended::set(
|
chat_id,
|
||||||
chrono::offset::Local::now().into(),
|
chrono::offset::Local::now().naive_local()
|
||||||
)],
|
)
|
||||||
)
|
.fetch_one(&db.0)
|
||||||
.exec()
|
.await
|
||||||
.await;
|
.unwrap();
|
||||||
|
|
||||||
StatusCode::OK
|
StatusCode::OK
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,49 +2,35 @@ use axum::{extract::Path, http::StatusCode, response::IntoResponse, routing::get
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::Database;
|
use super::Database;
|
||||||
use crate::prisma::language;
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(sqlx::FromRow, Serialize)]
|
||||||
pub struct LanguageDetail {
|
pub struct LanguageDetail {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub code: String,
|
pub code: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<language::Data> for LanguageDetail {
|
|
||||||
fn from(value: language::Data) -> Self {
|
|
||||||
let language::Data {
|
|
||||||
id, label, code, ..
|
|
||||||
} = value;
|
|
||||||
|
|
||||||
Self { id, label, code }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_languages(db: Database) -> impl IntoResponse {
|
async fn get_languages(db: Database) -> impl IntoResponse {
|
||||||
let languages: Vec<LanguageDetail> = db
|
let languages = sqlx::query_as!(LanguageDetail, "SELECT id, label, code FROM languages")
|
||||||
.language()
|
.fetch_all(&db.0)
|
||||||
.find_many(vec![])
|
|
||||||
.exec()
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.into())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Json(languages).into_response()
|
Json(languages).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_language_by_code(Path(code): Path<String>, db: Database) -> impl IntoResponse {
|
async fn get_language_by_code(Path(code): Path<String>, db: Database) -> impl IntoResponse {
|
||||||
let language = db
|
let language = sqlx::query_as!(
|
||||||
.language()
|
LanguageDetail,
|
||||||
.find_unique(language::code::equals(code))
|
r#"SELECT id, label, code FROM languages WHERE code = $1"#,
|
||||||
.exec()
|
code
|
||||||
.await
|
)
|
||||||
.unwrap();
|
.fetch_optional(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
match language {
|
match language {
|
||||||
Some(v) => Json::<LanguageDetail>(v.into()).into_response(),
|
Some(v) => Json(v).into_response(),
|
||||||
None => StatusCode::NOT_FOUND.into_response(),
|
None => StatusCode::NOT_FOUND.into_response(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,19 @@ use axum::{
|
|||||||
Extension, Router,
|
Extension, Router,
|
||||||
};
|
};
|
||||||
use axum_prometheus::PrometheusMetricLayer;
|
use axum_prometheus::PrometheusMetricLayer;
|
||||||
|
use sqlx::PgPool;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tower_http::trace::{self, TraceLayer};
|
use tower_http::trace::{self, TraceLayer};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
|
|
||||||
use crate::{config::CONFIG, db::get_prisma_client, prisma::PrismaClient};
|
use crate::{config::CONFIG, db::get_prisma_client};
|
||||||
|
|
||||||
pub mod donate_notifications;
|
pub mod donate_notifications;
|
||||||
pub mod languages;
|
pub mod languages;
|
||||||
pub mod pagination;
|
pub mod pagination;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
|
||||||
pub type Database = Extension<Arc<PrismaClient>>;
|
pub type Database = Extension<PgPool>;
|
||||||
|
|
||||||
async fn auth(req: Request<axum::body::Body>, next: Next) -> Result<Response, StatusCode> {
|
async fn auth(req: Request<axum::body::Body>, next: Next) -> Result<Response, StatusCode> {
|
||||||
let auth_header = req
|
let auth_header = req
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
pub mod serializers;
|
pub mod serializers;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
use crate::prisma::{language_to_user, user_activity, user_settings};
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query},
|
extract::{Path, Query},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@@ -9,9 +8,10 @@ use axum::{
|
|||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
|
use serializers::SimpleUser;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
serializers::{CreateOrUpdateUserData, UserDetail},
|
serializers::{CreateOrUpdateUserData, UserDetail, UserLanguage},
|
||||||
utils::update_languages,
|
utils::update_languages,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -23,112 +23,165 @@ use super::{
|
|||||||
async fn get_users(pagination: Query<Pagination>, db: Database) -> impl IntoResponse {
|
async fn get_users(pagination: Query<Pagination>, db: Database) -> impl IntoResponse {
|
||||||
let pagination: Pagination = pagination.0;
|
let pagination: Pagination = pagination.0;
|
||||||
|
|
||||||
let users_count = db.user_settings().count(vec![]).exec().await.unwrap();
|
let users_count = sqlx::query_scalar(r#"SELECT COUNT(*) FROM user_settings"#)
|
||||||
|
.fetch_one(&db.0)
|
||||||
let users: Vec<UserDetail> = db
|
|
||||||
.user_settings()
|
|
||||||
.find_many(vec![])
|
|
||||||
.with(user_settings::languages::fetch(vec![]).with(language_to_user::language::fetch()))
|
|
||||||
.order_by(user_settings::id::order(prisma_client_rust::Direction::Asc))
|
|
||||||
.skip(pagination.skip())
|
|
||||||
.take(pagination.take())
|
|
||||||
.exec()
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.into())
|
let users = sqlx::query_as!(
|
||||||
.collect();
|
UserDetail,
|
||||||
|
r#"
|
||||||
|
SELECT
|
||||||
|
user_settings.id,
|
||||||
|
user_settings.user_id,
|
||||||
|
user_settings.last_name,
|
||||||
|
user_settings.first_name,
|
||||||
|
user_settings.username,
|
||||||
|
user_settings.source,
|
||||||
|
ARRAY_AGG((
|
||||||
|
languages.id,
|
||||||
|
languages.label,
|
||||||
|
languages.code
|
||||||
|
)) AS "allowed_langs: Vec<UserLanguage>"
|
||||||
|
FROM user_settings
|
||||||
|
LEFT JOIN users_languages ON user_settings.id = users_languages.user
|
||||||
|
LEFT JOIN languages ON users_languages.language = languages.id
|
||||||
|
GROUP BY user_settings.id
|
||||||
|
ORDER BY user_settings.id ASC
|
||||||
|
OFFSET $1
|
||||||
|
LIMIT $2
|
||||||
|
"#,
|
||||||
|
pagination.skip(),
|
||||||
|
pagination.take(),
|
||||||
|
)
|
||||||
|
.fetch_all(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Json(Page::create(users, users_count, pagination)).into_response()
|
Json(Page::create(users, users_count, pagination)).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_user(Path(user_id): Path<i64>, db: Database) -> impl IntoResponse {
|
async fn get_user(Path(user_id): Path<i64>, db: Database) -> impl IntoResponse {
|
||||||
let user = db
|
let user = sqlx::query_as!(
|
||||||
.user_settings()
|
UserDetail,
|
||||||
.find_unique(user_settings::user_id::equals(user_id))
|
r#"
|
||||||
.with(user_settings::languages::fetch(vec![]).with(language_to_user::language::fetch()))
|
SELECT
|
||||||
.exec()
|
user_settings.id,
|
||||||
.await
|
user_settings.user_id,
|
||||||
.unwrap();
|
user_settings.last_name,
|
||||||
|
user_settings.first_name,
|
||||||
|
user_settings.username,
|
||||||
|
user_settings.source,
|
||||||
|
ARRAY_AGG((
|
||||||
|
languages.id,
|
||||||
|
languages.label,
|
||||||
|
languages.code
|
||||||
|
)) AS "allowed_langs: Vec<UserLanguage>"
|
||||||
|
FROM user_settings
|
||||||
|
LEFT JOIN users_languages ON user_settings.id = users_languages.user
|
||||||
|
LEFT JOIN languages ON users_languages.language = languages.id
|
||||||
|
WHERE user_settings.user_id = $1
|
||||||
|
GROUP BY user_settings.id
|
||||||
|
"#,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
|
.fetch_optional(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if user.is_none() {
|
if user.is_none() {
|
||||||
return StatusCode::NO_CONTENT.into_response();
|
return StatusCode::NO_CONTENT.into_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::<UserDetail>(user.unwrap().into()).into_response()
|
Json::<UserDetail>(user.unwrap()).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_or_update_user(
|
async fn create_or_update_user(
|
||||||
db: Database,
|
db: Database,
|
||||||
Json(data): Json<CreateOrUpdateUserData>,
|
Json(data): Json<CreateOrUpdateUserData>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let user = db
|
let user = sqlx::query_as!(
|
||||||
.user_settings()
|
SimpleUser,
|
||||||
.upsert(
|
r#"
|
||||||
user_settings::user_id::equals(data.user_id),
|
INSERT INTO user_settings (user_id, last_name, first_name, username, source)
|
||||||
user_settings::create(
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
data.user_id,
|
ON CONFLICT (user_id) DO UPDATE
|
||||||
data.last_name.clone(),
|
SET last_name = $2, first_name = $3, username = $4, source = $5
|
||||||
data.first_name.clone(),
|
RETURNING id, user_id, last_name, first_name, username, source
|
||||||
data.username.clone(),
|
"#,
|
||||||
data.source.clone(),
|
data.user_id,
|
||||||
vec![],
|
data.last_name,
|
||||||
),
|
data.first_name,
|
||||||
vec![
|
data.username,
|
||||||
user_settings::last_name::set(data.last_name),
|
data.source,
|
||||||
user_settings::first_name::set(data.first_name),
|
)
|
||||||
user_settings::username::set(data.username),
|
.fetch_one(&db.0)
|
||||||
user_settings::source::set(data.source),
|
.await
|
||||||
],
|
.unwrap();
|
||||||
)
|
|
||||||
.with(user_settings::languages::fetch(vec![]).with(language_to_user::language::fetch()))
|
|
||||||
.exec()
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let user_id = user.id;
|
update_languages(user.id, data.allowed_langs, db.clone()).await;
|
||||||
update_languages(user, data.allowed_langs, db.clone()).await;
|
|
||||||
|
|
||||||
let user = db
|
let user = sqlx::query_as!(
|
||||||
.user_settings()
|
UserDetail,
|
||||||
.find_unique(user_settings::id::equals(user_id))
|
r#"
|
||||||
.with(user_settings::languages::fetch(vec![]).with(language_to_user::language::fetch()))
|
SELECT
|
||||||
.exec()
|
user_settings.id,
|
||||||
.await
|
user_settings.user_id,
|
||||||
.unwrap()
|
user_settings.last_name,
|
||||||
.unwrap();
|
user_settings.first_name,
|
||||||
|
user_settings.username,
|
||||||
|
user_settings.source,
|
||||||
|
ARRAY_AGG((
|
||||||
|
languages.id,
|
||||||
|
languages.label,
|
||||||
|
languages.code
|
||||||
|
)) AS "allowed_langs: Vec<UserLanguage>"
|
||||||
|
FROM user_settings
|
||||||
|
LEFT JOIN users_languages ON user_settings.id = users_languages.user
|
||||||
|
LEFT JOIN languages ON users_languages.language = languages.id
|
||||||
|
WHERE user_settings.id = $1
|
||||||
|
GROUP BY user_settings.id
|
||||||
|
"#,
|
||||||
|
user.id,
|
||||||
|
)
|
||||||
|
.fetch_one(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Json::<UserDetail>(user.into()).into_response()
|
Json::<UserDetail>(user).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_activity(Path(user_id): Path<i64>, db: Database) -> impl IntoResponse {
|
async fn update_activity(Path(user_id): Path<i64>, db: Database) -> impl IntoResponse {
|
||||||
let user = db
|
let user = sqlx::query_as!(
|
||||||
.user_settings()
|
SimpleUser,
|
||||||
.find_unique(user_settings::user_id::equals(user_id))
|
r#"
|
||||||
.exec()
|
SELECT id, user_id, last_name, first_name, username, source
|
||||||
.await
|
FROM user_settings
|
||||||
.unwrap();
|
WHERE user_id = $1
|
||||||
|
"#,
|
||||||
|
user_id,
|
||||||
|
)
|
||||||
|
.fetch_optional(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let user = match user {
|
let user = match user {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return StatusCode::NOT_FOUND.into_response(),
|
None => return StatusCode::NOT_FOUND.into_response(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = db
|
sqlx::query!(
|
||||||
.user_activity()
|
r#"
|
||||||
.upsert(
|
INSERT INTO user_activity ("user", updated)
|
||||||
user_activity::user_id::equals(user.id),
|
VALUES ($1, NOW())
|
||||||
user_activity::create(
|
ON CONFLICT ("user") DO UPDATE
|
||||||
chrono::offset::Local::now().into(),
|
SET updated = NOW()
|
||||||
user_settings::id::equals(user.id),
|
"#,
|
||||||
vec![],
|
user.id,
|
||||||
),
|
)
|
||||||
vec![user_activity::updated::set(
|
.execute(&db.0)
|
||||||
chrono::offset::Local::now().into(),
|
.await
|
||||||
)],
|
.unwrap();
|
||||||
)
|
|
||||||
.exec()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
StatusCode::OK.into_response()
|
StatusCode::OK.into_response()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::prisma::{language, user_settings};
|
#[derive(sqlx::FromRow, sqlx::Type, Serialize)]
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
pub struct UserLanguage {
|
pub struct UserLanguage {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub code: String,
|
pub code: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<language::Data> for UserLanguage {
|
#[derive(sqlx::FromRow, Serialize)]
|
||||||
fn from(value: language::Data) -> Self {
|
pub struct SimpleUser {
|
||||||
Self {
|
pub id: i32,
|
||||||
id: value.id,
|
pub user_id: i64,
|
||||||
label: value.label,
|
pub last_name: String,
|
||||||
code: value.code,
|
pub first_name: String,
|
||||||
}
|
pub username: String,
|
||||||
}
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(sqlx::FromRow, Serialize)]
|
||||||
pub struct UserDetail {
|
pub struct UserDetail {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub user_id: i64,
|
pub user_id: i64,
|
||||||
@@ -27,29 +25,8 @@ pub struct UserDetail {
|
|||||||
pub first_name: String,
|
pub first_name: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub source: String,
|
pub source: String,
|
||||||
pub allowed_langs: Vec<UserLanguage>,
|
#[serde(default)]
|
||||||
}
|
pub allowed_langs: Option<Vec<UserLanguage>>,
|
||||||
|
|
||||||
impl From<user_settings::Data> for UserDetail {
|
|
||||||
fn from(value: user_settings::Data) -> Self {
|
|
||||||
let allowed_langs: Vec<UserLanguage> = value
|
|
||||||
.languages
|
|
||||||
.unwrap()
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| *item.language.unwrap())
|
|
||||||
.map(|item| item.into())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
id: value.id,
|
|
||||||
user_id: value.user_id,
|
|
||||||
last_name: value.last_name,
|
|
||||||
first_name: value.first_name,
|
|
||||||
username: value.username,
|
|
||||||
source: value.source,
|
|
||||||
allowed_langs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|||||||
@@ -1,68 +1,32 @@
|
|||||||
use std::collections::HashMap;
|
use crate::views::Database;
|
||||||
|
|
||||||
use crate::{
|
pub async fn update_languages(user: i32, new_langs: Vec<String>, db: Database) {
|
||||||
prisma::{language, language_to_user, user_settings},
|
sqlx::query!(
|
||||||
views::Database,
|
r#"
|
||||||
};
|
DELETE FROM users_languages
|
||||||
|
WHERE "user" = $1 AND language NOT IN (
|
||||||
|
SELECT id FROM languages WHERE code = ANY($2)
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
user,
|
||||||
|
&new_langs
|
||||||
|
)
|
||||||
|
.execute(&db.0)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
pub async fn update_languages(user: user_settings::Data, new_langs: Vec<String>, db: Database) {
|
sqlx::query!(
|
||||||
// Delete
|
r#"
|
||||||
{
|
INSERT INTO users_languages ("user", language)
|
||||||
let need_delete: Vec<_> = user
|
SELECT $1, id
|
||||||
.languages()
|
FROM languages
|
||||||
.unwrap()
|
WHERE code = ANY($2)
|
||||||
.iter()
|
ON CONFLICT DO NOTHING
|
||||||
.map(|item| {
|
"#,
|
||||||
let language::Data { code, .. } = *item.clone().language.unwrap();
|
user,
|
||||||
(item.id, code)
|
&new_langs
|
||||||
})
|
)
|
||||||
.filter(|(_, code)| !new_langs.contains(code))
|
.execute(&db.0)
|
||||||
.map(|(id, _)| id)
|
.await
|
||||||
.collect();
|
.unwrap();
|
||||||
|
|
||||||
let _ = db
|
|
||||||
.language_to_user()
|
|
||||||
.delete_many(vec![language_to_user::id::in_vec(need_delete)])
|
|
||||||
.exec()
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create
|
|
||||||
{
|
|
||||||
let languages: HashMap<_, _> = db
|
|
||||||
.language()
|
|
||||||
.find_many(vec![])
|
|
||||||
.exec()
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.into_iter()
|
|
||||||
.map(|l| (l.code, l.id))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let current_langs: Vec<_> = user
|
|
||||||
.languages()
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
.map(|item| item.clone().language.unwrap().code)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let need_create: Vec<i32> = new_langs
|
|
||||||
.into_iter()
|
|
||||||
.filter(|code| !current_langs.contains(code))
|
|
||||||
.map(|code| *languages.get(&code).unwrap())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let _ = db
|
|
||||||
.language_to_user()
|
|
||||||
.create_many(
|
|
||||||
need_create
|
|
||||||
.iter()
|
|
||||||
.map(|language_id| {
|
|
||||||
language_to_user::create_unchecked(*language_id, user.id, vec![])
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.exec()
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user