feat(email): add email verification
This commit is contained in:
parent
1192a58342
commit
18e74dd57e
27 changed files with 1107 additions and 18 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
27
.sqlx/query-02d51edf65163f311dfa215da26acb2bc8c02735e2f79782c612d5fe0cf01042.json
generated
Normal file
27
.sqlx/query-02d51edf65163f311dfa215da26acb2bc8c02735e2f79782c612d5fe0cf01042.json
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO users (\n pid,\n username,\n password,\n birthdate,\n timezone,\n email,\n country,\n language,\n marketing_allowed,\n off_device_allowed,\n region,\n gender,\n mii_data,\n verification_code\n ) VALUES (\n $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Date",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Bool",
|
||||
"Int4",
|
||||
"Bpchar",
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "02d51edf65163f311dfa215da26acb2bc8c02735e2f79782c612d5fe0cf01042"
|
||||
}
|
||||
22
.sqlx/query-08c4a5721982ecd267ebc515b866c61aaef9395170430a58dcd7ac78f8cc75b2.json
generated
Normal file
22
.sqlx/query-08c4a5721982ecd267ebc515b866c61aaef9395170430a58dcd7ac78f8cc75b2.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM users WHERE username = $1 ) as exists",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "08c4a5721982ecd267ebc515b866c61aaef9395170430a58dcd7ac78f8cc75b2"
|
||||
}
|
||||
15
.sqlx/query-248fc3dbfadb793f1f380486d9c1c95230d4d5a7ee3cb66d9382b7f0522c5e82.json
generated
Normal file
15
.sqlx/query-248fc3dbfadb793f1f380486d9c1c95230d4d5a7ee3cb66d9382b7f0522c5e82.json
generated
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE users SET email_verified_since = $1 WHERE pid = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Timestamp",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "248fc3dbfadb793f1f380486d9c1c95230d4d5a7ee3cb66d9382b7f0522c5e82"
|
||||
}
|
||||
20
.sqlx/query-3c9b1695f8ae49e4308c048de98c1c262351465b6f102e98912f67442a1f54d9.json
generated
Normal file
20
.sqlx/query-3c9b1695f8ae49e4308c048de98c1c262351465b6f102e98912f67442a1f54d9.json
generated
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT nextval('pid_counter') as pid",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "3c9b1695f8ae49e4308c048de98c1c262351465b6f102e98912f67442a1f54d9"
|
||||
}
|
||||
66
.sqlx/query-48710e0b87742cc3fef816b3c95604095f71324011e7093ec37af15da8c158f4.json
generated
Normal file
66
.sqlx/query-48710e0b87742cc3fef816b3c95604095f71324011e7093ec37af15da8c158f4.json
generated
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "select * from tokens where pid = $1 and token_id = $2 and random = $3",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token_id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "assigned_ip",
|
||||
"type_info": "Inet"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "random",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "token_type",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "creation_time",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "expires",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "title_id",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int8",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "48710e0b87742cc3fef816b3c95604095f71324011e7093ec37af15da8c158f4"
|
||||
}
|
||||
28
.sqlx/query-566221b869f293e6c721e2e8bbf3087943e5816a98cdce151302055c58bd1183.json
generated
Normal file
28
.sqlx/query-566221b869f293e6c721e2e8bbf3087943e5816a98cdce151302055c58bd1183.json
generated
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "select pid, username from users where username = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "566221b869f293e6c721e2e8bbf3087943e5816a98cdce151302055c58bd1183"
|
||||
}
|
||||
28
.sqlx/query-5bd26d4c9e701bde77ce598fea2ce0b98ea2c7de03e71ac704c3ba047162c0b2.json
generated
Normal file
28
.sqlx/query-5bd26d4c9e701bde77ce598fea2ce0b98ea2c7de03e71ac704c3ba047162c0b2.json
generated
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "select address, port from nex_servers where game_server_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "address",
|
||||
"type_info": "Inet"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "port",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "5bd26d4c9e701bde77ce598fea2ce0b98ea2c7de03e71ac704c3ba047162c0b2"
|
||||
}
|
||||
130
.sqlx/query-606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100.json
generated
Normal file
130
.sqlx/query-606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100.json
generated
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT * FROM users WHERE username = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "password",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "birthdate",
|
||||
"type_info": "Date"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "timezone",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email_verified_since",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "country",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "language",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "gender",
|
||||
"type_info": "Bpchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "marketing_allowed",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "off_device_allowed",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "region",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "mii_data",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "account_level",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "creation_date",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "updated",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "nex_password",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "verification_code",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100"
|
||||
}
|
||||
22
.sqlx/query-6c1df0b05553305ba847f571a5859bf11353f28c25e4f81268e9379b5b2cb375.json
generated
Normal file
22
.sqlx/query-6c1df0b05553305ba847f571a5859bf11353f28c25e4f81268e9379b5b2cb375.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "select nex_password from users where pid = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "nex_password",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "6c1df0b05553305ba847f571a5859bf11353f28c25e4f81268e9379b5b2cb375"
|
||||
}
|
||||
130
.sqlx/query-93960465bbf8f670891d49b95fc52257c0ef596eee2d9a0e6a7d0aad03de4421.json
generated
Normal file
130
.sqlx/query-93960465bbf8f670891d49b95fc52257c0ef596eee2d9a0e6a7d0aad03de4421.json
generated
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT * FROM users WHERE pid = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "password",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "birthdate",
|
||||
"type_info": "Date"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "timezone",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email_verified_since",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "country",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "language",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "gender",
|
||||
"type_info": "Bpchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "marketing_allowed",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "off_device_allowed",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "region",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "mii_data",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "account_level",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "creation_date",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "updated",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "nex_password",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "verification_code",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "93960465bbf8f670891d49b95fc52257c0ef596eee2d9a0e6a7d0aad03de4421"
|
||||
}
|
||||
66
.sqlx/query-9d3cee43a86cead9a6d078abc1266fc2a97ac6e25a9733d1d20faf555c67abe1.json
generated
Normal file
66
.sqlx/query-9d3cee43a86cead9a6d078abc1266fc2a97ac6e25a9733d1d20faf555c67abe1.json
generated
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "select * from tokens where pid = $1 and token_id = $2 and random =$3",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token_id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "assigned_ip",
|
||||
"type_info": "Inet"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "random",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "token_type",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "creation_time",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "expires",
|
||||
"type_info": "Timestamp"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "title_id",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int8",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "9d3cee43a86cead9a6d078abc1266fc2a97ac6e25a9733d1d20faf555c67abe1"
|
||||
}
|
||||
22
.sqlx/query-b16ba4b6c1b7d1c207e94515268c3bbd90d4bcf92d20203cba5afb2664f4bb8a.json
generated
Normal file
22
.sqlx/query-b16ba4b6c1b7d1c207e94515268c3bbd90d4bcf92d20203cba5afb2664f4bb8a.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT verification_code FROM users WHERE pid = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "verification_code",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "b16ba4b6c1b7d1c207e94515268c3bbd90d4bcf92d20203cba5afb2664f4bb8a"
|
||||
}
|
||||
22
.sqlx/query-c8d50662530cac49c4261fb321cd15f9e4bafdfca12d2130a873d44a88dd435b.json
generated
Normal file
22
.sqlx/query-c8d50662530cac49c4261fb321cd15f9e4bafdfca12d2130a873d44a88dd435b.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(select 1 from users where pid = $1)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "c8d50662530cac49c4261fb321cd15f9e4bafdfca12d2130a873d44a88dd435b"
|
||||
}
|
||||
30
.sqlx/query-e5a2f7f28c3d7b9524d3dce48a9e47d6180ff634ebf59f3a1efd92b797170ac2.json
generated
Normal file
30
.sqlx/query-e5a2f7f28c3d7b9524d3dce48a9e47d6180ff634ebf59f3a1efd92b797170ac2.json
generated
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "insert into tokens (token_type, pid, title_id)\n values ($1, $2, $3) returning token_id, random",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token_id",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "random",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int4",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e5a2f7f28c3d7b9524d3dce48a9e47d6180ff634ebf59f3a1efd92b797170ac2"
|
||||
}
|
||||
28
.sqlx/query-eafa97669e8ec04f1dc0a8e05d417f12ffeeb26a5eabca323abfed0e1d7bcbea.json
generated
Normal file
28
.sqlx/query-eafa97669e8ec04f1dc0a8e05d417f12ffeeb26a5eabca323abfed0e1d7bcbea.json
generated
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "select pid, username from users where pid = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "pid",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "eafa97669e8ec04f1dc0a8e05d417f12ffeeb26a5eabca323abfed0e1d7bcbea"
|
||||
}
|
||||
123
Cargo.lock
generated
123
Cargo.lock
generated
|
|
@ -20,6 +20,7 @@ dependencies = [
|
|||
"hmac",
|
||||
"juniper",
|
||||
"juniper_rocket",
|
||||
"lettre",
|
||||
"log",
|
||||
"md-5",
|
||||
"mii",
|
||||
|
|
@ -27,6 +28,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"prost",
|
||||
"quick-xml",
|
||||
"rand",
|
||||
"rocket",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -64,6 +66,18 @@ dependencies = [
|
|||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
|
@ -470,6 +484,16 @@ dependencies = [
|
|||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chumsky"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
"stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
|
|
@ -713,6 +737,22 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "email-encoding"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9298e6504d9b9e780ed3f7dfd43a61be8cd0e09eb07f7706a945b0072b6670b6"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "email_address"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
|
|
@ -1072,6 +1112,10 @@ name = "hashbrown"
|
|||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
|
|
@ -1144,6 +1188,17 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
|
|
@ -1639,6 +1694,31 @@ dependencies = [
|
|||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lettre"
|
||||
version = "0.11.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "759bc2b8eabb6a30b235d6f716f7f36479f4b38cbe65b8747aefee51f89e8437"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chumsky",
|
||||
"email-encoding",
|
||||
"email_address",
|
||||
"fastrand",
|
||||
"futures-util",
|
||||
"hostname",
|
||||
"httpdate",
|
||||
"idna",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"nom",
|
||||
"percent-encoding",
|
||||
"quoted_printable",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.170"
|
||||
|
|
@ -1861,6 +1941,15 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
|
@ -2256,6 +2345,15 @@ dependencies = [
|
|||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.37.2"
|
||||
|
|
@ -2275,6 +2373,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quoted_printable"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
|
|
@ -3029,6 +3133,19 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "state"
|
||||
version = "0.6.0"
|
||||
|
|
@ -3781,6 +3898,12 @@ dependencies = [
|
|||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.2.0"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ juniper_rocket = "0.9.0"
|
|||
|
||||
tonic = "0.12.3"
|
||||
prost = "0.13.4"
|
||||
lettre = "0.11.15"
|
||||
rand = "0.8.5"
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
BIN
res/.DS_Store
vendored
Normal file
BIN
res/.DS_Store
vendored
Normal file
Binary file not shown.
203
res/email/confirmationTemplate.html
Normal file
203
res/email/confirmationTemplate.html
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" lang="en">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
supported-color-schemes:light dark;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
body.email-body,
|
||||
table.centerer,
|
||||
table.wrapper {
|
||||
background-color: #FFFFFF !important;
|
||||
color: #000000 !important;
|
||||
}
|
||||
table.card {
|
||||
background-color: #B60000 !important;
|
||||
}
|
||||
span.shoutout {
|
||||
color: #FFB3B3 !important;
|
||||
}
|
||||
td.confirm-link {
|
||||
background-color: #FF4D4D !important;
|
||||
}
|
||||
td.confirm-code {
|
||||
background-color: #FFB3B3 !important;
|
||||
color: #660000 !important;
|
||||
}
|
||||
td.notice {
|
||||
color: #FF4D4D !important;
|
||||
}
|
||||
td.notice a {
|
||||
color: #B60000 !important;
|
||||
}
|
||||
img.logo {
|
||||
content: url("https://cdn.abmanagement.al/perditumgames.png") !important;
|
||||
}
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body.email-body,
|
||||
table.centerer,
|
||||
table.wrapper {
|
||||
background-color: #3B1B1B !important;
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
table.card {
|
||||
background-color: #4A2323 !important;
|
||||
}
|
||||
span.shoutout {
|
||||
color: #FF9999 !important;
|
||||
}
|
||||
td.confirm-link {
|
||||
background-color: #B60000 !important;
|
||||
}
|
||||
td.confirm-code {
|
||||
background-color: #652323 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
td.notice {
|
||||
color: #C18989 !important;
|
||||
}
|
||||
td.notice a {
|
||||
color: #F5C1C1 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="email-body" bgcolor="#1B1F3B" style="margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; font-family: Poppins, Arial, Helvetica, sans-serif;">
|
||||
<div style="display:none;">Hello {{username}}! Your Splatfestival Network ID activation is almost complete. Please click the link in this email to confirm your e-mail address and complete the activation process.</div>
|
||||
<table class="centerer" bgcolor="#1B1F3B" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table class="wrapper" bgcolor="#1B1F3B" style="font-family: Poppins, Arial, Helvetica, sans-serif;" border="0" cellpadding="0" cellspacing="0" height="100%" width="420px">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td width="32px"> </td>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td height="36px" style="line-height: 36px;" width="100%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://spfn.cc">
|
||||
<img class="logo" width="auto" height="48px" src="https://cdn.abmanagement.al/SPFN.png" alt="SPFN">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="36px" style="line-height: 36px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table class="card" bgcolor="#23274a" style="color: #ffffff; border-radius: 10px;" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr>
|
||||
<td width="24px" height="100%"> </td>
|
||||
<td>
|
||||
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
|
||||
<tr width="100%" height="48px" style="line-height: 48px;">
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr style="font-size: 24px; font-weight: 700;">
|
||||
<td>
|
||||
Hello <span class="shoutout" style="color: #cab1fb;">{{username}}</span>!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="24px" style="line-height: 24px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #ffffff; ">
|
||||
Your Splatfestival Network ID activation is almost complete.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="16px" style="line-height: 16px;"> </td>
|
||||
</tr>
|
||||
<!-- <tr>-->
|
||||
<!-- <td class="confirm-link" bgcolor="#673db6" style="font-size: 14px; font-weight: 700; border-radius: 10px; padding: 12px" align="center">-->
|
||||
<!-- <a href="{{confirmation-href}}" style="text-decoration: none; color: #ffffff; " width="100%">-->
|
||||
<!-- Confirm email address-->
|
||||
<!-- </a>-->
|
||||
<!-- </td>-->
|
||||
<!-- </tr>-->
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Enter the following 6-digit code on your console:
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="16px" style="line-height: 16px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="confirm-code" bgcolor="#373c65" style="color: #ffffff; font-size: 14px; font-weight: 700; border-radius: 10px; padding: 12px" align="center">
|
||||
{{confirmation-code}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
We hope you have fun using our services!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="36px" style="line-height: 36px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">
|
||||
The SPFN team
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="24px" style="line-height: 24px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="24px" height="100%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="18px" style="line-height: 18px;"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="notice" style="color: #8990c1; font-size: 12px;">
|
||||
Note: this email message was auto-generated, please do not respond. For further assistance, please join our <a href="https://discord.gg/splatfestival" style="text-decoration: none; color: #ffffff; ">Discord server</a> or make a post on our <a href="https://forum.perditum.com" style="text-decoration: none; color: #ffffff; ">Forum</a>.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100%" height="48px" style="line-height: 48px;"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="32px"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -54,7 +54,8 @@ pub struct User {
|
|||
pub mii_data: String,
|
||||
pub creation_date: NaiveDateTime,
|
||||
pub updated: NaiveDateTime,
|
||||
pub nex_password: String
|
||||
pub nex_password: String,
|
||||
pub verification_code: Option<i32>
|
||||
}
|
||||
|
||||
fn generate_nintendo_hash(pid: i32, text_password: &str) -> String{
|
||||
|
|
|
|||
38
src/email.rs
Normal file
38
src/email.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use lettre::transport::smtp::authentication::Credentials;
|
||||
use lettre::{Message, SmtpTransport, Transport};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
pub async fn send_verification_email(to: &str, code: i32, username: &str) -> Result<(), String> {
|
||||
let smtp_user = env::var("SMTP_USER").map_err(|_| "SMTP_USER not set".to_string())?;
|
||||
let smtp_pass = env::var("SMTP_PASS").map_err(|_| "SMTP_PASS not set".to_string())?;
|
||||
let smtp_server = env::var("SMTP_SERVER").map_err(|_| "SMTP_SERVER not set".to_string())?;
|
||||
|
||||
// Load template
|
||||
let template = fs::read_to_string("res/email/confirmationTemplate.html")
|
||||
.map_err(|e| format!("Failed to read email template: {}", e))?;
|
||||
|
||||
// Replace placeholders
|
||||
let body = template
|
||||
.replace("{{username}}", username)
|
||||
.replace("{{confirmation-code}}", &format!("{:06}", code));
|
||||
|
||||
let email = Message::builder()
|
||||
.from(smtp_user.parse().unwrap())
|
||||
.to(to.parse().unwrap())
|
||||
.subject("Your Verification Code")
|
||||
.header(lettre::message::header::ContentType::TEXT_HTML)
|
||||
.body(body)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let creds = Credentials::new(smtp_user, smtp_pass);
|
||||
|
||||
let mailer = SmtpTransport::relay(&smtp_server)
|
||||
.map_err(|e| e.to_string())?
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
||||
mailer.send(&email).map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ mod data_wrapper;
|
|||
#[deprecated]
|
||||
mod grpc;
|
||||
mod graphql;
|
||||
mod email;
|
||||
|
||||
type Pool = sqlx::Pool<Postgres>;
|
||||
|
||||
|
|
@ -109,7 +110,8 @@ async fn launch() -> _ {
|
|||
nnid::agreements::get_agreement,
|
||||
nnid::timezones::get_timezone,
|
||||
nnid::person_exists::person_exists,
|
||||
nnid::email::validate,
|
||||
nnid::support::validate,
|
||||
nnid::support::verify_email,
|
||||
nnid::people::create_account,
|
||||
nnid::people::get_own_profile,
|
||||
nnid::oauth::generate_token::generate_token,
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
use rocket::{post, FromForm};
|
||||
use rocket::form::Form;
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct ValidateEmailInput{
|
||||
email: String,
|
||||
}
|
||||
#[post("/v1/api/support/validate/email", data="<data>")]
|
||||
pub fn validate(data: Form<ValidateEmailInput>){
|
||||
|
||||
}
|
||||
|
|
@ -2,9 +2,9 @@ pub mod devices;
|
|||
pub mod agreements;
|
||||
pub mod timezones;
|
||||
pub mod person_exists;
|
||||
pub mod email;
|
||||
pub mod oauth;
|
||||
mod pid_distribution;
|
||||
pub mod people;
|
||||
pub mod provider;
|
||||
pub mod mapped_ids;
|
||||
pub mod support;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ use crate::nnid::pid_distribution::next_pid;
|
|||
use crate::nnid::timezones::{OFFSET_FROM_TIMEZONE, ZONE_TO_TIMEZONES};
|
||||
use crate::Pool;
|
||||
use crate::xml::{Xml, YesNoVal};
|
||||
use crate::email::send_verification_email;
|
||||
use rand::Rng;
|
||||
|
||||
static S3_URL_STRING: Lazy<Box<str>> = Lazy::new(||
|
||||
env::var("S3_URL").expect("S3_URL not specified").into_boxed_str()
|
||||
|
|
@ -114,6 +116,8 @@ pub async fn create_account(database: &State<Pool>, data: Xml<AccountCreationDat
|
|||
|
||||
let pid = next_pid(database).await;
|
||||
|
||||
let verification_code: i32 = rand::thread_rng().gen_range(100_000..1_000_000);
|
||||
|
||||
let AccountCreationData {
|
||||
user_id,
|
||||
password,
|
||||
|
|
@ -152,9 +156,10 @@ pub async fn create_account(database: &State<Pool>, data: Xml<AccountCreationDat
|
|||
off_device_allowed,
|
||||
region,
|
||||
gender,
|
||||
mii_data
|
||||
mii_data,
|
||||
verification_code
|
||||
) VALUES (
|
||||
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13
|
||||
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14
|
||||
)
|
||||
",
|
||||
pid,
|
||||
|
|
@ -169,11 +174,16 @@ pub async fn create_account(database: &State<Pool>, data: Xml<AccountCreationDat
|
|||
off_device_flag.0,
|
||||
region,
|
||||
gender.as_ref(),
|
||||
data.as_ref()
|
||||
data.as_ref(),
|
||||
verification_code,
|
||||
).execute(database).await.unwrap();
|
||||
|
||||
generate_s3_images(pid, &data).await;
|
||||
|
||||
if let Err(e) = send_verification_email(address.as_ref(), verification_code, user_id.as_ref()).await {
|
||||
println!("Failed to send verification email: {e}");
|
||||
}
|
||||
|
||||
Ok(
|
||||
Xml(AccountCreationResponseData{
|
||||
pid
|
||||
|
|
|
|||
65
src/nnid/support.rs
Normal file
65
src/nnid/support.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use rocket::{get, State, post, FromForm};
|
||||
use rocket::http::Status;
|
||||
use crate::Pool;
|
||||
use rocket::form::Form;
|
||||
use crate::email::send_verification_email;
|
||||
use crate::error::{Error, Errors};
|
||||
use chrono::Utc;
|
||||
|
||||
const BAD_CODE_ERROR: Errors = Errors{
|
||||
error: &[
|
||||
Error{
|
||||
code: "0116",
|
||||
message: "Missing or invalid verification code"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct ValidateEmailInput{
|
||||
email: String,
|
||||
}
|
||||
#[post("/v1/api/support/validate/email", data="<data>")]
|
||||
pub async fn validate(data: Form<ValidateEmailInput>){
|
||||
if let Err(e) = send_verification_email(&*data.email, 123456, "Andrea Test Username").await {
|
||||
println!("Failed to send verification email: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/v1/api/support/email_confirmation/<pid>/<code>")]
|
||||
pub async fn verify_email(database: &State<Pool>, pid: i32, code: i32) -> Result<(), Errors<'static>> {
|
||||
let db = database.inner();
|
||||
|
||||
let result = sqlx::query!(
|
||||
"SELECT verification_code FROM users WHERE pid = $1",
|
||||
pid
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await;
|
||||
|
||||
let Ok(Some(record)) = result else {
|
||||
return Err(BAD_CODE_ERROR);
|
||||
};
|
||||
|
||||
if let Some(stored_code) = record.verification_code {
|
||||
if stored_code == code {
|
||||
// Set email_verified_since to NOW
|
||||
let now = Utc::now().naive_utc();
|
||||
let update_result = sqlx::query!(
|
||||
"UPDATE users SET email_verified_since = $1 WHERE pid = $2",
|
||||
now,
|
||||
pid
|
||||
)
|
||||
.execute(db)
|
||||
.await;
|
||||
|
||||
if update_result.is_err() {
|
||||
return Err(BAD_CODE_ERROR); // fallback in case the update fails
|
||||
}
|
||||
|
||||
return Ok(()); // Success
|
||||
}
|
||||
}
|
||||
|
||||
Err(BAD_CODE_ERROR)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue