summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtkay123 <dev@kanjala.com>2025-07-27 18:16:41 +0200
committerrtkay123 <dev@kanjala.com>2025-07-27 18:16:41 +0200
commit3c4d17cf2840c643b8cd111ef775750cc5ae83b3 (patch)
tree2b7d25b24d94141a6d9255426d4f973cced5d278
parente26d87f4fa18999c6bcfbcf32cfa85adab11acdd (diff)
downloadsellershut-3c4d17cf2840c643b8cd111ef775750cc5ae83b3.tar.bz2
sellershut-3c4d17cf2840c643b8cd111ef775750cc5ae83b3.zip
refactor: profile -> users
-rw-r--r--Cargo.lock2
-rw-r--r--crates/auth-service/Cargo.toml2
-rw-r--r--crates/auth-service/src/server/routes/authorised.rs4
-rw-r--r--crates/auth-service/src/state.rs8
-rw-r--r--crates/profile-service/src/server/manager.rs45
-rw-r--r--crates/users-service/Cargo.toml (renamed from crates/profile-service/Cargo.toml)4
-rw-r--r--crates/users-service/migrations/20250726161947_profile.sql (renamed from crates/profile-service/migrations/20250726161947_profile.sql)0
-rw-r--r--crates/users-service/src/cnfg.rs (renamed from crates/profile-service/src/cnfg.rs)0
-rw-r--r--crates/users-service/src/main.rs (renamed from crates/profile-service/src/main.rs)9
-rw-r--r--crates/users-service/src/server.rs (renamed from crates/profile-service/src/server.rs)0
-rw-r--r--crates/users-service/src/server/interceptor.rs (renamed from crates/profile-service/src/server/interceptor.rs)0
-rw-r--r--crates/users-service/src/server/manager.rs85
-rw-r--r--crates/users-service/src/state.rs (renamed from crates/profile-service/src/state.rs)25
-rw-r--r--crates/users-service/users.toml (renamed from crates/profile-service/profile.toml)2
-rw-r--r--lib/sellershut-core/Cargo.toml2
-rw-r--r--lib/sellershut-core/build.rs22
-rw-r--r--lib/sellershut-core/proto/users/users.proto (renamed from lib/sellershut-core/proto/profile/profile.proto)42
-rw-r--r--lib/sellershut-core/src/lib.rs8
-rw-r--r--lib/sellershut-core/src/profile.rs4
-rw-r--r--lib/sellershut-core/src/users.rs36
20 files changed, 208 insertions, 92 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 23a8702..ec78576 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2649,7 +2649,7 @@ dependencies = [
]
[[package]]
-name = "sellershut-profiles"
+name = "sellershut-users"
version = "0.1.0"
dependencies = [
"anyhow",
diff --git a/crates/auth-service/Cargo.toml b/crates/auth-service/Cargo.toml
index bbbb10d..837fc8b 100644
--- a/crates/auth-service/Cargo.toml
+++ b/crates/auth-service/Cargo.toml
@@ -19,7 +19,7 @@ jsonwebtoken = "9.3.1"
nanoid.workspace = true
oauth2 = "5.0.0"
reqwest = { workspace = true, features = ["json", "rustls-tls"] }
-sellershut-core = { workspace = true, features = ["auth", "serde"] }
+sellershut-core = { workspace = true, features = ["auth", "serde", "users"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
sqlx = { workspace = true, features = ["macros", "migrate", "runtime-tokio", "time", "tls-rustls", "uuid"] }
diff --git a/crates/auth-service/src/server/routes/authorised.rs b/crates/auth-service/src/server/routes/authorised.rs
index 4d48299..2538cdc 100644
--- a/crates/auth-service/src/server/routes/authorised.rs
+++ b/crates/auth-service/src/server/routes/authorised.rs
@@ -9,7 +9,7 @@ use axum::{
use axum_extra::{TypedHeader, headers};
use oauth2::{AuthorizationCode, TokenResponse};
use reqwest::{StatusCode, header::SET_COOKIE};
-use sellershut_core::profile::CreateUserRequest;
+use sellershut_core::users::CreateUserRequest;
use serde::{Deserialize, Serialize};
use sqlx::types::uuid;
use time::OffsetDateTime;
@@ -215,7 +215,7 @@ pub async fn login_authorised(
let cookie = format!("{SESSION_COOKIE}={session_id}; SameSite=Lax; HttpOnly; Secure; Path=/");
- let mut profile_client = state.profile_client.clone();
+ let mut profile_client = state.users_client.clone();
let resp = profile_client.create_user(user_request).await?.into_inner();
let user_id = resp.temp_id;
diff --git a/crates/auth-service/src/state.rs b/crates/auth-service/src/state.rs
index 5905948..07bfda9 100644
--- a/crates/auth-service/src/state.rs
+++ b/crates/auth-service/src/state.rs
@@ -1,6 +1,6 @@
use std::{ops::Deref, sync::Arc};
-use sellershut_core::profile::profile_client::ProfileClient;
+use sellershut_core::users::users_service_client::UsersServiceClient;
use sqlx::PgPool;
use stack_up::Configuration;
use tokio::task::JoinHandle;
@@ -39,7 +39,7 @@ pub struct AppState {
pub discord_client: OauthClient,
pub http_client: reqwest::Client,
pub session_store: CachingSessionStore<MokaStore, PostgresStore>,
- pub profile_client: ProfileClient<Intercepted>,
+ pub users_client: UsersServiceClient<Intercepted>,
}
impl AppState {
@@ -68,7 +68,7 @@ impl AppState {
.await
.inspect_err(|e| error!("could not connect to profile service: {e}"))?;
- let profile_client = ProfileClient::with_interceptor(channel, MyInterceptor);
+ let users_client = UsersServiceClient::with_interceptor(channel, MyInterceptor);
Ok((
AppHandle(Arc::new(Self {
@@ -77,7 +77,7 @@ impl AppState {
discord_client,
http_client: reqwest::Client::new(),
session_store: store,
- profile_client,
+ users_client,
})),
deletion_task,
))
diff --git a/crates/profile-service/src/server/manager.rs b/crates/profile-service/src/server/manager.rs
deleted file mode 100644
index bd7e149..0000000
--- a/crates/profile-service/src/server/manager.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use prost::Message;
-use sellershut_core::profile::{
- CompleteUserRequest, CreateUserRequest, CreateUserResponse, User, profile_server::Profile,
-};
-use stack_up::redis::AsyncCommands;
-use tonic::{Request, Response, Status, async_trait};
-use tracing::trace;
-use uuid::Uuid;
-
-use crate::state::AppHandle;
-
-#[async_trait]
-impl Profile for AppHandle {
- #[doc = " Create a new user profile"]
- async fn create_user(
- &self,
- request: Request<CreateUserRequest>,
- ) -> Result<Response<CreateUserResponse>, Status> {
- trace!("creating user");
- let data = request.into_inner();
- let id = Uuid::now_v7().to_string();
-
- let bytes = data.encode_to_vec();
- let mut cache = self
- .services
- .cache
- .get()
- .await
- .map_err(|e| Status::internal("storage not ready"))?;
- cache
- .set_ex::<_, _, ()>(&id, &bytes, self.local_config.temp_ttl)
- .await
- .map_err(|e| Status::internal("storage not ready"))?;
-
- Ok(Response::new(CreateUserResponse { temp_id: id }))
- }
-
- #[doc = " Complete Profile"]
- async fn complete_profile(
- &self,
- request: Request<CompleteUserRequest>,
- ) -> Result<Response<User>, Status> {
- todo!()
- }
-}
diff --git a/crates/profile-service/Cargo.toml b/crates/users-service/Cargo.toml
index e56db3a..2bbfe28 100644
--- a/crates/profile-service/Cargo.toml
+++ b/crates/users-service/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "sellershut-profiles"
+name = "sellershut-users"
version = "0.1.0"
edition = "2024"
license.workspace = true
@@ -15,7 +15,7 @@ config = { workspace = true, features = ["convert-case", "toml"] }
futures-util.workspace = true
nanoid.workspace = true
prost.workspace = true
-sellershut-core = { workspace = true, features = ["profile", "serde"] }
+sellershut-core = { workspace = true, features = ["users", "serde"] }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
sqlx = { workspace = true, features = ["macros", "migrate", "runtime-tokio", "time", "tls-rustls", "uuid"] }
diff --git a/crates/profile-service/migrations/20250726161947_profile.sql b/crates/users-service/migrations/20250726161947_profile.sql
index 15822c8..15822c8 100644
--- a/crates/profile-service/migrations/20250726161947_profile.sql
+++ b/crates/users-service/migrations/20250726161947_profile.sql
diff --git a/crates/profile-service/src/cnfg.rs b/crates/users-service/src/cnfg.rs
index fec4cf7..fec4cf7 100644
--- a/crates/profile-service/src/cnfg.rs
+++ b/crates/users-service/src/cnfg.rs
diff --git a/crates/profile-service/src/main.rs b/crates/users-service/src/main.rs
index 5fe1331..218c74a 100644
--- a/crates/profile-service/src/main.rs
+++ b/crates/users-service/src/main.rs
@@ -4,7 +4,7 @@ mod state;
use std::net::{Ipv6Addr, SocketAddr};
use clap::Parser;
-use sellershut_core::profile::profile_server::ProfileServer;
+use sellershut_core::users::users_service_server::UsersServiceServer;
use stack_up::{Configuration, Services, tracing::Tracing};
use tokio::signal;
use tonic::transport::{Server, server::TcpIncoming};
@@ -27,7 +27,7 @@ struct Args {
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::parse();
- let config = include_str!("../profile.toml");
+ let config = include_str!("../users.toml");
let mut config = config::Config::builder()
.add_source(config::File::from_str(config, config::FileFormat::Toml));
@@ -61,7 +61,7 @@ async fn main() -> anyhow::Result<()> {
.take()
.ok_or_else(|| anyhow::anyhow!("cache is not ready"))?;
- let services = crate::state::Services { postgres, cache };
+ let services = crate::state::Services::new(postgres, cache);
let state = AppState::create(services, &config).await?;
@@ -73,8 +73,7 @@ async fn main() -> anyhow::Result<()> {
Server::builder()
.trace_fn(|_| tracing::info_span!(env!("CARGO_PKG_NAME")))
- // .add_service(QueryUsersServer::new(state.clone()))
- .add_service(ProfileServer::with_interceptor(
+ .add_service(UsersServiceServer::with_interceptor(
state.clone(),
MyInterceptor,
))
diff --git a/crates/profile-service/src/server.rs b/crates/users-service/src/server.rs
index b2e04f9..b2e04f9 100644
--- a/crates/profile-service/src/server.rs
+++ b/crates/users-service/src/server.rs
diff --git a/crates/profile-service/src/server/interceptor.rs b/crates/users-service/src/server/interceptor.rs
index 6fbe7fa..6fbe7fa 100644
--- a/crates/profile-service/src/server/interceptor.rs
+++ b/crates/users-service/src/server/interceptor.rs
diff --git a/crates/users-service/src/server/manager.rs b/crates/users-service/src/server/manager.rs
new file mode 100644
index 0000000..6affb4a
--- /dev/null
+++ b/crates/users-service/src/server/manager.rs
@@ -0,0 +1,85 @@
+use prost::Message;
+use sellershut_core::users::{
+ CompleteUserRequest, CreateUserRequest, CreateUserResponse, User,
+ users_service_server::UsersService,
+};
+use stack_up::redis::AsyncCommands;
+use tonic::{Request, Response, Status, async_trait};
+use tracing::{error, trace};
+use uuid::Uuid;
+
+use crate::state::AppHandle;
+
+#[async_trait]
+impl UsersService for AppHandle {
+ #[doc = " Create a new user profile"]
+ async fn create_user(
+ &self,
+ request: Request<CreateUserRequest>,
+ ) -> Result<Response<CreateUserResponse>, Status> {
+ trace!("creating user");
+ let data = request.into_inner();
+ let id = Uuid::now_v7().to_string();
+
+ let bytes = data.encode_to_vec();
+ let mut cache = self.cache().await?;
+ cache
+ .set_ex::<_, _, ()>(&id, &bytes, self.local_config.temp_ttl)
+ .await
+ .inspect_err(|e| error!("{e}"))
+ .map_err(|_e| Status::internal("storage not ready"))?;
+
+ Ok(Response::new(CreateUserResponse { temp_id: id }))
+ }
+
+ #[doc = " Complete Profile"]
+ async fn complete_user(
+ &self,
+ request: Request<CompleteUserRequest>,
+ ) -> Result<Response<User>, Status> {
+ let request = request.into_inner();
+
+ let mut cache = self.cache().await?;
+
+ let resp = cache
+ .get_del::<_, Vec<u8>>(&request.id)
+ .await
+ .inspect_err(|e| error!("{e}"))
+ .map_err(|_e| Status::internal("storage not ready"))?;
+
+ if resp.is_empty() {
+ return Err(Status::data_loss("user unavailable"));
+ }
+
+ let create_user = CreateUserRequest::decode(resp.as_ref())
+ .map_err(|_e| Status::data_loss("internal data corrupted"))?;
+
+ let user = sqlx::query!(
+ "insert
+ into
+ profile (
+ id,
+ username,
+ inbox,
+ outbox,
+ local,
+ avatar_url,
+ description,
+ user_type,
+ public_key
+ )
+ values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
+ ",
+ request.id,
+ request.username,
+ request.inbox,
+ request.outbox,
+ request.local,
+ request.avatar.or(create_user.avatar),
+ request.description,
+ request.user_type.to_string(),
+ request.public_key,
+ );
+ todo!()
+ }
+}
diff --git a/crates/profile-service/src/state.rs b/crates/users-service/src/state.rs
index 1ccfbfd..3f5ac7b 100644
--- a/crates/profile-service/src/state.rs
+++ b/crates/users-service/src/state.rs
@@ -1,7 +1,12 @@
use std::sync::Arc;
use sqlx::PgPool;
-use stack_up::{Configuration, cache::RedisManager};
+use stack_up::{
+ Configuration,
+ cache::{RedisConnection, RedisManager},
+};
+use tonic::Status;
+use tracing::error;
use crate::cnfg::LocalConfig;
@@ -22,6 +27,12 @@ pub struct Services {
pub cache: RedisManager,
}
+impl Services {
+ pub fn new(postgres: PgPool, cache: RedisManager) -> Self {
+ Self { postgres, cache }
+ }
+}
+
pub struct AppState {
pub services: Services,
pub local_config: LocalConfig,
@@ -39,4 +50,16 @@ impl AppState {
local_config,
})))
}
+
+ pub async fn cache(&self) -> Result<RedisConnection, tonic::Status> {
+ let cache = self
+ .services
+ .cache
+ .get()
+ .await
+ .inspect_err(|e| error!("{e}"))
+ .map_err(|_e| Status::internal("storage not ready"))?;
+
+ Ok(cache)
+ }
}
diff --git a/crates/profile-service/profile.toml b/crates/users-service/users.toml
index 13a5f0a..9706fcf 100644
--- a/crates/profile-service/profile.toml
+++ b/crates/users-service/users.toml
@@ -3,7 +3,7 @@ env = "development"
port = 1610
[monitoring]
-log-level = "sellershut_profiles=trace,info"
+log-level = "sellershut_users=trace,info"
[misc]
temp-ttl = 1000
diff --git a/lib/sellershut-core/Cargo.toml b/lib/sellershut-core/Cargo.toml
index 1b7d5f7..0be2ce7 100644
--- a/lib/sellershut-core/Cargo.toml
+++ b/lib/sellershut-core/Cargo.toml
@@ -18,7 +18,7 @@ tonic-types = "0.13.0"
[features]
default = []
auth = []
-profile = []
+users = []
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 13e3d06..ff57fec 100644
--- a/lib/sellershut-core/build.rs
+++ b/lib/sellershut-core/build.rs
@@ -1,12 +1,12 @@
-#[cfg(any(feature = "auth", feature = "profile"))]
+#[cfg(any(feature = "auth", feature = "users"))]
enum Entity {
#[cfg(feature = "auth")]
Auth,
- #[cfg(feature = "profile")]
- Profile,
+ #[cfg(feature = "users")]
+ User,
}
-#[cfg(any(feature = "auth", feature = "profile"))]
+#[cfg(any(feature = "auth", feature = "users"))]
impl Entity {
fn protos(&self) -> Vec<&'static str> {
let mut res: Vec<&'static str> = vec![];
@@ -16,9 +16,9 @@ impl Entity {
Entity::Auth => {
res.extend(vec!["proto/auth/auth.proto"]);
}
- #[cfg(feature = "profile")]
- Entity::Profile => {
- res.extend(vec!["proto/profile/profile.proto"]);
+ #[cfg(feature = "users")]
+ Entity::User => {
+ res.extend(vec!["proto/users/users.proto"]);
}
}
res
@@ -31,13 +31,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature = "auth")]
build_proto("auth", Entity::Auth);
- #[cfg(feature = "profile")]
- build_proto("profile", Entity::Profile);
+ #[cfg(feature = "users")]
+ build_proto("users", Entity::User);
Ok(())
}
-#[cfg(any(feature = "auth", feature = "profile"))]
+#[cfg(any(feature = "auth", feature = "users"))]
fn build_proto(package: &str, entity: Entity) {
let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
@@ -81,7 +81,7 @@ fn build_proto(package: &str, entity: Entity) {
.compile_protos(&entity.protos(), include_paths).unwrap();
}
-#[cfg(all(feature = "serde", any(feature = "auth", feature = "profile")))]
+#[cfg(all(feature = "serde", any(feature = "auth", feature = "users")))]
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/users/users.proto
index 61181b3..d1cf692 100644
--- a/lib/sellershut-core/proto/profile/profile.proto
+++ b/lib/sellershut-core/proto/users/users.proto
@@ -1,10 +1,18 @@
syntax = "proto3";
-package profile;
+package users;
import "google/protobuf/timestamp.proto";
-// A message representing a user profile
+enum UserType {
+ PERSON = 0;
+ APPLICATION = 1;
+ GROUP = 2;
+ ORGANIZATION = 3;
+ SERVICE = 4;
+}
+
+// A message representing a user user
message User {
// Unique identifier for the user
string id = 1;
@@ -20,9 +28,13 @@ message User {
google.protobuf.Timestamp updated_at = 6;
// User-provided description or bio
optional string description = 7;
+ // User type
+ UserType user_type = 8;
+ // Public key
+ string public_key = 9;
}
-// Request message for creating a new user profile
+// Request message for creating a new user
message CreateUserRequest {
// Email address of the new user
string email = 1;
@@ -36,22 +48,32 @@ message CreateUserResponse {
string temp_id = 1;
}
-// Message to finalise profile creation
+// Message to finalise user creation
message CompleteUserRequest {
// ID of the user to finalise
string id = 1;
- // Required: username to finalise the profile
+ // Required: username to finalise the user
string username = 2;
// Optional: user-provided description
optional string description = 3;
// Optional: update avatar
optional string avatar = 4;
+ // Inbox URL for this user
+ string inbox = 5;
+ // Outbox URL for this user
+ string outbox = 6;
+ // Is this user local or remote
+ bool local = 7;
+ // Public key for this user
+ string public_key = 8;
+ // User type
+ UserType user_type = 9;
}
-// Profile gRPC service
-service Profile {
- // Create a new user profile
+// Users gRPC service
+service UsersService {
+ // Create a new user
rpc CreateUser (CreateUserRequest) returns (CreateUserResponse);
- // Complete Profile
- rpc CompleteProfile (CompleteUserRequest) returns (User);
+ // Complete user
+ rpc CompleteUser (CompleteUserRequest) returns (User);
}
diff --git a/lib/sellershut-core/src/lib.rs b/lib/sellershut-core/src/lib.rs
index 70544cf..afbd20f 100644
--- a/lib/sellershut-core/src/lib.rs
+++ b/lib/sellershut-core/src/lib.rs
@@ -7,13 +7,13 @@
)]
/// Protobuf types
-#[cfg(any(feature = "auth", feature = "profile"))]
+#[cfg(any(feature = "auth", feature = "users"))]
pub mod google;
/// Interactions with Auth server
#[cfg(feature = "auth")]
pub mod auth;
-/// Interactions with Profile server
-#[cfg(feature = "profile")]
-pub mod profile;
+/// Interactions with user server
+#[cfg(feature = "users")]
+pub mod users;
diff --git a/lib/sellershut-core/src/profile.rs b/lib/sellershut-core/src/profile.rs
deleted file mode 100644
index 06484d9..0000000
--- a/lib/sellershut-core/src/profile.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-tonic::include_proto!("profile");
-/// Profile file descriptor
-pub const PROFILE_FILE_DESCRIPTOR_SET: &[u8] =
- tonic::include_file_descriptor_set!("profile_descriptor");
diff --git a/lib/sellershut-core/src/users.rs b/lib/sellershut-core/src/users.rs
new file mode 100644
index 0000000..5721d53
--- /dev/null
+++ b/lib/sellershut-core/src/users.rs
@@ -0,0 +1,36 @@
+tonic::include_proto!("users");
+/// Users file descriptor
+pub const USERS_FILE_DESCRIPTOR_SET: &[u8] =
+ tonic::include_file_descriptor_set!("users_descriptor");
+
+impl std::fmt::Display for UserType {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ UserType::Person => "person",
+ UserType::Application => "application",
+ UserType::Group => "group",
+ UserType::Organization => "organization",
+ UserType::Service => "service",
+ }
+ .to_uppercase()
+ )
+ }
+}
+
+impl std::str::FromStr for UserType {
+ type Err = String;
+
+ fn from_str(value: &str) -> Result<Self, Self::Err> {
+ match value.to_lowercase().as_str() {
+ "person" => Ok(Self::Person),
+ "application" => Ok(Self::Application),
+ "group" => Ok(Self::Group),
+ "organization" => Ok(Self::Organization),
+ "service" => Ok(Self::Service),
+ _ => Err(format!("invalid user type: {value}")),
+ }
+ }
+}