Compare commits

...

2 Commits

4 changed files with 133 additions and 32 deletions

View File

@ -14,6 +14,9 @@ pub struct Account {
pub password: String,
pub joined: sqlx_chrono::NaiveDateTime,
pub verified: bool,
pub follows: Option<Vec<i64>>,
pub followers: Option<Vec<i64>>,
pub permissions: i64,
}
impl Account {
@ -33,7 +36,7 @@ impl Account {
let joined = sqlx_chrono::Utc::now().naive_utc();
sqlx::query!(
r#"INSERT INTO Accounts (username, email, salt, password, joined, verified) VALUES ($1, $2, $3, $4, $5, false);"#,
r#"INSERT INTO Accounts (username, email, salt, password, joined, verified, permissions) VALUES ($1, $2, $3, $4, $5, false, 0);"#,
username,
email,
salt.to_string(),
@ -54,7 +57,18 @@ impl Account {
pub async fn from_username(pool: &PgPool, username: &String) -> Result<Option<Self>> {
match sqlx::query_as!(
Self,
r#"SELECT id, username, email, salt, password, joined, verified as "verified!: bool" FROM Accounts WHERE username = $1;"#,
r#"SELECT
id,
username,
email,
salt,
password,
joined,
verified as "verified!: bool",
follows,
followers,
permissions
FROM Accounts WHERE username = $1;"#,
username
)
.fetch_one(pool)
@ -69,7 +83,18 @@ impl Account {
pub async fn from_id(pool: &PgPool, id: i64) -> Result<Option<Self>> {
match sqlx::query_as!(
Self,
r#"SELECT id, username, email, salt, password, joined, verified as "verified!: bool" FROM Accounts WHERE id = $1;"#,
r#"SELECT
id,
username,
email,
salt,
password,
joined,
verified as "verified!: bool",
follows,
followers,
permissions
FROM Accounts WHERE id = $1;"#,
id
)
.fetch_one(pool)
@ -84,7 +109,18 @@ impl Account {
pub async fn from_email(pool: &PgPool, email: &String) -> Result<Option<Self>> {
match sqlx::query_as!(
Self,
r#"SELECT id, username, email, salt, password, joined, verified as "verified!: bool" FROM Accounts WHERE email = $1;"#,
r#"SELECT
id,
username,
email,
salt,
password,
joined,
verified as "verified!: bool",
follows,
followers,
permissions
FROM Accounts WHERE email = $1;"#,
email
)
.fetch_one(pool)
@ -105,4 +141,15 @@ impl Account {
Err(_) => Ok(false),
}
}
pub async fn delete(&self, pool: &PgPool) -> Result<()> {
sqlx::query!(r#"DELETE FROM AuthTokens WHERE account = $1;"#, self.id)
.execute(pool)
.await?;
sqlx::query!(r#"DELETE FROM Accounts WHERE id = $1;"#, self.id)
.execute(pool)
.await?;
Ok(())
}
}

View File

@ -41,19 +41,34 @@ pub async fn register(
return Ok(data::RegisterResponse::MalformedEmail);
}
if Account::from_username(pool, &request.username)
.await?
.is_some()
{
return Ok(data::RegisterResponse::Conflict(
data::RegisterConflict::Username,
));
// Check if the usernam is already taken
if let Some(account) = Account::from_username(pool, &request.username).await? {
// Check if the account that has taken the username is verified or has an open verification request.
if account.verified
|| VerificationToken::from_id(pool, account.id)
.await?
.is_some()
{
return Ok(data::RegisterResponse::Conflict(
data::RegisterConflict::Username,
));
}
// The found account is a Zombie account, we can delete it and continue.
account.delete(pool).await?;
}
if Account::from_email(pool, &request.email).await?.is_some() {
return Ok(data::RegisterResponse::Conflict(
data::RegisterConflict::Email,
));
// The same stuff for the email
if let Some(account) = Account::from_email(pool, &request.email).await? {
if account.verified
|| VerificationToken::from_id(pool, account.id)
.await?
.is_some()
{
return Ok(data::RegisterResponse::Conflict(
data::RegisterConflict::Email,
));
}
account.delete(pool).await?;
}
let account = Account::new(pool, &request.username, &request.email, &request.password).await?;
@ -137,16 +152,14 @@ pub async fn delete(pool: &PgPool, auth: String) -> Result<data::DeleteResponse>
None => return Ok(data::DeleteResponse::Unauthorized),
};
sqlx::query!(
r#"DELETE FROM AuthTokens WHERE account = $1;"#,
token.account
)
.execute(pool)
.await?;
sqlx::query!(r#"DELETE FROM Accounts WHERE id = $1;"#, token.account)
.execute(pool)
.await?;
match Account::from_id(pool, token.account).await? {
Some(a) => a.delete(pool).await?,
None => {
return Err(anyhow::Error::msg(
"Failed to delete account. Account not found in database",
))
}
}
Ok(data::DeleteResponse::Success)
}

View File

@ -15,13 +15,16 @@ pub async fn start(port: u16, pool: PgPool) -> Result<()> {
sqlx::query!(
r#"
CREATE TABLE IF NOT EXISTS Accounts (
id SERIAL8 NOT NULL,
username VARCHAR(32) NOT NULL,
email TEXT NOT NULL,
salt VARCHAR(22) NOT NULL,
password VARCHAR(96) NOT NULL,
joined TIMESTAMP NOT NULL,
verified BOOLEAN NOT NULL,
id SERIAL8 NOT NULL,
username VARCHAR(32) NOT NULL,
email TEXT NOT NULL,
salt VARCHAR(22) NOT NULL,
password VARCHAR(96) NOT NULL,
joined TIMESTAMP NOT NULL,
verified BOOLEAN NOT NULL,
follows BIGINT[],
followers BIGINT[],
permissions BIGINT NOT NULL,
PRIMARY KEY(id)
);
"#
@ -53,6 +56,21 @@ pub async fn start(port: u16, pool: PgPool) -> Result<()> {
.execute(&pool)
.await?;
sqlx::query!(
r#"
CREATE TABLE IF NOT EXISTS Projects (
id SERIAL8 NOT NULL,
name VARCHAR(32) NOT NULL,
desription TEXT,
created TIMESTAMP NOT NULL,
members BIGINT[][] NOT NULL,
PRIMARY KEY(id)
);
"#
)
.execute(&pool)
.await?;
let _ = HttpServer::new(move || {
App::new()
.service(account::calls::register)

View File

@ -156,6 +156,29 @@ impl VerificationToken {
}
}
pub async fn from_id(pool: &PgPool, account_id: i64) -> Result<Option<Self>> {
let query_result = sqlx::query_as!(
Self,
r#"SELECT * FROM VerificationTokens WHERE account = $1;"#,
account_id
)
.fetch_one(pool)
.await;
match query_result {
Ok(token) => {
if token.expire.timestamp() > chrono::Utc::now().timestamp() {
Ok(Some(token))
} else {
token.delete(pool).await?;
Ok(None)
}
}
Err(sqlx::Error::RowNotFound) => Ok(None),
Err(e) => Err(Error::new(e)),
}
}
pub async fn delete(&self, pool: &PgPool) -> Result<()> {
sqlx::query!(
r#"DELETE FROM VerificationTokens WHERE token = $1;"#,