Skip to content

Commit

Permalink
feat(rust)!: Update the NpProfile struct to make ORCID and name opt…
Browse files Browse the repository at this point in the history
…ional, and use the builder pattern to build a profile. Remove dependency on serde_yaml (YAML profile file parsed manually)
  • Loading branch information
vemonet committed Apr 19, 2024
1 parent 6b0c599 commit c3e30fa
Show file tree
Hide file tree
Showing 18 changed files with 350 additions and 204 deletions.
27 changes: 13 additions & 14 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::{arg, value_parser, Command};
use clap_complete::{generate, Generator, Shell};
use nanopub::{error::NpError, get_np_server, Nanopub, NpProfile};
use nanopub::{error::NpError, get_np_server, Nanopub, ProfileBuilder};
use std::{error::Error, fs, io, path::Path};

// https://github.com/clap-rs/clap/blob/master/examples/git.rs
Expand Down Expand Up @@ -60,18 +60,17 @@ async fn main() -> Result<(), Box<dyn Error>> {

match matches.subcommand() {
Some(("sign", sub)) => {
let orcid = "http://orcid.org/0000-0000-0000-0000";
let np_file = sub.get_one::<String>("NANOPUB_FILE").expect("required");
let key_file = sub.get_one::<String>("key").unwrap();
let profile_file = sub.get_one::<String>("profile").unwrap();

// Read RDF from file, and get profile from YAML file or key
let np_rdf = fs::read_to_string(np_file)?;
let profile = if !key_file.is_empty() {
let private_key = fs::read_to_string(key_file)?;
NpProfile::new(&private_key, orcid, "", None)?
let privkey = fs::read_to_string(key_file)?;
ProfileBuilder::new(privkey).build()?
} else {
NpProfile::from_file(profile_file)?
ProfileBuilder::from_file(profile_file)?
};
println!("✍️ Signing {}", np_file);
let np = Nanopub::new(&np_rdf)?.sign(&profile)?;
Expand All @@ -82,21 +81,21 @@ async fn main() -> Result<(), Box<dyn Error>> {
let parent = path.parent().unwrap_or_else(|| Path::new(""));
let file_name = path
.file_name()
.ok_or_else(|| NpError("Error getting filename".to_string()))?
.ok_or_else(|| NpError(format!("Error getting filename from {:?}", path)))?
.to_str()
.ok_or_else(|| NpError("Error getting filename".to_string()))?;
.ok_or_else(|| NpError(format!("Error getting filename from {:?}", path)))?;
let new_file_name = format!("signed.{}", file_name);
let signed_path = parent.join(new_file_name);
println!(
"📁 Signed Nanopub stored to {}",
signed_path
.to_str()
.ok_or_else(|| NpError("Error getting signed path".to_string()))?
signed_path.to_str().ok_or_else(|| NpError(format!(
"Error getting signed path {:?}",
signed_path
)))?
);
let _ = fs::write(signed_path, np.rdf()?);
}
Some(("publish", sub)) => {
let orcid = "http://orcid.org/0000-0000-0000-0000";
let np_file = sub.get_one::<String>("NANOPUB_FILE").expect("required");
let key_file = sub.get_one::<String>("key").unwrap();
let profile_file = sub.get_one::<String>("profile").unwrap();
Expand All @@ -105,10 +104,10 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Read RDF from file, and get profile from YAML file or key
let np_rdf = fs::read_to_string(np_file)?;
let profile = if !key_file.is_empty() {
let private_key = fs::read_to_string(key_file)?;
NpProfile::new(&private_key, orcid, "", None)?
let privkey = fs::read_to_string(key_file)?;
ProfileBuilder::new(privkey).build()?
} else {
NpProfile::from_file(profile_file)?
ProfileBuilder::from_file(profile_file)?
};
if test_server {
println!("🧪 Publishing {np_file} to test server");
Expand Down
72 changes: 37 additions & 35 deletions cliff.toml
Original file line number Diff line number Diff line change
@@ -1,39 +1,7 @@
[changelog]
header = """
# 📜 Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# Template for the changelog: https://keats.github.io/tera/docs
body = """
{% if version %}\
{% if previous.version %}\
## [{{ version | trim_start_matches(pat="v") }}](<REPO>/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [{{ version | trim_start_matches(pat="v") }}](<REPO>/tree/{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
{% endif %}\
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first | trim }} - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }}))\
{% endfor %}
{% endfor %}\n
"""
trim = true
footer = """
<!-- generated by git-cliff -->
"""
postprocessors = [
{ pattern = '<REPO>', replace = "https://github.com/vemonet/nanopub-rs" },
]
[git]
# https://www.conventionalcommits.org
# Example breaking change commit in python API: `feat(python)!: changed everything`
conventional_commits = true
filter_unconventional = false
split_commits = false
# NOTE: Add an exclamation mark in your commit message prefix to indicate a BREAKING change
# e.g. `feat!: changed things` or `feat(python)!: changed things`
# More details about the standard at https://www.conventionalcommits.org
commit_parsers = [
{ message = "^feat", group = "⛰️ Features" },
{ message = "^fix", group = "🐛 Bug Fixes" },
Expand All @@ -51,6 +19,9 @@ commit_parsers = [
{ body = ".*security", group = "🛡️ Security" },
{ message = "^revert", group = "◀️ Revert" },
]
conventional_commits = true
filter_unconventional = false
split_commits = false
# Protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
filter_commits = false
Expand All @@ -67,3 +38,34 @@ sort_commits = "oldest"
# commit_preprocessors = [
# # { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, # replace issue numbers
# ]

[changelog]
header = """
# 📜 Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# Template for the changelog: https://keats.github.io/tera/docs
body = """
{% if version %}\
{% if previous.version %}\
## [{{ version | trim_start_matches(pat="v") }}](<REPO>/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [{{ version | trim_start_matches(pat="v") }}](<REPO>/tree/{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
{% endif %}\
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first | trim }} - ([{{ commit.id | truncate(length=7, end="") }}](<REPO>/commit/{{ commit.id }}))\
{% endfor %}
{% endfor %}\n
"""
trim = true
footer = """
<!-- generated by git-cliff -->
"""
postprocessors = [
{ pattern = '<REPO>', replace = "https://github.com/vemonet/nanopub-rs" },
]
33 changes: 20 additions & 13 deletions js/src/nanopub.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use js_sys::{Promise, JSON};
use nanopub::{
constants::TEST_SERVER, get_np_server as get_server, profile::gen_keys, Nanopub as RsNanopub,
NpProfile as RsNpProfile,
NpProfile as RsNpProfile, ProfileBuilder,
};
use serde::Serialize;
use wasm_bindgen::prelude::*;
Expand Down Expand Up @@ -158,19 +158,26 @@ extern "C" {
impl NpProfile {
#[wasm_bindgen(constructor)]
pub fn new(
private_key: &str,
orcid_id: &str,
name: &str,
introduction_nanopub_uri: &str,
private_key: String,
orcid_id: Option<String>,
name: Option<String>,
introduction_nanopub_uri: Option<String>,
) -> Result<NpProfile, JsValue> {
RsNpProfile::new(
private_key,
orcid_id,
name,
Some(introduction_nanopub_uri.to_string()),
)
.map(|profile: RsNpProfile| Self { profile })
.map_err(|e| JsValue::from_str(&e.to_string()))
let mut profile = ProfileBuilder::new(private_key);
if let Some(orcid_id) = orcid_id {
profile = profile.with_orcid(orcid_id);
};
if let Some(name) = name {
profile = profile.with_name(name);
};
if let Some(intro_np_uri) = introduction_nanopub_uri {
profile = profile.with_intro_nanopub(intro_np_uri);
};
Ok(Self {
profile: profile
.build()
.map_err(|e| JsValue::from_str(&e.to_string()))?,
})
}
// TODO: create from profile.yml file?

Expand Down
2 changes: 1 addition & 1 deletion js/tests/nanopub.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Tests for the @nanopub/sign npm package', () => {
// NOTE: `await init()` only needed in browser environment

test('publish nanopub', async () => {
const profile = new NpProfile(privKey, orcid, "Your Name", "");
const profile = new NpProfile(privKey, orcid, "Your Name");
const np = await new Nanopub(unsignedRdf).publish(profile);

// console.log("Published Nanopub:", np.info());
Expand Down
1 change: 0 additions & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ openssl-probe = "0.1"
sophia = { version = "0.8.0", features = ["jsonld"] }
regex = "1.10"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
chrono = "0.4.35"
getrandom = { version = "0.2", features = ["js"] }
rand_core = { version = "0.6", features = ["std"] }
Expand Down
4 changes: 2 additions & 2 deletions lib/docs/docs/javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ const rdfStr = `@prefix : <http://purl.org/nanopub/temp/mynanopub#> .
}`
const privateKey=`MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc=`;

// Instantiate Nanopub profile
const profile = new NpProfile(privateKey, "https://orcid.org/0000-0000-0000-0000", "Your Name", "");
// Instantiate Nanopub profile (ORCID and name are optional)
const profile = new NpProfile(privateKey, "https://orcid.org/0000-0000-0000-0000", "Your Name");

// Sign the Nanopub RDF
const signed = new Nanopub(rdfStr).sign(profile);
Expand Down
4 changes: 1 addition & 3 deletions lib/docs/docs/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,11 @@ rdf_str = """@prefix : <http://purl.org/nanopub/temp/mynanopub#> .
}"""
private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc="

# Instantiate a nanopub profile
# Instantiate a nanopub profile (ORCID and name are optional)
profile = NpProfile(
private_key=private_key,
orcid_id="https://orcid.org/0000-0000-0000-0000",
name="Your Name",
introduction_nanopub_uri=""
)

# Sign a nanopub
Expand Down Expand Up @@ -152,7 +151,6 @@ new_profile = NpProfile(
private_key=keypair.private,
orcid_id="https://orcid.org/0000-0000-0000-0000",
name="Your Name",
introduction_nanopub_uri=""
)

# Publish a nanopub introduction for this profile
Expand Down
Loading

0 comments on commit c3e30fa

Please sign in to comment.