Skip to content

Commit

Permalink
Implement database operations and endpoints username/displayname
Browse files Browse the repository at this point in the history
  • Loading branch information
MapManagement committed Aug 8, 2023
1 parent 704f5a2 commit 25f8e83
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/api/src/api_models/profile_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use utoipa::ToSchema;
#[derive(Deserialize, ToSchema)]
pub struct PostProfile {
pub username: String,
pub displayname: Option<String>,
pub password: String,
pub email_address: String,
}
Expand All @@ -13,13 +14,15 @@ pub struct PostProfile {
#[derive(Deserialize, Serialize, ToSchema)]
pub struct GetProfile {
pub username: String,
pub displayname: String,
pub email_address: String,
pub join_datetime: NaiveDateTime,
}

#[derive(Deserialize, ToSchema)]
pub struct PatchProfile {
pub username: Option<String>,
pub displayname: Option<String>,
pub password: Option<String>,
pub email_address: Option<String>,
pub profile_picture: Option<String>,
Expand Down
1 change: 1 addition & 0 deletions src/api/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use utoipa::OpenApi;
paths(
profile_service::new_profile,
profile_service::get_profile,
profile_service::get_profile_username,
profile_service::update_profile,
profile_service::delete_profile,
private_message_service::new_private_message,
Expand Down
53 changes: 51 additions & 2 deletions src/api/src/services/profile_service.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::api_models::profile_schema::*;
use crate::AppState;
use actix_web::*;
use database::sea_orm::DbErr;
use database::*;

#[get("/")]
Expand All @@ -15,6 +16,7 @@ async fn index() -> impl Responder {
request_body = PostProfile,
responses(
(status = 201, description = "Success!"),
(status = 403, description = "Whitespaces cannot be used in usernames!"),
(status = 500, description = "Error!")
)
)]
Expand All @@ -28,6 +30,7 @@ pub(super) async fn new_profile(
// TODO: hash password
let result = insert_profile(
&new_profile.username,
&new_profile.displayname,
&new_profile.password,
&new_profile.email_address,
&db_connection,
Expand All @@ -36,11 +39,14 @@ pub(super) async fn new_profile(

match result {
Ok(_) => HttpResponse::Created().body("Success!"),
Err(_) => HttpResponse::InternalServerError().body("Error!"),
Err(error) => match error {
DbErr::Custom(text) => HttpResponse::Forbidden().body(text),
_ => HttpResponse::InternalServerError().body("Error!"),
},
}
}

/// Get profile
/// Get profile by id
///
/// Get a specific platform profile by its identifier
#[utoipa::path(
Expand All @@ -66,6 +72,44 @@ pub(super) async fn get_profile(
Ok(profile) => {
let profile_schema = GetProfile {
username: profile.username,
displayname: profile.displayname.unwrap(),
email_address: profile.email_address,
join_datetime: profile.join_datetime,
};

HttpResponse::Ok().json(profile_schema)
}
Err(_) => HttpResponse::NotFound().body("Couldn't find the specified profile!"),
}
}

/// Get profile by username
///
/// Get a specific platform profile by its username
#[utoipa::path(
tag = "Profile",
params(
("username", description = "Username of profile")
),
responses(
(status = 200, body = GetProfile),
(status = 404, description = "Couldn't find the specified profile!")
)
)]
#[get("/profile/username/{profile_username}")]
pub(super) async fn get_profile_username(
data: web::Data<AppState>,
profile_username: web::Path<String>,
) -> impl Responder {
let db_connection = &data.db_connection;

let query_result = get_profile_by_username(&profile_username, &db_connection).await;

match query_result {
Ok(profile) => {
let profile_schema = GetProfile {
username: profile.username,
displayname: profile.displayname.unwrap(),
email_address: profile.email_address,
join_datetime: profile.join_datetime,
};
Expand Down Expand Up @@ -108,6 +152,10 @@ pub(super) async fn update_profile(
.username
.to_owned()
.unwrap_or(profile.username),
&updated_fields
.displayname
.to_owned()
.unwrap_or(profile.displayname.unwrap()),
&updated_fields
.password
.to_owned()
Expand Down Expand Up @@ -164,6 +212,7 @@ pub(super) async fn delete_profile(
pub fn profile_config(cfg: &mut web::ServiceConfig) {
cfg.service(new_profile);
cfg.service(get_profile);
cfg.service(get_profile_username);
cfg.service(update_profile);
cfg.service(delete_profile);
}
29 changes: 29 additions & 0 deletions src/database/src/profile_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@ use sea_orm::*;
// TODO: profile picture
pub async fn insert_profile(
username: &str,
displayname: &Option<String>,
hashed_password: &str,
email_address: &str,
connection: &DbConn,
) -> Result<profile::ActiveModel, DbErr> {
if !is_username_valid(&username) {
return Err(DbErr::Custom(
"Whitespaces cannot be used in usernames!".to_string(),
));
}

let new_profile = profile::ActiveModel {
username: ActiveValue::Set(username.to_string()),
displayname: ActiveValue::Set(displayname.to_owned()),
password: ActiveValue::Set(hashed_password.to_string()),
email_address: ActiveValue::Set(email_address.to_string()),
join_datetime: ActiveValue::Set(Local::now().naive_local()),
Expand All @@ -36,6 +44,7 @@ pub async fn insert_profile(
pub async fn update_profile(
profile_id: i32,
username: &str,
displayname: &str,
hashed_password: &str,
email_address: &str,
profile_picture: &str,
Expand All @@ -52,6 +61,7 @@ pub async fn update_profile(
profile::ActiveModel {
profile_id: ActiveValue::Set(target_profile.profile_id),
username: ActiveValue::Set(username.to_string()),
displayname: ActiveValue::Set(Some(displayname.to_string())),
password: ActiveValue::Set(hashed_password.to_string()),
email_address: ActiveValue::Set(email_address.to_string()),
join_datetime: ActiveValue::Set(Local::now().naive_local()),
Expand All @@ -75,6 +85,21 @@ pub async fn get_profile_by_id(
return target_profile;
}

pub async fn get_profile_by_username(
username: &str,
connection: &DbConn,
) -> Result<profile::Model, DbErr> {
let target_profile = profile::Entity::find()
.filter(profile::Column::Username.eq(username))
.one(connection)
.await?
.ok_or(DbErr::Custom(
"Couldn't find a profile with the specified username.".to_owned(),
));

return target_profile;
}

pub async fn delete_profile_by_id(
profile_id: i32,
connection: &DbConn,
Expand All @@ -100,3 +125,7 @@ pub async fn check_profile_exists(

target_profile
}

fn is_username_valid(username: &str) -> bool {
return !username.contains(char::is_whitespace) && username.len() < 33;
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@ impl MigrationTrait for Migration {
db_connection
.execute_unprepared(
"ALTER TABLE profile
DROP COLUMN displayname",
DROP COLUMN IF EXISTS displayname",
)
.await?;

db_connection
.execute_unprepared(
"ALTER TABLE profile
MODIFY username NULL",
MODIFY username varchar(32) NULL",
)
.await?;

db_connection
.execute_unprepared(
"ALTER TABLE profile
DROP CONSTRAINT unique_username",
DROP CONSTRAINT IF EXISTS unique_username",
)
.await?;

Expand Down

0 comments on commit 25f8e83

Please sign in to comment.