From 9b9d94205d3e55a5e8a765674ef464e80f3e40fb Mon Sep 17 00:00:00 2001 From: rtkay123 Date: Sat, 26 Jul 2025 10:20:06 +0200 Subject: feat(profile): create service --- crates/profile-service/Cargo.toml | 38 ++++++++++++++++ crates/profile-service/src/main.rs | 3 ++ lib/sellershut-core/Cargo.toml | 1 + lib/sellershut-core/build.rs | 17 +++++-- lib/sellershut-core/proto/profile/profile.proto | 59 +++++++++++++++++++++++++ lib/sellershut-core/src/lib.rs | 4 ++ lib/sellershut-core/src/profile.rs | 3 ++ 7 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 crates/profile-service/Cargo.toml create mode 100644 crates/profile-service/src/main.rs create mode 100644 lib/sellershut-core/proto/profile/profile.proto create mode 100644 lib/sellershut-core/src/profile.rs diff --git a/crates/profile-service/Cargo.toml b/crates/profile-service/Cargo.toml new file mode 100644 index 0000000..409110b --- /dev/null +++ b/crates/profile-service/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "profile-service" +version = "0.1.0" +edition = "2024" +license.workspace = true +homepage.workspace = true +documentation.workspace = true +description.workspace = true + +[dependencies] +anyhow.workspace = true +axum = { workspace = true, features = ["macros"] } +axum-extra = { version = "0.10.1", features = ["typed-header"] } +base64.workspace = true +clap = { workspace = true, features = ["derive"] } +config = { workspace = true, features = ["convert-case", "toml"] } +futures-util.workspace = true +jsonwebtoken = "9.3.1" +nanoid.workspace = true +oauth2 = "5.0.0" +reqwest = { workspace = true, features = ["json", "rustls-tls"] } +sellershut-core = { workspace = true, features = ["profile", "serde"] } +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +sqlx = { workspace = true, features = ["macros", "migrate", "runtime-tokio", "time", "tls-rustls", "uuid"] } +time = { workspace = true, features = ["parsing", "serde"] } +tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal"] } +tonic.workspace = true +tonic-reflection = "0.13.0" +tower = { workspace = true, features = ["steer", "util"] } +tower-http = { workspace = true, features = ["map-request-body", "trace", "util"] } +tower-sessions = "0.14.0" +tower-sessions-core = { version = "0.14.0", features = ["deletion-task"] } +tower-sessions-moka-store = "0.15.0" +tower-sessions-sqlx-store = { version = "0.15.0", features = ["postgres"] } +tracing.workspace = true +url.workspace = true +uuid = { workspace = true, features = ["serde", "v7"] } diff --git a/crates/profile-service/src/main.rs b/crates/profile-service/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/crates/profile-service/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/lib/sellershut-core/Cargo.toml b/lib/sellershut-core/Cargo.toml index b5e1bb9..1b7d5f7 100644 --- a/lib/sellershut-core/Cargo.toml +++ b/lib/sellershut-core/Cargo.toml @@ -18,6 +18,7 @@ tonic-types = "0.13.0" [features] default = [] auth = [] +profile = [] serde = ["dep:serde", "serde/derive", "serde_json"] time = [ "dep:time", diff --git a/lib/sellershut-core/build.rs b/lib/sellershut-core/build.rs index 8ff48f1..110bc22 100644 --- a/lib/sellershut-core/build.rs +++ b/lib/sellershut-core/build.rs @@ -1,10 +1,12 @@ -#[cfg(feature = "auth")] +#[cfg(any(feature = "auth", feature = "profile"))] enum Entity { #[cfg(feature = "auth")] Auth, + #[cfg(feature = "profile")] + Profile, } -#[cfg(feature = "auth")] +#[cfg(any(feature = "auth", feature = "profile"))] impl Entity { fn protos(&self) -> Vec<&'static str> { let mut res: Vec<&'static str> = vec![]; @@ -13,6 +15,10 @@ impl Entity { #[cfg(feature = "auth")] Entity::Auth => { res.extend(vec!["proto/auth/auth.proto"]); + }, + #[cfg(feature = "profile")] + Entity::Profile => { + res.extend(vec!["proto/profile/profile.proto"]); } } res @@ -25,10 +31,13 @@ fn main() -> Result<(), Box> { #[cfg(feature = "auth")] build_proto("auth", Entity::Auth); + #[cfg(feature = "profile")] + build_proto("profile", Entity::Profile); + Ok(()) } -#[cfg(feature = "auth")] +#[cfg(any(feature = "auth", feature = "profile"))] fn build_proto(package: &str, entity: Entity) { let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap()); @@ -72,7 +81,7 @@ fn build_proto(package: &str, entity: Entity) { .compile_protos(&entity.protos(), include_paths).unwrap(); } -#[cfg(all(feature = "serde", feature = "auth",))] +#[cfg(all(feature = "serde", any(feature = "auth",feature = "profile")))] fn add_serde(config: tonic_build::Builder) -> tonic_build::Builder { config.type_attribute( ".", diff --git a/lib/sellershut-core/proto/profile/profile.proto b/lib/sellershut-core/proto/profile/profile.proto new file mode 100644 index 0000000..742dc7b --- /dev/null +++ b/lib/sellershut-core/proto/profile/profile.proto @@ -0,0 +1,59 @@ +syntax = "proto3"; + +package profile; + +import "google/protobuf/timestamp.proto"; + +// A message representing a user profile +message User { + // Unique identifier for the user + string id = 1; + // Email address of the user + string email = 2; + // Unique username chosen by the user + string username = 3; + // URL to the user's avatar image + optional string avatar = 4; + // Timestamp when the user was created + google.protobuf.Timestamp created_at = 5; + // Timestamp when the user was last updated + google.protobuf.Timestamp updated_at = 6; + // User-provided description or bio + optional string description = 7; +} + +// Request message for creating a new user profile +message CreateUserRequest { + // Email address of the new user + string email = 1; + // Avatar for the new user + optional string avatar = 2; +} + +// Response message for CreateUser RPC +message CreateUserResponse { + // Temporary assigned id + string temp_id = 1; + // Timestamp when the user was created + google.protobuf.Timestamp created_at = 2; +} + +// Message to finalise profile creation +message CompleteUserRequest { + // ID of the user to finalise + string id = 1; + // Required: username to finalise the profile + string username = 2; + // Optional: user-provided description + optional string description = 3; + // Optional: update avatar + optional string avatar = 4; +} + +// Profile gRPC service +service Profile { + // Create a new user profile + rpc CreateUser (CreateUserRequest) returns (CreateUserResponse); + // Complete Profile + rpc CompleteProfile (CompleteUserRequest) returns (User); +} diff --git a/lib/sellershut-core/src/lib.rs b/lib/sellershut-core/src/lib.rs index ee2ed9b..c300495 100644 --- a/lib/sellershut-core/src/lib.rs +++ b/lib/sellershut-core/src/lib.rs @@ -10,4 +10,8 @@ #[cfg(feature = "auth")] pub mod google; +/// Interactions with Auth server pub mod auth; + +/// Interactions with Profile server +pub mod profile; diff --git a/lib/sellershut-core/src/profile.rs b/lib/sellershut-core/src/profile.rs new file mode 100644 index 0000000..bf366b1 --- /dev/null +++ b/lib/sellershut-core/src/profile.rs @@ -0,0 +1,3 @@ +tonic::include_proto!("profile"); +/// Profile file descriptor +pub const PROFILE_FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("profile_descriptor"); -- cgit v1.2.3