//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vtc/groups/show`. Version: `0.1`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///A dynamic group's membership rule: a member belongs when every condition holds and they have not opted out. The community evaluates it under its `groups` policy and recomputes membership whenever a fact it reads changes, always excluding opted-out entries.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DynamicRule",
/// "description": "A dynamic group's membership rule: a member belongs when every condition holds and they have not opted out. The community evaluates it under its `groups` policy and recomputes membership whenever a fact it reads changes, always excluding opted-out entries.",
/// "type": "object",
/// "required": [
/// "all"
/// ],
/// "properties": {
/// "all": {
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/RuleCondition"
/// },
/// "maxItems": 16,
/// "minItems": 1
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DynamicRule {
pub all: ::std::vec::Vec<RuleCondition>,
}
impl DynamicRule {
pub fn builder() -> builder::DynamicRule {
Default::default()
}
}
///Opaque identifier of one directory entry: `dir_` followed by 16 to 64 base64url characters. Random, scoped to one community, and stable for the life of the membership — it survives a rotation of the member's DID, which is why groups, notes and cards are keyed by it. It MUST NOT be derived from, and MUST NOT reveal, any DID of the member, and the same person's entries in two communities MUST NOT share one. Compared by exact string equality.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "EntryId",
/// "description": "Opaque identifier of one directory entry: `dir_` followed by 16 to 64 base64url characters. Random, scoped to one community, and stable for the life of the membership — it survives a rotation of the member's DID, which is why groups, notes and cards are keyed by it. It MUST NOT be derived from, and MUST NOT reveal, any DID of the member, and the same person's entries in two communities MUST NOT share one. Compared by exact string equality.",
/// "type": "string",
/// "pattern": "^dir_[A-Za-z0-9_-]{16,64}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct EntryId(::std::string::String);
impl ::std::ops::Deref for EntryId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<EntryId> for ::std::string::String {
fn from(value: EntryId) -> Self {
value.0
}
}
impl ::std::str::FromStr for EntryId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^dir_[A-Za-z0-9_-]{16,64}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^dir_[A-Za-z0-9_-]{16,64}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for EntryId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for EntryId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for EntryId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for EntryId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Identifier of a directory field. A key with no `.` is a BASE field, the same in every community: `displayName`, `nickname`, `avatar`, `pronouns`, `bio`, `links` (written by the member) and `role`, `joinedAt`, `did`, `personhood` (derived from the community's own records, never stored on a card). A community-defined field MUST use a reverse-DNS key (`org.example.employer`), so a base key never collides with one, and a key is never reused with a different meaning once defined.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "FieldKey",
/// "description": "Identifier of a directory field. A key with no `.` is a BASE field, the same in every community: `displayName`, `nickname`, `avatar`, `pronouns`, `bio`, `links` (written by the member) and `role`, `joinedAt`, `did`, `personhood` (derived from the community's own records, never stored on a card). A community-defined field MUST use a reverse-DNS key (`org.example.employer`), so a base key never collides with one, and a key is never reused with a different meaning once defined.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^([a-z][a-z0-9-]*\\.)*[a-z][a-zA-Z0-9]{0,63}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct FieldKey(::std::string::String);
impl ::std::ops::Deref for FieldKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<FieldKey> for ::std::string::String {
fn from(value: FieldKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for FieldKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^([a-z][a-z0-9-]*\\.)*[a-z][a-zA-Z0-9]{0,63}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^([a-z][a-z0-9-]*\\.)*[a-z][a-zA-Z0-9]{0,63}$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for FieldKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for FieldKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for FieldKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for FieldKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A community group, as a caller who may see it sees it. Members a caller may not see are absent: `memberCount` only to those who may see the group's members, `managers` and `credentialAuthorityValidUntil` only to its managers.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Group",
/// "description": "A community group, as a caller who may see it sees it. Members a caller may not see are absent: `memberCount` only to those who may see the group's members, `managers` and `credentialAuthorityValidUntil` only to its managers.",
/// "type": "object",
/// "required": [
/// "carriesAuthority",
/// "createdAt",
/// "groupDid",
/// "groupId",
/// "issuesCredentials",
/// "kind",
/// "name",
/// "showMembers",
/// "visibility"
/// ],
/// "properties": {
/// "carriesAuthority": {
/// "description": "`true` while the group has a `grants` or `role` binding. Such a group is `static` and `closed` for as long as it does.",
/// "type": "boolean"
/// },
/// "createdAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "createdBy": {
/// "description": "The creating administrator's directory entry, where they have one.",
/// "$ref": "#/definitions/EntryId"
/// },
/// "credentialAuthorityValidUntil": {
/// "description": "When the community's authorization credential to the group expires. The community renews it well before.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "description": {
/// "$ref": "#/definitions/GroupDescription"
/// },
/// "ext": {
/// "description": "Ecosystem-defined extension members per SPEC.md §4.5.1. An extension member MUST NOT carry authority.",
/// "$ref": "#/definitions/Ext"
/// },
/// "groupDid": {
/// "description": "The group's own DID, minted by the community's VTA for this group alone. It issues the group's membership credentials. Its DID document carries no name or description.",
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:"
/// },
/// "groupId": {
/// "$ref": "#/definitions/GroupId"
/// },
/// "issuesCredentials": {
/// "description": "Whether the group's DID issues its members a membership credential. Default true.",
/// "type": "boolean"
/// },
/// "joinPolicy": {
/// "description": "Present exactly when `kind` is `static`.",
/// "$ref": "#/definitions/JoinPolicy"
/// },
/// "kind": {
/// "$ref": "#/definitions/GroupKind"
/// },
/// "managers": {
/// "description": "Entries holding `vtc.groups.manage` qualified to this group, read from the access-control list. Informational: managers are appointed by an access-control grant (vtc/groups/managers/add), never by this record.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/EntryId"
/// },
/// "maxItems": 256,
/// "uniqueItems": true
/// },
/// "memberCount": {
/// "description": "Active members. Only to callers who may see the member list.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "name": {
/// "$ref": "#/definitions/GroupName"
/// },
/// "rule": {
/// "description": "Present exactly when `kind` is `dynamic`.",
/// "$ref": "#/definitions/DynamicRule"
/// },
/// "showMembers": {
/// "description": "Who may see the group's member list. Separate from `visibility`: a group everyone sees may show its members only to administrators. Never wider than `visibility`.",
/// "$ref": "#/definitions/GroupAudience"
/// },
/// "updatedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "visibility": {
/// "description": "Who may see that the group exists, and its name and description.",
/// "$ref": "#/definitions/GroupAudience"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Group {
///`true` while the group has a `grants` or `role` binding. Such a group is `static` and `closed` for as long as it does.
#[serde(rename = "carriesAuthority")]
pub carries_authority: bool,
#[serde(rename = "createdAt")]
pub created_at: ::chrono::DateTime<::chrono::offset::Utc>,
///The creating administrator's directory entry, where they have one.
#[serde(
rename = "createdBy",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub created_by: ::std::option::Option<EntryId>,
///When the community's authorization credential to the group expires. The community renews it well before.
#[serde(
rename = "credentialAuthorityValidUntil",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub credential_authority_valid_until:
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<GroupDescription>,
///Ecosystem-defined extension members per SPEC.md §4.5.1. An extension member MUST NOT carry authority.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The group's own DID, minted by the community's VTA for this group alone. It issues the group's membership credentials. Its DID document carries no name or description.
#[serde(rename = "groupDid")]
pub group_did: GroupGroupDid,
#[serde(rename = "groupId")]
pub group_id: GroupId,
///Whether the group's DID issues its members a membership credential. Default true.
#[serde(rename = "issuesCredentials")]
pub issues_credentials: bool,
///Present exactly when `kind` is `static`.
#[serde(
rename = "joinPolicy",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub join_policy: ::std::option::Option<JoinPolicy>,
pub kind: GroupKind,
///Entries holding `vtc.groups.manage` qualified to this group, read from the access-control list. Informational: managers are appointed by an access-control grant (vtc/groups/managers/add), never by this record.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub managers: ::std::option::Option<Vec<EntryId>>,
///Active members. Only to callers who may see the member list.
#[serde(
rename = "memberCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub member_count: ::std::option::Option<u64>,
pub name: GroupName,
///Present exactly when `kind` is `dynamic`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub rule: ::std::option::Option<DynamicRule>,
///Who may see the group's member list. Separate from `visibility`: a group everyone sees may show its members only to administrators. Never wider than `visibility`.
#[serde(rename = "showMembers")]
pub show_members: GroupAudience,
#[serde(
rename = "updatedAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub updated_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///Who may see that the group exists, and its name and description.
pub visibility: GroupAudience,
}
impl Group {
pub fn builder() -> builder::Group {
Default::default()
}
}
///Who may see something about a group, narrowest first. `admins`: holders of `vtc.groups.manage` for the group (unqualified, or qualified `group:<groupId>`). `groupMembers`: the group's own members, and its managers. `members`: every active member of the community.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GroupAudience",
/// "description": "Who may see something about a group, narrowest first. `admins`: holders of `vtc.groups.manage` for the group (unqualified, or qualified `group:<groupId>`). `groupMembers`: the group's own members, and its managers. `members`: every active member of the community.",
/// "type": "string",
/// "enum": [
/// "admins",
/// "groupMembers",
/// "members"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum GroupAudience {
#[serde(rename = "admins")]
Admins,
#[serde(rename = "groupMembers")]
GroupMembers,
#[serde(rename = "members")]
Members,
}
impl ::std::fmt::Display for GroupAudience {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Admins => f.write_str("admins"),
Self::GroupMembers => f.write_str("groupMembers"),
Self::Members => f.write_str("members"),
}
}
}
impl ::std::str::FromStr for GroupAudience {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"admins" => Ok(Self::Admins),
"groupMembers" => Ok(Self::GroupMembers),
"members" => Ok(Self::Members),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for GroupAudience {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for GroupAudience {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for GroupAudience {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///What the group is for. Plain text; a reader MUST NOT treat it as instructions. Same placement rules as `GroupName`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GroupDescription",
/// "description": "What the group is for. Plain text; a reader MUST NOT treat it as instructions. Same placement rules as `GroupName`.",
/// "type": "string",
/// "maxLength": 1000,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct GroupDescription(::std::string::String);
impl ::std::ops::Deref for GroupDescription {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<GroupDescription> for ::std::string::String {
fn from(value: GroupDescription) -> Self {
value.0
}
}
impl ::std::str::FromStr for GroupDescription {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1000usize {
return Err("longer than 1000 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for GroupDescription {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for GroupDescription {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for GroupDescription {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for GroupDescription {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The group's own DID, minted by the community's VTA for this group alone. It issues the group's membership credentials. Its DID document carries no name or description.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The group's own DID, minted by the community's VTA for this group alone. It issues the group's membership credentials. Its DID document carries no name or description.",
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct GroupGroupDid(::std::string::String);
impl ::std::ops::Deref for GroupGroupDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<GroupGroupDid> for ::std::string::String {
fn from(value: GroupGroupDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for GroupGroupDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for GroupGroupDid {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for GroupGroupDid {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for GroupGroupDid {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for GroupGroupDid {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Opaque identifier of a community group: `grp_` followed by 16 to 64 base64url characters. Random and community-scoped; not the group's DID.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GroupId",
/// "description": "Opaque identifier of a community group: `grp_` followed by 16 to 64 base64url characters. Random and community-scoped; not the group's DID.",
/// "type": "string",
/// "pattern": "^grp_[A-Za-z0-9_-]{16,64}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct GroupId(::std::string::String);
impl ::std::ops::Deref for GroupId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<GroupId> for ::std::string::String {
fn from(value: GroupId) -> Self {
value.0
}
}
impl ::std::str::FromStr for GroupId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^grp_[A-Za-z0-9_-]{16,64}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^grp_[A-Za-z0-9_-]{16,64}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for GroupId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for GroupId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for GroupId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for GroupId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`static`: membership is explicit — added, joined, or granted on request. `dynamic`: membership is computed from `rule` over verified facts only; nobody is added by hand, but a member may opt out (vtc/groups/leave), an exclusion the rule cannot override, and undo it (vtc/groups/join). A dynamic group never confers authority. Fixed for the group's life.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GroupKind",
/// "description": "`static`: membership is explicit — added, joined, or granted on request. `dynamic`: membership is computed from `rule` over verified facts only; nobody is added by hand, but a member may opt out (vtc/groups/leave), an exclusion the rule cannot override, and undo it (vtc/groups/join). A dynamic group never confers authority. Fixed for the group's life.",
/// "type": "string",
/// "enum": [
/// "static",
/// "dynamic"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum GroupKind {
#[serde(rename = "static")]
Static,
#[serde(rename = "dynamic")]
Dynamic,
}
impl ::std::fmt::Display for GroupKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Static => f.write_str("static"),
Self::Dynamic => f.write_str("dynamic"),
}
}
}
impl ::std::str::FromStr for GroupKind {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"static" => Ok(Self::Static),
"dynamic" => Ok(Self::Dynamic),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for GroupKind {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for GroupKind {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for GroupKind {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///The group's name, shown to those who may see the group. The community's own record: never in the group's DID document or its credentials' subject beyond the group's DID. Plain text.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GroupName",
/// "description": "The group's name, shown to those who may see the group. The community's own record: never in the group's DID document or its credentials' subject beyond the group's DID. Plain text.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct GroupName(::std::string::String);
impl ::std::ops::Deref for GroupName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<GroupName> for ::std::string::String {
fn from(value: GroupName) -> Self {
value.0
}
}
impl ::std::str::FromStr for GroupName {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for GroupName {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for GroupName {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for GroupName {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for GroupName {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///How a member enters a static group by themselves. `closed`: only a manager adds them. `request`: a member asks and a manager decides. `open`: a member joins at once, subject to the community's `groups` policy. A group carrying authority is always `closed`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "JoinPolicy",
/// "description": "How a member enters a static group by themselves. `closed`: only a manager adds them. `request`: a member asks and a manager decides. `open`: a member joins at once, subject to the community's `groups` policy. A group carrying authority is always `closed`.",
/// "type": "string",
/// "enum": [
/// "closed",
/// "request",
/// "open"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum JoinPolicy {
#[serde(rename = "closed")]
Closed,
#[serde(rename = "request")]
Request,
#[serde(rename = "open")]
Open,
}
impl ::std::fmt::Display for JoinPolicy {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Closed => f.write_str("closed"),
Self::Request => f.write_str("request"),
Self::Open => f.write_str("open"),
}
}
}
impl ::std::str::FromStr for JoinPolicy {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"closed" => Ok(Self::Closed),
"request" => Ok(Self::Request),
"open" => Ok(Self::Open),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for JoinPolicy {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for JoinPolicy {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for JoinPolicy {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Read one community group the caller may see: its DID, name, kind, policies and, where permitted, its member count and managers. The outer document members are owned by the framework — SPEC §6.3.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vtc/groups/show/0.1",
/// "title": "Payload",
/// "description": "Read one community group the caller may see: its DID, name, kind, policies and, where permitted, its member count and managers. The outer document members are owned by the framework — SPEC §6.3.",
/// "type": "object",
/// "required": [
/// "groupId"
/// ],
/// "properties": {
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "groupId": {
/// "$ref": "#/definitions/GroupId"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
#[serde(rename = "groupId")]
pub group_id: GroupId,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///The success response to a vtc/groups/show/0.1 request. Carried in a Trust Task document whose type is https://trusttasks.org/spec/vtc/groups/show/0.1#response.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "The success response to a vtc/groups/show/0.1 request. Carried in a Trust Task document whose type is https://trusttasks.org/spec/vtc/groups/show/0.1#response.",
/// "type": "object",
/// "required": [
/// "group",
/// "myMembership"
/// ],
/// "properties": {
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "group": {
/// "$ref": "#/definitions/Group"
/// },
/// "myMembership": {
/// "type": "string",
/// "enum": [
/// "member",
/// "pending",
/// "requested",
/// "optedOut",
/// "none"
/// ]
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
pub group: Group,
#[serde(rename = "myMembership")]
pub my_membership: ResponseMyMembership,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///`ResponseMyMembership`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "member",
/// "pending",
/// "requested",
/// "optedOut",
/// "none"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ResponseMyMembership {
#[serde(rename = "member")]
Member,
#[serde(rename = "pending")]
Pending,
#[serde(rename = "requested")]
Requested,
#[serde(rename = "optedOut")]
OptedOut,
#[serde(rename = "none")]
None,
}
impl ::std::fmt::Display for ResponseMyMembership {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Member => f.write_str("member"),
Self::Pending => f.write_str("pending"),
Self::Requested => f.write_str("requested"),
Self::OptedOut => f.write_str("optedOut"),
Self::None => f.write_str("none"),
}
}
}
impl ::std::str::FromStr for ResponseMyMembership {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"member" => Ok(Self::Member),
"pending" => Ok(Self::Pending),
"requested" => Ok(Self::Requested),
"optedOut" => Ok(Self::OptedOut),
"none" => Ok(Self::None),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ResponseMyMembership {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseMyMembership {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseMyMembership {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///One test over a verified fact about a member. `fact: role` tests the member's community role; `fact: field` tests an `admin`- or `credential`-sourced directory field named by `field`; `fact: personhood` tests whether a personhood assertion is on file; `fact: joinedAt` tests when they joined. A rule never reads a self-asserted (`member`-sourced) field: a member must not be able to join a group by editing their card.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "RuleCondition",
/// "description": "One test over a verified fact about a member. `fact: role` tests the member's community role; `fact: field` tests an `admin`- or `credential`-sourced directory field named by `field`; `fact: personhood` tests whether a personhood assertion is on file; `fact: joinedAt` tests when they joined. A rule never reads a self-asserted (`member`-sourced) field: a member must not be able to join a group by editing their card.",
/// "type": "object",
/// "required": [
/// "fact",
/// "op"
/// ],
/// "properties": {
/// "fact": {
/// "type": "string",
/// "enum": [
/// "role",
/// "field",
/// "personhood",
/// "joinedAt"
/// ]
/// },
/// "field": {
/// "description": "Present exactly when `fact` is `field`.",
/// "$ref": "#/definitions/FieldKey"
/// },
/// "op": {
/// "description": "`equals` compares with `value`; `oneOf` with any of `values`; `exists` needs neither; `before` and `after` compare a date fact with `value`.",
/// "type": "string",
/// "enum": [
/// "equals",
/// "oneOf",
/// "exists",
/// "before",
/// "after"
/// ]
/// },
/// "value": {
/// "anyOf": [
/// {
/// "type": "string",
/// "maxLength": 256
/// },
/// {
/// "type": "boolean"
/// }
/// ]
/// },
/// "values": {
/// "type": "array",
/// "items": {
/// "type": "string",
/// "maxLength": 256
/// },
/// "maxItems": 64,
/// "minItems": 1
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct RuleCondition {
pub fact: RuleConditionFact,
///Present exactly when `fact` is `field`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub field: ::std::option::Option<FieldKey>,
///`equals` compares with `value`; `oneOf` with any of `values`; `exists` needs neither; `before` and `after` compare a date fact with `value`.
pub op: RuleConditionOp,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub value: ::std::option::Option<RuleConditionValue>,
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub values: ::std::vec::Vec<RuleConditionValuesItem>,
}
impl RuleCondition {
pub fn builder() -> builder::RuleCondition {
Default::default()
}
}
///`RuleConditionFact`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "role",
/// "field",
/// "personhood",
/// "joinedAt"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum RuleConditionFact {
#[serde(rename = "role")]
Role,
#[serde(rename = "field")]
Field,
#[serde(rename = "personhood")]
Personhood,
#[serde(rename = "joinedAt")]
JoinedAt,
}
impl ::std::fmt::Display for RuleConditionFact {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Role => f.write_str("role"),
Self::Field => f.write_str("field"),
Self::Personhood => f.write_str("personhood"),
Self::JoinedAt => f.write_str("joinedAt"),
}
}
}
impl ::std::str::FromStr for RuleConditionFact {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"role" => Ok(Self::Role),
"field" => Ok(Self::Field),
"personhood" => Ok(Self::Personhood),
"joinedAt" => Ok(Self::JoinedAt),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for RuleConditionFact {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for RuleConditionFact {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for RuleConditionFact {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`equals` compares with `value`; `oneOf` with any of `values`; `exists` needs neither; `before` and `after` compare a date fact with `value`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`equals` compares with `value`; `oneOf` with any of `values`; `exists` needs neither; `before` and `after` compare a date fact with `value`.",
/// "type": "string",
/// "enum": [
/// "equals",
/// "oneOf",
/// "exists",
/// "before",
/// "after"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum RuleConditionOp {
#[serde(rename = "equals")]
Equals,
#[serde(rename = "oneOf")]
OneOf,
#[serde(rename = "exists")]
Exists,
#[serde(rename = "before")]
Before,
#[serde(rename = "after")]
After,
}
impl ::std::fmt::Display for RuleConditionOp {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Equals => f.write_str("equals"),
Self::OneOf => f.write_str("oneOf"),
Self::Exists => f.write_str("exists"),
Self::Before => f.write_str("before"),
Self::After => f.write_str("after"),
}
}
}
impl ::std::str::FromStr for RuleConditionOp {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"equals" => Ok(Self::Equals),
"oneOf" => Ok(Self::OneOf),
"exists" => Ok(Self::Exists),
"before" => Ok(Self::Before),
"after" => Ok(Self::After),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for RuleConditionOp {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for RuleConditionOp {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for RuleConditionOp {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`RuleConditionValue`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "anyOf": [
/// {
/// "type": "string",
/// "maxLength": 256
/// },
/// {
/// "type": "boolean"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(untagged)]
#[non_exhaustive]
pub enum RuleConditionValue {
String(RuleConditionValueString),
Boolean(bool),
}
impl ::std::str::FromStr for RuleConditionValue {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if let Ok(v) = value.parse() {
Ok(Self::String(v))
} else if let Ok(v) = value.parse() {
Ok(Self::Boolean(v))
} else {
Err("string conversion failed for all variants".into())
}
}
}
impl ::std::convert::TryFrom<&str> for RuleConditionValue {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for RuleConditionValue {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for RuleConditionValue {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::fmt::Display for RuleConditionValue {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match self {
Self::String(x) => x.fmt(f),
Self::Boolean(x) => x.fmt(f),
}
}
}
impl ::std::convert::From<RuleConditionValueString> for RuleConditionValue {
fn from(value: RuleConditionValueString) -> Self {
Self::String(value)
}
}
impl ::std::convert::From<bool> for RuleConditionValue {
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
///`RuleConditionValueString`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 256
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct RuleConditionValueString(::std::string::String);
impl ::std::ops::Deref for RuleConditionValueString {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<RuleConditionValueString> for ::std::string::String {
fn from(value: RuleConditionValueString) -> Self {
value.0
}
}
impl ::std::str::FromStr for RuleConditionValueString {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for RuleConditionValueString {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for RuleConditionValueString {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for RuleConditionValueString {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for RuleConditionValueString {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`RuleConditionValuesItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 256
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct RuleConditionValuesItem(::std::string::String);
impl ::std::ops::Deref for RuleConditionValuesItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<RuleConditionValuesItem> for ::std::string::String {
fn from(value: RuleConditionValuesItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for RuleConditionValuesItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for RuleConditionValuesItem {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for RuleConditionValuesItem {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for RuleConditionValuesItem {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for RuleConditionValuesItem {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct DynamicRule {
all: ::std::result::Result<::std::vec::Vec<super::RuleCondition>, ::std::string::String>,
}
impl ::std::default::Default for DynamicRule {
fn default() -> Self {
Self {
all: Err("no value supplied for all".to_string()),
}
}
}
impl DynamicRule {
pub fn all<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::RuleCondition>>,
T::Error: ::std::fmt::Display,
{
self.all = value
.try_into()
.map_err(|e| format!("error converting supplied value for all: {e}"));
self
}
}
impl ::std::convert::TryFrom<DynamicRule> for super::DynamicRule {
type Error = super::error::ConversionError;
fn try_from(
value: DynamicRule,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self { all: value.all? })
}
}
impl ::std::convert::From<super::DynamicRule> for DynamicRule {
fn from(value: super::DynamicRule) -> Self {
Self { all: Ok(value.all) }
}
}
#[derive(Clone, Debug)]
pub struct Group {
carries_authority: ::std::result::Result<bool, ::std::string::String>,
created_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
created_by:
::std::result::Result<::std::option::Option<super::EntryId>, ::std::string::String>,
credential_authority_valid_until: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
description: ::std::result::Result<
::std::option::Option<super::GroupDescription>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
group_did: ::std::result::Result<super::GroupGroupDid, ::std::string::String>,
group_id: ::std::result::Result<super::GroupId, ::std::string::String>,
issues_credentials: ::std::result::Result<bool, ::std::string::String>,
join_policy:
::std::result::Result<::std::option::Option<super::JoinPolicy>, ::std::string::String>,
kind: ::std::result::Result<super::GroupKind, ::std::string::String>,
managers: ::std::result::Result<
::std::option::Option<Vec<super::EntryId>>,
::std::string::String,
>,
member_count: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
name: ::std::result::Result<super::GroupName, ::std::string::String>,
rule:
::std::result::Result<::std::option::Option<super::DynamicRule>, ::std::string::String>,
show_members: ::std::result::Result<super::GroupAudience, ::std::string::String>,
updated_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
visibility: ::std::result::Result<super::GroupAudience, ::std::string::String>,
}
impl ::std::default::Default for Group {
fn default() -> Self {
Self {
carries_authority: Err("no value supplied for carries_authority".to_string()),
created_at: Err("no value supplied for created_at".to_string()),
created_by: Ok(Default::default()),
credential_authority_valid_until: Ok(Default::default()),
description: Ok(Default::default()),
ext: Ok(Default::default()),
group_did: Err("no value supplied for group_did".to_string()),
group_id: Err("no value supplied for group_id".to_string()),
issues_credentials: Err("no value supplied for issues_credentials".to_string()),
join_policy: Ok(Default::default()),
kind: Err("no value supplied for kind".to_string()),
managers: Ok(Default::default()),
member_count: Ok(Default::default()),
name: Err("no value supplied for name".to_string()),
rule: Ok(Default::default()),
show_members: Err("no value supplied for show_members".to_string()),
updated_at: Ok(Default::default()),
visibility: Err("no value supplied for visibility".to_string()),
}
}
}
impl Group {
pub fn carries_authority<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.carries_authority = value
.try_into()
.map_err(|e| format!("error converting supplied value for carries_authority: {e}"));
self
}
pub fn created_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.created_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for created_at: {e}"));
self
}
pub fn created_by<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::EntryId>>,
T::Error: ::std::fmt::Display,
{
self.created_by = value
.try_into()
.map_err(|e| format!("error converting supplied value for created_by: {e}"));
self
}
pub fn credential_authority_valid_until<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.credential_authority_valid_until = value.try_into().map_err(|e| {
format!("error converting supplied value for credential_authority_valid_until: {e}")
});
self
}
pub fn description<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::GroupDescription>>,
T::Error: ::std::fmt::Display,
{
self.description = value
.try_into()
.map_err(|e| format!("error converting supplied value for description: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn group_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupGroupDid>,
T::Error: ::std::fmt::Display,
{
self.group_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for group_did: {e}"));
self
}
pub fn group_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupId>,
T::Error: ::std::fmt::Display,
{
self.group_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for group_id: {e}"));
self
}
pub fn issues_credentials<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.issues_credentials = value.try_into().map_err(|e| {
format!("error converting supplied value for issues_credentials: {e}")
});
self
}
pub fn join_policy<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::JoinPolicy>>,
T::Error: ::std::fmt::Display,
{
self.join_policy = value
.try_into()
.map_err(|e| format!("error converting supplied value for join_policy: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupKind>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn managers<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::EntryId>>>,
T::Error: ::std::fmt::Display,
{
self.managers = value
.try_into()
.map_err(|e| format!("error converting supplied value for managers: {e}"));
self
}
pub fn member_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.member_count = value
.try_into()
.map_err(|e| format!("error converting supplied value for member_count: {e}"));
self
}
pub fn name<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupName>,
T::Error: ::std::fmt::Display,
{
self.name = value
.try_into()
.map_err(|e| format!("error converting supplied value for name: {e}"));
self
}
pub fn rule<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DynamicRule>>,
T::Error: ::std::fmt::Display,
{
self.rule = value
.try_into()
.map_err(|e| format!("error converting supplied value for rule: {e}"));
self
}
pub fn show_members<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupAudience>,
T::Error: ::std::fmt::Display,
{
self.show_members = value
.try_into()
.map_err(|e| format!("error converting supplied value for show_members: {e}"));
self
}
pub fn updated_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.updated_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for updated_at: {e}"));
self
}
pub fn visibility<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupAudience>,
T::Error: ::std::fmt::Display,
{
self.visibility = value
.try_into()
.map_err(|e| format!("error converting supplied value for visibility: {e}"));
self
}
}
impl ::std::convert::TryFrom<Group> for super::Group {
type Error = super::error::ConversionError;
fn try_from(value: Group) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
carries_authority: value.carries_authority?,
created_at: value.created_at?,
created_by: value.created_by?,
credential_authority_valid_until: value.credential_authority_valid_until?,
description: value.description?,
ext: value.ext?,
group_did: value.group_did?,
group_id: value.group_id?,
issues_credentials: value.issues_credentials?,
join_policy: value.join_policy?,
kind: value.kind?,
managers: value.managers?,
member_count: value.member_count?,
name: value.name?,
rule: value.rule?,
show_members: value.show_members?,
updated_at: value.updated_at?,
visibility: value.visibility?,
})
}
}
impl ::std::convert::From<super::Group> for Group {
fn from(value: super::Group) -> Self {
Self {
carries_authority: Ok(value.carries_authority),
created_at: Ok(value.created_at),
created_by: Ok(value.created_by),
credential_authority_valid_until: Ok(value.credential_authority_valid_until),
description: Ok(value.description),
ext: Ok(value.ext),
group_did: Ok(value.group_did),
group_id: Ok(value.group_id),
issues_credentials: Ok(value.issues_credentials),
join_policy: Ok(value.join_policy),
kind: Ok(value.kind),
managers: Ok(value.managers),
member_count: Ok(value.member_count),
name: Ok(value.name),
rule: Ok(value.rule),
show_members: Ok(value.show_members),
updated_at: Ok(value.updated_at),
visibility: Ok(value.visibility),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
group_id: ::std::result::Result<super::GroupId, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
group_id: Err("no value supplied for group_id".to_string()),
}
}
}
impl Payload {
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn group_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GroupId>,
T::Error: ::std::fmt::Display,
{
self.group_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for group_id: {e}"));
self
}
}
impl ::std::convert::TryFrom<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
ext: value.ext?,
group_id: value.group_id?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
ext: Ok(value.ext),
group_id: Ok(value.group_id),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
group: ::std::result::Result<super::Group, ::std::string::String>,
my_membership: ::std::result::Result<super::ResponseMyMembership, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
group: Err("no value supplied for group".to_string()),
my_membership: Err("no value supplied for my_membership".to_string()),
}
}
}
impl Response {
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn group<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Group>,
T::Error: ::std::fmt::Display,
{
self.group = value
.try_into()
.map_err(|e| format!("error converting supplied value for group: {e}"));
self
}
pub fn my_membership<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseMyMembership>,
T::Error: ::std::fmt::Display,
{
self.my_membership = value
.try_into()
.map_err(|e| format!("error converting supplied value for my_membership: {e}"));
self
}
}
impl ::std::convert::TryFrom<Response> for super::Response {
type Error = super::error::ConversionError;
fn try_from(value: Response) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
ext: value.ext?,
group: value.group?,
my_membership: value.my_membership?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
ext: Ok(value.ext),
group: Ok(value.group),
my_membership: Ok(value.my_membership),
}
}
}
#[derive(Clone, Debug)]
pub struct RuleCondition {
fact: ::std::result::Result<super::RuleConditionFact, ::std::string::String>,
field: ::std::result::Result<::std::option::Option<super::FieldKey>, ::std::string::String>,
op: ::std::result::Result<super::RuleConditionOp, ::std::string::String>,
value: ::std::result::Result<
::std::option::Option<super::RuleConditionValue>,
::std::string::String,
>,
values: ::std::result::Result<
::std::vec::Vec<super::RuleConditionValuesItem>,
::std::string::String,
>,
}
impl ::std::default::Default for RuleCondition {
fn default() -> Self {
Self {
fact: Err("no value supplied for fact".to_string()),
field: Ok(Default::default()),
op: Err("no value supplied for op".to_string()),
value: Ok(Default::default()),
values: Ok(Default::default()),
}
}
}
impl RuleCondition {
pub fn fact<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::RuleConditionFact>,
T::Error: ::std::fmt::Display,
{
self.fact = value
.try_into()
.map_err(|e| format!("error converting supplied value for fact: {e}"));
self
}
pub fn field<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::FieldKey>>,
T::Error: ::std::fmt::Display,
{
self.field = value
.try_into()
.map_err(|e| format!("error converting supplied value for field: {e}"));
self
}
pub fn op<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::RuleConditionOp>,
T::Error: ::std::fmt::Display,
{
self.op = value
.try_into()
.map_err(|e| format!("error converting supplied value for op: {e}"));
self
}
pub fn value<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::RuleConditionValue>>,
T::Error: ::std::fmt::Display,
{
self.value = value
.try_into()
.map_err(|e| format!("error converting supplied value for value: {e}"));
self
}
pub fn values<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::RuleConditionValuesItem>>,
T::Error: ::std::fmt::Display,
{
self.values = value
.try_into()
.map_err(|e| format!("error converting supplied value for values: {e}"));
self
}
}
impl ::std::convert::TryFrom<RuleCondition> for super::RuleCondition {
type Error = super::error::ConversionError;
fn try_from(
value: RuleCondition,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
fact: value.fact?,
field: value.field?,
op: value.op?,
value: value.value?,
values: value.values?,
})
}
}
impl ::std::convert::From<super::RuleCondition> for RuleCondition {
fn from(value: super::RuleCondition) -> Self {
Self {
fact: Ok(value.fact),
field: Ok(value.field),
op: Ok(value.op),
value: Ok(value.value),
values: Ok(value.values),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vtc/groups/show/0.1";
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"DynamicRule\": {\n \"additionalProperties\": false,\n \"description\": \"A dynamic group's membership rule: a member belongs when every condition holds and they have not opted out. The community evaluates it under its `groups` policy and recomputes membership whenever a fact it reads changes, always excluding opted-out entries.\",\n \"properties\": {\n \"all\": {\n \"items\": {\n \"$ref\": \"#/$defs/RuleCondition\"\n },\n \"maxItems\": 16,\n \"minItems\": 1,\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"all\"\n ],\n \"title\": \"DynamicRule\",\n \"type\": \"object\"\n },\n \"EntryId\": {\n \"description\": \"Opaque identifier of one directory entry: `dir_` followed by 16 to 64 base64url characters. Random, scoped to one community, and stable for the life of the membership — it survives a rotation of the member's DID, which is why groups, notes and cards are keyed by it. It MUST NOT be derived from, and MUST NOT reveal, any DID of the member, and the same person's entries in two communities MUST NOT share one. Compared by exact string equality.\",\n \"pattern\": \"^dir_[A-Za-z0-9_-]{16,64}$\",\n \"title\": \"EntryId\",\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"FieldKey\": {\n \"description\": \"Identifier of a directory field. A key with no `.` is a BASE field, the same in every community: `displayName`, `nickname`, `avatar`, `pronouns`, `bio`, `links` (written by the member) and `role`, `joinedAt`, `did`, `personhood` (derived from the community's own records, never stored on a card). A community-defined field MUST use a reverse-DNS key (`org.example.employer`), so a base key never collides with one, and a key is never reused with a different meaning once defined.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^([a-z][a-z0-9-]*\\\\.)*[a-z][a-zA-Z0-9]{0,63}$\",\n \"title\": \"FieldKey\",\n \"type\": \"string\"\n },\n \"Group\": {\n \"additionalProperties\": false,\n \"description\": \"A community group, as a caller who may see it sees it. Members a caller may not see are absent: `memberCount` only to those who may see the group's members, `managers` and `credentialAuthorityValidUntil` only to its managers.\",\n \"properties\": {\n \"carriesAuthority\": {\n \"description\": \"`true` while the group has a `grants` or `role` binding. Such a group is `static` and `closed` for as long as it does.\",\n \"type\": \"boolean\"\n },\n \"createdAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"createdBy\": {\n \"$ref\": \"#/$defs/EntryId\",\n \"description\": \"The creating administrator's directory entry, where they have one.\"\n },\n \"credentialAuthorityValidUntil\": {\n \"description\": \"When the community's authorization credential to the group expires. The community renews it well before.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"description\": {\n \"$ref\": \"#/$defs/GroupDescription\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\",\n \"description\": \"Ecosystem-defined extension members per SPEC.md §4.5.1. An extension member MUST NOT carry authority.\"\n },\n \"groupDid\": {\n \"description\": \"The group's own DID, minted by the community's VTA for this group alone. It issues the group's membership credentials. Its DID document carries no name or description.\",\n \"maxLength\": 2048,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"groupId\": {\n \"$ref\": \"#/$defs/GroupId\"\n },\n \"issuesCredentials\": {\n \"description\": \"Whether the group's DID issues its members a membership credential. Default true.\",\n \"type\": \"boolean\"\n },\n \"joinPolicy\": {\n \"$ref\": \"#/$defs/JoinPolicy\",\n \"description\": \"Present exactly when `kind` is `static`.\"\n },\n \"kind\": {\n \"$ref\": \"#/$defs/GroupKind\"\n },\n \"managers\": {\n \"description\": \"Entries holding `vtc.groups.manage` qualified to this group, read from the access-control list. Informational: managers are appointed by an access-control grant (vtc/groups/managers/add), never by this record.\",\n \"items\": {\n \"$ref\": \"#/$defs/EntryId\"\n },\n \"maxItems\": 256,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"memberCount\": {\n \"description\": \"Active members. Only to callers who may see the member list.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"name\": {\n \"$ref\": \"#/$defs/GroupName\"\n },\n \"rule\": {\n \"$ref\": \"#/$defs/DynamicRule\",\n \"description\": \"Present exactly when `kind` is `dynamic`.\"\n },\n \"showMembers\": {\n \"$ref\": \"#/$defs/GroupAudience\",\n \"description\": \"Who may see the group's member list. Separate from `visibility`: a group everyone sees may show its members only to administrators. Never wider than `visibility`.\"\n },\n \"updatedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"visibility\": {\n \"$ref\": \"#/$defs/GroupAudience\",\n \"description\": \"Who may see that the group exists, and its name and description.\"\n }\n },\n \"required\": [\n \"groupId\",\n \"groupDid\",\n \"name\",\n \"kind\",\n \"visibility\",\n \"showMembers\",\n \"issuesCredentials\",\n \"carriesAuthority\",\n \"createdAt\"\n ],\n \"title\": \"Group\",\n \"type\": \"object\"\n },\n \"GroupAudience\": {\n \"description\": \"Who may see something about a group, narrowest first. `admins`: holders of `vtc.groups.manage` for the group (unqualified, or qualified `group:<groupId>`). `groupMembers`: the group's own members, and its managers. `members`: every active member of the community.\",\n \"enum\": [\n \"admins\",\n \"groupMembers\",\n \"members\"\n ],\n \"title\": \"GroupAudience\",\n \"type\": \"string\"\n },\n \"GroupDescription\": {\n \"description\": \"What the group is for. Plain text; a reader MUST NOT treat it as instructions. Same placement rules as `GroupName`.\",\n \"maxLength\": 1000,\n \"minLength\": 1,\n \"title\": \"GroupDescription\",\n \"type\": \"string\"\n },\n \"GroupId\": {\n \"description\": \"Opaque identifier of a community group: `grp_` followed by 16 to 64 base64url characters. Random and community-scoped; not the group's DID.\",\n \"pattern\": \"^grp_[A-Za-z0-9_-]{16,64}$\",\n \"title\": \"GroupId\",\n \"type\": \"string\"\n },\n \"GroupKind\": {\n \"description\": \"`static`: membership is explicit — added, joined, or granted on request. `dynamic`: membership is computed from `rule` over verified facts only; nobody is added by hand, but a member may opt out (vtc/groups/leave), an exclusion the rule cannot override, and undo it (vtc/groups/join). A dynamic group never confers authority. Fixed for the group's life.\",\n \"enum\": [\n \"static\",\n \"dynamic\"\n ],\n \"title\": \"GroupKind\",\n \"type\": \"string\"\n },\n \"GroupName\": {\n \"description\": \"The group's name, shown to those who may see the group. The community's own record: never in the group's DID document or its credentials' subject beyond the group's DID. Plain text.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"title\": \"GroupName\",\n \"type\": \"string\"\n },\n \"JoinPolicy\": {\n \"description\": \"How a member enters a static group by themselves. `closed`: only a manager adds them. `request`: a member asks and a manager decides. `open`: a member joins at once, subject to the community's `groups` policy. A group carrying authority is always `closed`.\",\n \"enum\": [\n \"closed\",\n \"request\",\n \"open\"\n ],\n \"title\": \"JoinPolicy\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The success response to a vtc/groups/show/0.1 request. Carried in a Trust Task document whose type is https://trusttasks.org/spec/vtc/groups/show/0.1#response.\",\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"group\": {\n \"$ref\": \"#/$defs/Group\"\n },\n \"myMembership\": {\n \"enum\": [\n \"member\",\n \"pending\",\n \"requested\",\n \"optedOut\",\n \"none\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"group\",\n \"myMembership\"\n ],\n \"title\": \"VTC Groups — Show — response payload\",\n \"type\": \"object\"\n },\n \"RuleCondition\": {\n \"additionalProperties\": false,\n \"description\": \"One test over a verified fact about a member. `fact: role` tests the member's community role; `fact: field` tests an `admin`- or `credential`-sourced directory field named by `field`; `fact: personhood` tests whether a personhood assertion is on file; `fact: joinedAt` tests when they joined. A rule never reads a self-asserted (`member`-sourced) field: a member must not be able to join a group by editing their card.\",\n \"properties\": {\n \"fact\": {\n \"enum\": [\n \"role\",\n \"field\",\n \"personhood\",\n \"joinedAt\"\n ],\n \"type\": \"string\"\n },\n \"field\": {\n \"$ref\": \"#/$defs/FieldKey\",\n \"description\": \"Present exactly when `fact` is `field`.\"\n },\n \"op\": {\n \"description\": \"`equals` compares with `value`; `oneOf` with any of `values`; `exists` needs neither; `before` and `after` compare a date fact with `value`.\",\n \"enum\": [\n \"equals\",\n \"oneOf\",\n \"exists\",\n \"before\",\n \"after\"\n ],\n \"type\": \"string\"\n },\n \"value\": {\n \"anyOf\": [\n {\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n {\n \"type\": \"boolean\"\n }\n ]\n },\n \"values\": {\n \"items\": {\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"maxItems\": 64,\n \"minItems\": 1,\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"fact\",\n \"op\"\n ],\n \"title\": \"RuleCondition\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/vtc/groups/show/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"Read one community group the caller may see: its DID, name, kind, policies and, where permitted, its member count and managers. The outer document members are owned by the framework — SPEC §6.3.\",\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"groupId\": {\n \"$ref\": \"#/$defs/GroupId\"\n }\n },\n \"required\": [\n \"groupId\"\n ],\n \"title\": \"VTC Groups — Show — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vtc/groups/show/0.1#response";
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"DynamicRule\": {\n \"additionalProperties\": false,\n \"description\": \"A dynamic group's membership rule: a member belongs when every condition holds and they have not opted out. The community evaluates it under its `groups` policy and recomputes membership whenever a fact it reads changes, always excluding opted-out entries.\",\n \"properties\": {\n \"all\": {\n \"items\": {\n \"$ref\": \"#/$defs/RuleCondition\"\n },\n \"maxItems\": 16,\n \"minItems\": 1,\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"all\"\n ],\n \"title\": \"DynamicRule\",\n \"type\": \"object\"\n },\n \"EntryId\": {\n \"description\": \"Opaque identifier of one directory entry: `dir_` followed by 16 to 64 base64url characters. Random, scoped to one community, and stable for the life of the membership — it survives a rotation of the member's DID, which is why groups, notes and cards are keyed by it. It MUST NOT be derived from, and MUST NOT reveal, any DID of the member, and the same person's entries in two communities MUST NOT share one. Compared by exact string equality.\",\n \"pattern\": \"^dir_[A-Za-z0-9_-]{16,64}$\",\n \"title\": \"EntryId\",\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"FieldKey\": {\n \"description\": \"Identifier of a directory field. A key with no `.` is a BASE field, the same in every community: `displayName`, `nickname`, `avatar`, `pronouns`, `bio`, `links` (written by the member) and `role`, `joinedAt`, `did`, `personhood` (derived from the community's own records, never stored on a card). A community-defined field MUST use a reverse-DNS key (`org.example.employer`), so a base key never collides with one, and a key is never reused with a different meaning once defined.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^([a-z][a-z0-9-]*\\\\.)*[a-z][a-zA-Z0-9]{0,63}$\",\n \"title\": \"FieldKey\",\n \"type\": \"string\"\n },\n \"Group\": {\n \"additionalProperties\": false,\n \"description\": \"A community group, as a caller who may see it sees it. Members a caller may not see are absent: `memberCount` only to those who may see the group's members, `managers` and `credentialAuthorityValidUntil` only to its managers.\",\n \"properties\": {\n \"carriesAuthority\": {\n \"description\": \"`true` while the group has a `grants` or `role` binding. Such a group is `static` and `closed` for as long as it does.\",\n \"type\": \"boolean\"\n },\n \"createdAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"createdBy\": {\n \"$ref\": \"#/$defs/EntryId\",\n \"description\": \"The creating administrator's directory entry, where they have one.\"\n },\n \"credentialAuthorityValidUntil\": {\n \"description\": \"When the community's authorization credential to the group expires. The community renews it well before.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"description\": {\n \"$ref\": \"#/$defs/GroupDescription\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\",\n \"description\": \"Ecosystem-defined extension members per SPEC.md §4.5.1. An extension member MUST NOT carry authority.\"\n },\n \"groupDid\": {\n \"description\": \"The group's own DID, minted by the community's VTA for this group alone. It issues the group's membership credentials. Its DID document carries no name or description.\",\n \"maxLength\": 2048,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"groupId\": {\n \"$ref\": \"#/$defs/GroupId\"\n },\n \"issuesCredentials\": {\n \"description\": \"Whether the group's DID issues its members a membership credential. Default true.\",\n \"type\": \"boolean\"\n },\n \"joinPolicy\": {\n \"$ref\": \"#/$defs/JoinPolicy\",\n \"description\": \"Present exactly when `kind` is `static`.\"\n },\n \"kind\": {\n \"$ref\": \"#/$defs/GroupKind\"\n },\n \"managers\": {\n \"description\": \"Entries holding `vtc.groups.manage` qualified to this group, read from the access-control list. Informational: managers are appointed by an access-control grant (vtc/groups/managers/add), never by this record.\",\n \"items\": {\n \"$ref\": \"#/$defs/EntryId\"\n },\n \"maxItems\": 256,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"memberCount\": {\n \"description\": \"Active members. Only to callers who may see the member list.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"name\": {\n \"$ref\": \"#/$defs/GroupName\"\n },\n \"rule\": {\n \"$ref\": \"#/$defs/DynamicRule\",\n \"description\": \"Present exactly when `kind` is `dynamic`.\"\n },\n \"showMembers\": {\n \"$ref\": \"#/$defs/GroupAudience\",\n \"description\": \"Who may see the group's member list. Separate from `visibility`: a group everyone sees may show its members only to administrators. Never wider than `visibility`.\"\n },\n \"updatedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"visibility\": {\n \"$ref\": \"#/$defs/GroupAudience\",\n \"description\": \"Who may see that the group exists, and its name and description.\"\n }\n },\n \"required\": [\n \"groupId\",\n \"groupDid\",\n \"name\",\n \"kind\",\n \"visibility\",\n \"showMembers\",\n \"issuesCredentials\",\n \"carriesAuthority\",\n \"createdAt\"\n ],\n \"title\": \"Group\",\n \"type\": \"object\"\n },\n \"GroupAudience\": {\n \"description\": \"Who may see something about a group, narrowest first. `admins`: holders of `vtc.groups.manage` for the group (unqualified, or qualified `group:<groupId>`). `groupMembers`: the group's own members, and its managers. `members`: every active member of the community.\",\n \"enum\": [\n \"admins\",\n \"groupMembers\",\n \"members\"\n ],\n \"title\": \"GroupAudience\",\n \"type\": \"string\"\n },\n \"GroupDescription\": {\n \"description\": \"What the group is for. Plain text; a reader MUST NOT treat it as instructions. Same placement rules as `GroupName`.\",\n \"maxLength\": 1000,\n \"minLength\": 1,\n \"title\": \"GroupDescription\",\n \"type\": \"string\"\n },\n \"GroupId\": {\n \"description\": \"Opaque identifier of a community group: `grp_` followed by 16 to 64 base64url characters. Random and community-scoped; not the group's DID.\",\n \"pattern\": \"^grp_[A-Za-z0-9_-]{16,64}$\",\n \"title\": \"GroupId\",\n \"type\": \"string\"\n },\n \"GroupKind\": {\n \"description\": \"`static`: membership is explicit — added, joined, or granted on request. `dynamic`: membership is computed from `rule` over verified facts only; nobody is added by hand, but a member may opt out (vtc/groups/leave), an exclusion the rule cannot override, and undo it (vtc/groups/join). A dynamic group never confers authority. Fixed for the group's life.\",\n \"enum\": [\n \"static\",\n \"dynamic\"\n ],\n \"title\": \"GroupKind\",\n \"type\": \"string\"\n },\n \"GroupName\": {\n \"description\": \"The group's name, shown to those who may see the group. The community's own record: never in the group's DID document or its credentials' subject beyond the group's DID. Plain text.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"title\": \"GroupName\",\n \"type\": \"string\"\n },\n \"JoinPolicy\": {\n \"description\": \"How a member enters a static group by themselves. `closed`: only a manager adds them. `request`: a member asks and a manager decides. `open`: a member joins at once, subject to the community's `groups` policy. A group carrying authority is always `closed`.\",\n \"enum\": [\n \"closed\",\n \"request\",\n \"open\"\n ],\n \"title\": \"JoinPolicy\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The success response to a vtc/groups/show/0.1 request. Carried in a Trust Task document whose type is https://trusttasks.org/spec/vtc/groups/show/0.1#response.\",\n \"properties\": {\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"group\": {\n \"$ref\": \"#/$defs/Group\"\n },\n \"myMembership\": {\n \"enum\": [\n \"member\",\n \"pending\",\n \"requested\",\n \"optedOut\",\n \"none\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"group\",\n \"myMembership\"\n ],\n \"title\": \"VTC Groups — Show — response payload\",\n \"type\": \"object\"\n },\n \"RuleCondition\": {\n \"additionalProperties\": false,\n \"description\": \"One test over a verified fact about a member. `fact: role` tests the member's community role; `fact: field` tests an `admin`- or `credential`-sourced directory field named by `field`; `fact: personhood` tests whether a personhood assertion is on file; `fact: joinedAt` tests when they joined. A rule never reads a self-asserted (`member`-sourced) field: a member must not be able to join a group by editing their card.\",\n \"properties\": {\n \"fact\": {\n \"enum\": [\n \"role\",\n \"field\",\n \"personhood\",\n \"joinedAt\"\n ],\n \"type\": \"string\"\n },\n \"field\": {\n \"$ref\": \"#/$defs/FieldKey\",\n \"description\": \"Present exactly when `fact` is `field`.\"\n },\n \"op\": {\n \"description\": \"`equals` compares with `value`; `oneOf` with any of `values`; `exists` needs neither; `before` and `after` compare a date fact with `value`.\",\n \"enum\": [\n \"equals\",\n \"oneOf\",\n \"exists\",\n \"before\",\n \"after\"\n ],\n \"type\": \"string\"\n },\n \"value\": {\n \"anyOf\": [\n {\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n {\n \"type\": \"boolean\"\n }\n ]\n },\n \"values\": {\n \"items\": {\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"maxItems\": 64,\n \"minItems\": 1,\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"fact\",\n \"op\"\n ],\n \"title\": \"RuleCondition\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[error_codes::NOT_FOUND];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `vtc/groups/show:notFound`
///
/// No group the caller may see has this identifier. A group that exists and is not visible to the caller answers the same way.
///
/// Declared `retryable: false`.
pub const NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/groups/show:notFound",
retryable: false,
details_schema: ::core::option::Option::None,
};
}