add ability to edit a GiveAction
This commit is contained in:
@@ -67,7 +67,7 @@ export async function createEndorserJwtForKey(
|
||||
* The SimpleSigner returns a configured function for signing data.
|
||||
*
|
||||
* @example
|
||||
* const signer = SimpleSigner(import.meta.env.PRIVATE_KEY)
|
||||
* const signer = SimpleSigner(privateKeyHexString)
|
||||
* signer(data, (err, signature) => {
|
||||
* ...
|
||||
* })
|
||||
|
||||
@@ -48,29 +48,31 @@ export interface ClaimResult {
|
||||
}
|
||||
|
||||
export interface GenericVerifiableCredential {
|
||||
"@context": string;
|
||||
"@context"?: string;
|
||||
"@type": string;
|
||||
[key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
export interface GenericCredWrapper extends GenericVerifiableCredential {
|
||||
export interface GenericCredWrapper<T extends GenericVerifiableCredential> {
|
||||
"@context": string;
|
||||
"@type": string;
|
||||
handleId: string;
|
||||
id: string;
|
||||
issuedAt: string;
|
||||
issuer: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
claim: Record<string, any>;
|
||||
claim: T;
|
||||
claimType?: string;
|
||||
}
|
||||
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper = {
|
||||
"@context": SCHEMA_ORG_CONTEXT,
|
||||
"@type": "",
|
||||
claim: {},
|
||||
handleId: "",
|
||||
id: "",
|
||||
issuedAt: "",
|
||||
issuer: "",
|
||||
};
|
||||
export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper<GenericVerifiableCredential> =
|
||||
{
|
||||
"@context": SCHEMA_ORG_CONTEXT,
|
||||
"@type": "",
|
||||
claim: { "@type": "" },
|
||||
handleId: "",
|
||||
id: "",
|
||||
issuedAt: "",
|
||||
issuer: "",
|
||||
};
|
||||
|
||||
// a summary record; the VC is found the fullClaim field
|
||||
export interface GiveSummaryRecord {
|
||||
@@ -123,7 +125,7 @@ export interface PlanSummaryRecord {
|
||||
|
||||
// Note that previous VCs may have additional fields.
|
||||
// https://endorser.ch/doc/html/transactions.html#id4
|
||||
export interface GiveVerifiableCredential {
|
||||
export interface GiveVerifiableCredential extends GenericVerifiableCredential {
|
||||
"@context"?: string; // optional when embedded, eg. in an Agree
|
||||
"@type": "GiveAction";
|
||||
agent?: { identifier: string };
|
||||
@@ -191,7 +193,7 @@ export interface PlanData {
|
||||
*/
|
||||
issuerDid: string;
|
||||
/**
|
||||
* The Identier of the project -- different from jwtId, needs to be fixed
|
||||
* The identifier of the project -- different from jwtId, needs to be fixed
|
||||
**/
|
||||
rowid?: string;
|
||||
}
|
||||
@@ -562,8 +564,9 @@ export async function setPlanInCache(
|
||||
/**
|
||||
* Construct GiveAction VC for submission to server
|
||||
*/
|
||||
export function constructGive(
|
||||
fromDid?: string | null,
|
||||
export function hydrateGive(
|
||||
vcClaimOrig?: GiveVerifiableCredential,
|
||||
fromDid?: string,
|
||||
toDid?: string,
|
||||
description?: string,
|
||||
amount?: number,
|
||||
@@ -572,42 +575,68 @@ export function constructGive(
|
||||
fulfillsOfferHandleId?: string,
|
||||
isTrade: boolean = false,
|
||||
imageUrl?: string,
|
||||
lastClaimId?: string,
|
||||
): GiveVerifiableCredential {
|
||||
const vcClaim: GiveVerifiableCredential = {
|
||||
"@context": SCHEMA_ORG_CONTEXT,
|
||||
"@type": "GiveAction",
|
||||
recipient: toDid ? { identifier: toDid } : undefined,
|
||||
agent: fromDid ? { identifier: fromDid } : undefined,
|
||||
description: description || undefined,
|
||||
object: amount
|
||||
? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
|
||||
: undefined,
|
||||
fulfills: [{ "@type": isTrade ? "TradeAction" : "DonateAction" }],
|
||||
};
|
||||
// Remember: replace values or erase if it's null
|
||||
|
||||
const vcClaim: GiveVerifiableCredential = vcClaimOrig
|
||||
? R.clone(vcClaimOrig)
|
||||
: {
|
||||
"@context": SCHEMA_ORG_CONTEXT,
|
||||
"@type": "GiveAction",
|
||||
};
|
||||
|
||||
if (lastClaimId) {
|
||||
vcClaim.lastClaimId = lastClaimId;
|
||||
delete vcClaim.identifier;
|
||||
}
|
||||
|
||||
vcClaim.agent = fromDid ? { identifier: fromDid } : undefined;
|
||||
vcClaim.recipient = toDid ? { identifier: toDid } : undefined;
|
||||
vcClaim.description = description || undefined;
|
||||
vcClaim.object = amount
|
||||
? { amountOfThisGood: amount, unitCode: unitCode || "HUR" }
|
||||
: undefined;
|
||||
|
||||
// ensure fulfills is an array
|
||||
if (!Array.isArray(vcClaim.fulfills)) {
|
||||
vcClaim.fulfills = vcClaim.fulfills ? [vcClaim.fulfills] : [];
|
||||
}
|
||||
// ... and replace or add each element, ending with Trade or Donate
|
||||
// I realize this doesn't change any elements that are not PlanAction or Offer or Trade/Action.
|
||||
if (fulfillsProjectHandleId) {
|
||||
vcClaim.fulfills = vcClaim.fulfills || []; // weird that it won't typecheck without this
|
||||
vcClaim.fulfills = vcClaim.fulfills.filter(
|
||||
(elem) => elem["@type"] !== "PlanAction",
|
||||
);
|
||||
vcClaim.fulfills.push({
|
||||
"@type": "PlanAction",
|
||||
identifier: fulfillsProjectHandleId,
|
||||
});
|
||||
}
|
||||
if (fulfillsOfferHandleId) {
|
||||
vcClaim.fulfills = vcClaim.fulfills || []; // weird that it won't typecheck without this
|
||||
vcClaim.fulfills = vcClaim.fulfills.filter(
|
||||
(elem) => elem["@type"] !== "Offer",
|
||||
);
|
||||
vcClaim.fulfills.push({
|
||||
"@type": "Offer",
|
||||
identifier: fulfillsOfferHandleId,
|
||||
});
|
||||
}
|
||||
if (imageUrl) {
|
||||
vcClaim.image = imageUrl;
|
||||
}
|
||||
// do Trade/Donate last because current endorser.ch only looks at the first for plans & offers
|
||||
vcClaim.fulfills = vcClaim.fulfills.filter(
|
||||
(elem) =>
|
||||
elem["@type"] !== "DonateAction" && elem["@type"] !== "TradeAction",
|
||||
);
|
||||
vcClaim.fulfills.push({ "@type": isTrade ? "TradeAction" : "DonateAction" });
|
||||
|
||||
vcClaim.image = imageUrl || undefined;
|
||||
|
||||
return vcClaim;
|
||||
}
|
||||
|
||||
/**
|
||||
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
|
||||
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
|
||||
*
|
||||
* @param identity
|
||||
* @param fromDid may be null
|
||||
* @param toDid
|
||||
* @param description may be null; should have this or amount
|
||||
@@ -617,7 +646,7 @@ export async function createAndSubmitGive(
|
||||
axios: Axios,
|
||||
apiServer: string,
|
||||
issuerDid: string,
|
||||
fromDid?: string | null,
|
||||
fromDid?: string,
|
||||
toDid?: string,
|
||||
description?: string,
|
||||
amount?: number,
|
||||
@@ -627,7 +656,8 @@ export async function createAndSubmitGive(
|
||||
isTrade: boolean = false,
|
||||
imageUrl?: string,
|
||||
): Promise<CreateAndSubmitClaimResult> {
|
||||
const vcClaim = constructGive(
|
||||
const vcClaim = hydrateGive(
|
||||
undefined,
|
||||
fromDid,
|
||||
toDid,
|
||||
description,
|
||||
@@ -639,7 +669,51 @@ export async function createAndSubmitGive(
|
||||
imageUrl,
|
||||
);
|
||||
return createAndSubmitClaim(
|
||||
vcClaim as GenericCredWrapper,
|
||||
vcClaim as GenericVerifiableCredential,
|
||||
issuerDid,
|
||||
apiServer,
|
||||
axios,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
|
||||
*
|
||||
* @param fromDid may be null
|
||||
* @param toDid
|
||||
* @param description may be null; should have this or amount
|
||||
* @param amount may be null; should have this or description
|
||||
*/
|
||||
export async function editAndSubmitGive(
|
||||
axios: Axios,
|
||||
apiServer: string,
|
||||
fullClaim: GenericCredWrapper<GiveVerifiableCredential>,
|
||||
issuerDid: string,
|
||||
fromDid?: string,
|
||||
toDid?: string,
|
||||
description?: string,
|
||||
amount?: number,
|
||||
unitCode?: string,
|
||||
fulfillsProjectHandleId?: string,
|
||||
fulfillsOfferHandleId?: string,
|
||||
isTrade: boolean = false,
|
||||
imageUrl?: string,
|
||||
): Promise<CreateAndSubmitClaimResult> {
|
||||
const vcClaim = hydrateGive(
|
||||
fullClaim.claim,
|
||||
fromDid,
|
||||
toDid,
|
||||
description,
|
||||
amount,
|
||||
unitCode,
|
||||
fulfillsProjectHandleId,
|
||||
fulfillsOfferHandleId,
|
||||
isTrade,
|
||||
imageUrl,
|
||||
fullClaim.id,
|
||||
);
|
||||
return createAndSubmitClaim(
|
||||
vcClaim as GenericVerifiableCredential,
|
||||
issuerDid,
|
||||
apiServer,
|
||||
axios,
|
||||
@@ -692,7 +766,7 @@ export async function createAndSubmitOffer(
|
||||
};
|
||||
}
|
||||
return createAndSubmitClaim(
|
||||
vcClaim as GenericCredWrapper,
|
||||
vcClaim as OfferVerifiableCredential,
|
||||
issuerDid,
|
||||
apiServer,
|
||||
axios,
|
||||
@@ -751,7 +825,7 @@ export async function createAndSubmitClaim(
|
||||
return { type: "success", response };
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
console.error("Error creating claim:", error);
|
||||
console.error("Error submitting claim:", error);
|
||||
const errorMessage: string =
|
||||
error.response?.data?.error?.message ||
|
||||
error.message ||
|
||||
@@ -820,24 +894,29 @@ export const capitalizeAndInsertSpacesBeforeCaps = (text: string) => {
|
||||
similar code is also contained in endorser-mobile
|
||||
**/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const claimSummary = (claim: Record<string, any>) => {
|
||||
const claimSummary = (
|
||||
claim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||
) => {
|
||||
if (!claim) {
|
||||
// to differentiate from "something" above
|
||||
return "something";
|
||||
}
|
||||
let specificClaim:
|
||||
| GenericVerifiableCredential
|
||||
| GenericCredWrapper<GenericVerifiableCredential> = claim;
|
||||
if (claim.claim) {
|
||||
// probably a Verified Credential
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
claim = claim.claim as Record<string, any>;
|
||||
specificClaim = claim.claim;
|
||||
}
|
||||
if (Array.isArray(claim)) {
|
||||
if (claim.length === 1) {
|
||||
claim = claim[0];
|
||||
if (Array.isArray(specificClaim)) {
|
||||
if (specificClaim.length === 1) {
|
||||
specificClaim = specificClaim[0];
|
||||
} else {
|
||||
return "multiple claims";
|
||||
}
|
||||
}
|
||||
const type = claim["@type"];
|
||||
const type = specificClaim["@type"];
|
||||
if (!type) {
|
||||
return "a claim";
|
||||
} else {
|
||||
@@ -858,7 +937,7 @@ const claimSummary = (claim: Record<string, any>) => {
|
||||
similar code is also contained in endorser-mobile
|
||||
**/
|
||||
export const claimSpecialDescription = (
|
||||
record: GenericCredWrapper,
|
||||
record: GenericCredWrapper<GenericVerifiableCredential>,
|
||||
activeDid: string,
|
||||
identifiers: Array<string>,
|
||||
contacts: Array<Contact>,
|
||||
@@ -952,7 +1031,11 @@ export const claimSpecialDescription = (
|
||||
"...]"
|
||||
);
|
||||
} else {
|
||||
return issuer + " declared " + claimSummary(claim as GenericCredWrapper);
|
||||
return (
|
||||
issuer +
|
||||
" declared " +
|
||||
claimSummary(claim as GenericCredWrapper<GenericVerifiableCredential>)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@ import {
|
||||
MASTER_SETTINGS_KEY,
|
||||
} from "@/db/tables/settings";
|
||||
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
|
||||
import { GenericCredWrapper, containsHiddenDid } from "@/libs/endorserServer";
|
||||
import {
|
||||
containsHiddenDid,
|
||||
GenericCredWrapper,
|
||||
GenericVerifiableCredential,
|
||||
OfferVerifiableCredential,
|
||||
} from "@/libs/endorserServer";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import { registerCredential } from "@/libs/crypto/vc/passkeyDidPeer";
|
||||
|
||||
@@ -79,7 +84,9 @@ export const isGlobalUri = (uri: string) => {
|
||||
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
|
||||
};
|
||||
|
||||
export const isGiveAction = (veriClaim: GenericCredWrapper) => {
|
||||
export const isGiveAction = (
|
||||
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||
) => {
|
||||
return veriClaim.claimType === "GiveAction";
|
||||
};
|
||||
|
||||
@@ -95,7 +102,7 @@ export const doCopyTwoSecRedo = (text: string, fn: () => void) => {
|
||||
* @param veriClaim is expected to have fields: claim, claimType, and issuer
|
||||
*/
|
||||
export const isGiveRecordTheUserCanConfirm = (
|
||||
veriClaim: GenericCredWrapper,
|
||||
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||
activeDid: string,
|
||||
confirmerIdList: string[] = [],
|
||||
) => {
|
||||
@@ -111,9 +118,9 @@ export const isGiveRecordTheUserCanConfirm = (
|
||||
* @returns the DID of the person who offered, or undefined if hidden
|
||||
* @param veriClaim is expected to have fields: claim and issuer
|
||||
*/
|
||||
export const offerGiverDid: (arg0: GenericCredWrapper) => string | undefined = (
|
||||
veriClaim,
|
||||
) => {
|
||||
export const offerGiverDid: (
|
||||
arg0: GenericCredWrapper<OfferVerifiableCredential>,
|
||||
) => string | undefined = (veriClaim) => {
|
||||
let giver;
|
||||
if (
|
||||
veriClaim.claim.offeredBy?.identifier &&
|
||||
@@ -130,8 +137,13 @@ export const offerGiverDid: (arg0: GenericCredWrapper) => string | undefined = (
|
||||
* @returns true if the user can fulfill the offer
|
||||
* @param veriClaim is expected to have fields: claim, claimType, and issuer
|
||||
*/
|
||||
export const canFulfillOffer = (veriClaim: GenericCredWrapper) => {
|
||||
return !!(veriClaim.claimType === "Offer" && offerGiverDid(veriClaim));
|
||||
export const canFulfillOffer = (
|
||||
veriClaim: GenericCredWrapper<GenericVerifiableCredential>,
|
||||
) => {
|
||||
return !!(
|
||||
veriClaim.claimType === "Offer" &&
|
||||
offerGiverDid(veriClaim as GenericCredWrapper<OfferVerifiableCredential>)
|
||||
);
|
||||
};
|
||||
|
||||
// return object with paths and arrays of DIDs for any keys ending in "VisibleToDid"
|
||||
|
||||
Reference in New Issue
Block a user