1
0
Fork 0
mirror of https://codeberg.org/tyy/aspm synced 2024-12-22 15:59:29 -07:00

Add basic profile create command, with debugging for now (doesn't actually create)

This commit is contained in:
Tyler Beckman 2024-02-19 23:03:57 -07:00
parent b545ffe364
commit 1eff198141
Signed by: Ty
GPG key ID: 2813440C772555A4
6 changed files with 118 additions and 5 deletions

View file

@ -16,5 +16,6 @@
"subkeys",
"userid",
"writedoc"
]
],
"rust-analyzer.check.command": "clippy"
}

View file

@ -1,7 +1,7 @@
use hex_color::HexColor;
pub use hex_color::HexColor;
use serde::{Deserialize, Serialize};
use serde_email::Email;
use url::Url;
pub use serde_email::Email;
pub use url::Url;
use crate::utils::jwt::{AspJwsType, JwtSerializable};

View file

@ -1,4 +1,5 @@
pub mod keys;
pub mod profiles;
use clap::Parser;
use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, QueryFilter, QueryOrder};

View file

@ -0,0 +1,92 @@
use std::str::FromStr;
use anyhow::Context;
use asp::{profiles::*, utils::jwt::AspJwsType};
use clap::Parser;
use dialoguer::{theme::ColorfulTheme, Input};
use crate::commands::AspmSubcommand;
/// Creates a new profile containing claims and other metadata.
/// A key is needed to attach this profile to, but multiple profiles can be created for the same key.
#[derive(Parser, Debug)]
pub struct ProfilesCreateCommand {
/// The alias of the profile to create. This can be anything, and it can also be omitted to prompt interactively.
/// This has no purpose other than providing a way to nicely distinguish profiles.
#[arg(short = 'n', long)]
profile_alias: Option<String>,
}
#[async_trait::async_trait]
impl AspmSubcommand for ProfilesCreateCommand {
async fn execute(&self, state: crate::AspmState) -> Result<(), anyhow::Error> {
let theme = ColorfulTheme::default();
let alias = if let Some(alias) = &self.profile_alias {
alias.clone()
} else {
Input::with_theme(&theme)
.with_prompt("Please enter an alias to give to this profile")
.allow_empty(false)
.interact()
.context("Unable to prompt on stderr")?
};
let profile = AriadneSignatureProfile {
version: 0,
r#type: AspJwsType::Profile,
name: Input::with_theme(&theme)
.with_prompt("Please enter a public name to show on this profile (usually a username or real name, though anything works)")
.allow_empty(false)
.interact()
.context("Unable to prompt on stderr")?,
claims: {
let mut claims = Vec::<String>::new();
loop {
let claim: String = Input::with_theme(&theme)
.with_prompt("Please enter a claim and then press enter. To finish, enter an empty string")
.allow_empty(true)
.interact()
.context("Unable to prompt on stderr")?;
if claim.is_empty() {
break
} else {
claims.push(claim);
}
}
claims
},
description: Some(Input::with_theme(&theme)
.with_prompt("If you want to add a description to this profile, enter it or an empty string")
.allow_empty(true)
.interact()
.context("Unable to prompt on stderr")?).filter(|x: &String| !x.is_empty()),
avatar_url: Some(Input::with_theme(&theme)
.with_prompt("If you want to add an avatar to this profile, enter the URL or an empty string")
.allow_empty(true)
.interact()
.context("Unable to prompt on stderr")?)
.filter(|x: &String| !x.is_empty())
.map_or(Ok(None), |string: String| Url::parse(&string).context("Unable to parse avatar URL").map(|url| Some(url)))?,
email: Some(Input::with_theme(&theme)
.with_prompt("If you want to add an email to this profile, enter it or an empty string")
.allow_empty(true)
.interact()
.context("Unable to prompt on stderr")?)
.filter(|x: &String| !x.is_empty())
.map_or(Ok(None), |string: String| Email::from_string(string).context("Unable to parse email").map(|email| Some(email)))?,
color: Some(Input::with_theme(&theme)
.with_prompt("If you want to add a color to this profile, enter it in hex format (#AABBCC) or an empty string")
.allow_empty(true)
.interact()
.context("Unable to prompt on stderr")?)
.filter(|x: &String| !x.is_empty())
.map_or(Ok(None), |hex: String| HexColor::from_str(&hex).context("Unable to parse color code").map(|color| Some(color)))?,
};
dbg!(profile);
Ok(())
}
}

View file

@ -0,0 +1,15 @@
use clap::{Parser, Subcommand};
pub mod create;
/// A subcommand to allow the management of keys, which can then be used to create, modify, or delete profiles.
#[derive(Parser)]
pub struct ProfilesSubcommand {
#[command(subcommand)]
pub subcommand: ProfilesSubcommands,
}
#[derive(Subcommand)]
pub enum ProfilesSubcommands {
Create(create::ProfilesCreateCommand),
}

View file

@ -6,7 +6,7 @@ use anstyle::{AnsiColor, Color as AnstyleColor, Style as Anstyle};
use anyhow::Context;
use app_dirs2::{AppDataType, AppInfo};
use clap::{Parser, Subcommand};
use commands::{keys::KeysSubcommands, AspmSubcommand};
use commands::{keys::KeysSubcommands, profiles::ProfilesSubcommands, AspmSubcommand};
use migrations::{Migrator, MigratorTrait, SchemaManager};
use sea_orm::{Database, DatabaseConnection};
use thiserror::Error;
@ -77,6 +77,7 @@ impl AspmCommand {
#[derive(Subcommand)]
pub enum AspmSubcommands {
Keys(commands::keys::KeysSubcommand),
Profiles(commands::profiles::ProfilesSubcommand),
}
fn main() {
@ -151,6 +152,9 @@ fn cli(parsed: AspmCommand) -> Result<(), anyhow::Error> {
KeysSubcommands::Delete(subcommand) => subcommand.execute_sync(state, runtime),
KeysSubcommands::Import(subcommand) => subcommand.execute_sync(state, runtime),
},
AspmSubcommands::Profiles(subcommand) => match &subcommand.subcommand {
ProfilesSubcommands::Create(subcommand) => subcommand.execute_sync(state, runtime),
},
}
}