Skip to content

Commit

Permalink
Merge pull request #196 from logion-network/feature/pending-loc-review
Browse files Browse the repository at this point in the history
Enable review of pending LOC's items
  • Loading branch information
gdethier authored Oct 17, 2023
2 parents 9e2d90b + 5223bf6 commit 1dc6dfa
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 84 deletions.
40 changes: 15 additions & 25 deletions packages/client/integration/Loc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ export async function requestTransactionLoc(state: State, linkTarget: UUID) {
const nameHash = Hash.of(metadataName);
draftRequest = await draftRequest.addMetadata({
name: metadataName,
value: "Some value"
value: "Some invalid value"
}) as DraftRequest;
expect(draftRequest.data().metadata[0].name.validValue()).toBe(metadataName);
expect(draftRequest.data().metadata[0].value.validValue()).toBe("Some value");
expect(draftRequest.data().metadata[0].value.validValue()).toBe("Some invalid value");
expect(draftRequest.data().metadata[0].addedOn).toBeUndefined();
expect(draftRequest.data().metadata[0].status).toBe("DRAFT");

Expand Down Expand Up @@ -77,30 +77,36 @@ export async function requestTransactionLoc(state: State, linkTarget: UUID) {
const aliceClient = state.client.withCurrentAddress(aliceAccount);
let aliceLocs = await aliceClient.locsState({ spec: { ownerAddress: alice.address, statuses: [ "REVIEW_PENDING", "OPEN" ], locTypes: [ "Transaction" ] } });
let alicePendingLoc = aliceLocs.findById(pendingRequest.data().id) as PendingRequest;
alicePendingLoc = await alicePendingLoc.legalOfficer.reviewMetadata({ nameHash, decision: "REJECT", rejectReason: "Invalid value" });
let aliceRejectedLoc = await alicePendingLoc.legalOfficer.reject("Because.") as RejectedRequest;
let rejectedRequest = await pendingRequest.refresh() as RejectedRequest;
expect(rejectedRequest).toBeInstanceOf(RejectedRequest);
expect(rejectedRequest.data().metadata[0].status).toBe("REVIEW_REJECTED");
expect(rejectedRequest.data().links[0].status).toBe("REVIEW_REJECTED");
expect(rejectedRequest.data().links[0].status).toBe("REVIEW_PENDING");

draftRequest = await rejectedRequest.rework();
expect(draftRequest).toBeInstanceOf(DraftRequest);
expect(draftRequest.data().metadata[0].status).toBe("DRAFT");
expect(draftRequest.data().links[0].status).toBe("DRAFT");
expect(draftRequest.data().metadata[0].status).toBe("REVIEW_REJECTED");
expect(draftRequest.data().links[0].status).toBe("REVIEW_PENDING");
draftRequest = await draftRequest.deleteMetadata({ nameHash }) as DraftRequest;
draftRequest = await draftRequest.addMetadata({
name: metadataName,
value: "Some value"
}) as DraftRequest;
pendingRequest = await draftRequest.submit();
expect(pendingRequest.data().metadata[0].status).toBe("REVIEW_PENDING");

alicePendingLoc = await aliceRejectedLoc.refresh() as PendingRequest;
alicePendingLoc = await alicePendingLoc.legalOfficer.reviewMetadata({ nameHash, decision: "ACCEPT" });
expect(alicePendingLoc.data().metadata[0].status).toBe("REVIEW_ACCEPTED");
let aliceAcceptedLoc = await alicePendingLoc.legalOfficer.accept({ signer }) as AcceptedRequest;
let acceptedLoc = await pendingRequest.refresh() as AcceptedRequest;
expect(acceptedLoc).toBeInstanceOf(AcceptedRequest);
locsState = acceptedLoc.locsState();
checkData(locsState.acceptedRequests["Transaction"][0].data(), "REVIEW_ACCEPTED");

let openLoc = await acceptedLoc.open({ signer });
let aliceOpenLoc = await aliceAcceptedLoc.refresh() as OpenLoc;

expect(openLoc).toBeInstanceOf(OpenLoc);
expect(openLoc.data().metadata[0].status).toBe("REVIEW_PENDING");

locsState = openLoc.locsState();
checkData(locsState.openLocs["Transaction"][0].data(), "OPEN");
Expand Down Expand Up @@ -128,6 +134,7 @@ export async function requestTransactionLoc(state: State, linkTarget: UUID) {
openLoc = await openLoc.requestFileReview({ hash }) as OpenLoc;
expect(openLoc.data().files[0].status).toBe("REVIEW_PENDING");

let aliceOpenLoc = await aliceAcceptedLoc.refresh() as OpenLoc;
aliceOpenLoc = await aliceOpenLoc.legalOfficer.reviewFile({ hash, decision: "ACCEPT" }) as OpenLoc;
expect(aliceOpenLoc.data().files[0].status).toBe("REVIEW_ACCEPTED");
await waitFor<OnchainLocState>({
Expand All @@ -147,23 +154,6 @@ export async function requestTransactionLoc(state: State, linkTarget: UUID) {
expect(aliceOpenLoc.data().files[0].status).toBe("ACKNOWLEDGED");

// Continue with metadata
aliceOpenLoc = await aliceOpenLoc.refresh() as OpenLoc;
aliceOpenLoc = await aliceOpenLoc.legalOfficer.reviewMetadata({ nameHash, decision: "REJECT", rejectReason: "Because" }) as OpenLoc;
expect(aliceOpenLoc.data().metadata[0].status).toBe("REVIEW_REJECTED");
expect(aliceOpenLoc.data().metadata[0].rejectReason).toBe("Because");
await waitFor<OnchainLocState>({
producer: async state => state ? await state.refresh() : aliceOpenLoc,
predicate: state => state.data().metadata[0].reviewedOn !== undefined,
});
openLoc = await openLoc.refresh() as OpenLoc;
openLoc = await openLoc.deleteMetadata({ nameHash }) as OpenLoc;
openLoc = await openLoc.addMetadata({
name: metadataName,
value: "Some value"
}) as OpenLoc;
openLoc = await openLoc.requestMetadataReview({ nameHash }) as OpenLoc;
aliceOpenLoc = await aliceOpenLoc.refresh() as OpenLoc;
aliceOpenLoc = await aliceOpenLoc.legalOfficer.reviewMetadata({ nameHash, decision: "ACCEPT" }) as OpenLoc;
openLoc = await openLoc.refresh() as OpenLoc;
openLoc = await openLoc.publishMetadata({ nameHash, signer });
expect(openLoc.data().metadata[0].status).toBe("PUBLISHED");
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logion/client",
"version": "0.32.0",
"version": "0.33.0-1",
"description": "logion SDK for client applications",
"main": "dist/index.js",
"packageManager": "[email protected]",
Expand Down
156 changes: 102 additions & 54 deletions packages/client/src/Loc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1031,13 +1031,15 @@ export abstract class LocRequestState extends State {
}
}

export abstract class LegalOfficerLocRequestCommands {
export interface LegalOfficerCommandsConstructorArgs {
locId: UUID;
client: AuthenticatedLocClient;
request: LocRequestState;
}

constructor(args: {
locId: UUID,
client: AuthenticatedLocClient,
request: LocRequestState,
}) {
export class LegalOfficerCommands {

constructor(args: LegalOfficerCommandsConstructorArgs) {
this.locId = args.locId;
this.client = args.client;
this.request = args.request;
Expand All @@ -1048,6 +1050,22 @@ export abstract class LegalOfficerLocRequestCommands {
protected client: AuthenticatedLocClient;

protected request: LocRequestState;
}

export interface LegalOfficerRestrictedDeliveryCommands {
setCollectionFileRestrictedDelivery(params: {
hash: Hash,
restrictedDelivery: boolean,
}): Promise<LocRequestState>;
}

export class LegalOfficerRestrictedDeliveryCommandsImpl
extends LegalOfficerCommands
implements LegalOfficerRestrictedDeliveryCommands {

constructor(args: LegalOfficerCommandsConstructorArgs) {
super(args);
}

async setCollectionFileRestrictedDelivery(params: {
hash: Hash,
Expand Down Expand Up @@ -1151,45 +1169,46 @@ export abstract class EditableRequest extends LocRequestState {
});
return await this.refresh() as EditableRequest;
}
}

get legalOfficer(): LegalOfficerEditableRequestCommands {
return new LegalOfficerEditableRequestCommands({
locId: this.locId,
client: this.locSharedState.client,
request: this,
});
}
export type ReviewableRequest = OpenLoc | PendingRequest;

export interface LegalOfficeReviewCommands {

reviewFile(params: ReviewFileParams): Promise<ReviewableRequest>;
reviewMetadata(params: ReviewMetadataParams): Promise<ReviewableRequest>;
reviewLink(params: ReviewLinkParams): Promise<ReviewableRequest>;
}

/**
* Encapsulated calls can be used only by a Logion Legal Officer.
*/
export class LegalOfficerEditableRequestCommands extends LegalOfficerLocRequestCommands {
export class LegalOfficeReviewCommandsImpl extends LegalOfficerCommands implements LegalOfficeReviewCommands {

constructor(args: LegalOfficerCommandsConstructorArgs) {
super(args);
}

async reviewFile(params: ReviewFileParams): Promise<EditableRequest> {
async reviewFile(params: ReviewFileParams): Promise<ReviewableRequest> {
await this.client.reviewFile({
...params,
locId: this.locId,
});
return await this.request.refresh() as EditableRequest;
return await this.request.refresh() as ReviewableRequest;
}

async reviewMetadata(params: ReviewMetadataParams): Promise<EditableRequest> {
async reviewMetadata(params: ReviewMetadataParams): Promise<ReviewableRequest> {
await this.client.reviewMetadata({
...params,
locId: this.locId,
});
return await this.request.refresh() as EditableRequest;
return await this.request.refresh() as ReviewableRequest;
}

async reviewLink(params: ReviewLinkParams): Promise<EditableRequest> {
async reviewLink(params: ReviewLinkParams): Promise<ReviewableRequest> {
await this.client.reviewLink({
...params,
locId: this.locId,
});
return await this.request.refresh() as EditableRequest;
return await this.request.refresh() as ReviewableRequest;
}

}

export interface IdenfyVerificationCreation {
Expand Down Expand Up @@ -1267,23 +1286,16 @@ export class PendingRequest extends LocRequestState {
}
}

export class LegalOfficerPendingRequestCommands {
export class LegalOfficerPendingRequestCommands
extends LegalOfficerCommands
implements LegalOfficeReviewCommands {

constructor(args: {
locId: UUID,
client: AuthenticatedLocClient,
request: PendingRequest,
}) {
this.locId = args.locId;
this.client = args.client;
this.request = args.request;
constructor(args: LegalOfficerCommandsConstructorArgs) {
super(args);
this.reviewCommands = new LegalOfficeReviewCommandsImpl(args);
}

private readonly locId: UUID;

private client: AuthenticatedLocClient;

private request: PendingRequest;
private reviewCommands: LegalOfficeReviewCommands;

async reject(reason: string): Promise<RejectedRequest> {
await this.client.rejectLoc({
Expand Down Expand Up @@ -1346,6 +1358,18 @@ export class LegalOfficerPendingRequestCommands {
return undefined;
}
}

reviewFile(params: ReviewFileParams): Promise<PendingRequest> {
return this.reviewCommands.reviewFile(params) as Promise<PendingRequest>;
}

reviewMetadata(params: ReviewMetadataParams): Promise<PendingRequest> {
return this.reviewCommands.reviewMetadata(params) as Promise<PendingRequest>;
}

reviewLink(params: ReviewLinkParams): Promise<PendingRequest> {
return this.reviewCommands.reviewLink(params) as Promise<PendingRequest>;
}
}

export class ReviewedRequest extends LocRequestState {
Expand Down Expand Up @@ -1663,7 +1687,7 @@ export class OpenLoc extends EditableRequest {
});
}

override get legalOfficer(): LegalOfficerOpenRequestCommands {
get legalOfficer(): LegalOfficerOpenRequestCommands {
return new LegalOfficerOpenRequestCommands({
locId: this.locId,
client: this.locSharedState.client,
Expand All @@ -1676,24 +1700,26 @@ export class OpenLoc extends EditableRequest {
* Encapsulated calls can be used only by a Logion Legal Officer.
*/
export class LegalOfficerOpenRequestCommands
extends LegalOfficerEditableRequestCommands
implements LegalOfficerNonVoidedCommands, LegalOfficerLocWithSelectableIssuersCommands<OpenLoc> {
extends LegalOfficerCommands
implements LegalOfficeReviewCommands, LegalOfficerNonVoidedCommands, LegalOfficerLocWithSelectableIssuersCommands<OpenLoc>, LegalOfficerRestrictedDeliveryCommands {

constructor(args: {
locId: UUID,
client: AuthenticatedLocClient,
request: EditableRequest,
}) {
constructor(args: LegalOfficerCommandsConstructorArgs) {
super(args);

this.legalOfficerNonVoidedCommands = new LegalOfficerNonVoidedCommandsImpl(args);
this.legalOfficerLocWithSelectableIssuersCommands = new LegalOfficerLocWithSelectableIssuersCommandsImpl(args);
this.reviewCommands = new LegalOfficeReviewCommandsImpl(args);
this.restrictedDeliveryCommands = new LegalOfficerRestrictedDeliveryCommandsImpl(args);
}

private legalOfficerNonVoidedCommands: LegalOfficerNonVoidedCommands;

private legalOfficerLocWithSelectableIssuersCommands: LegalOfficerLocWithSelectableIssuersCommands<OpenLoc>;

private reviewCommands: LegalOfficeReviewCommands;

private restrictedDeliveryCommands: LegalOfficerRestrictedDeliveryCommands;

async acknowledgeFile(parameters: AckFileParams): Promise<OpenLoc> {
const file = this.request.data().files.find(file => file.hash.equalTo(parameters.hash) && file.status === "PUBLISHED");
if(!file) {
Expand Down Expand Up @@ -1788,13 +1814,29 @@ implements LegalOfficerNonVoidedCommands, LegalOfficerLocWithSelectableIssuersCo
async unselectIssuer(params: SelectUnselectIssuerParams): Promise<OpenLoc> {
return this.legalOfficerLocWithSelectableIssuersCommands.unselectIssuer(params);
}

reviewFile(params: ReviewFileParams): Promise<ReviewableRequest> {
return this.reviewCommands.reviewFile(params);
}

reviewMetadata(params: ReviewMetadataParams): Promise<ReviewableRequest> {
return this.reviewCommands.reviewMetadata(params);
}

reviewLink(params: ReviewLinkParams): Promise<ReviewableRequest> {
return this.reviewCommands.reviewLink(params);
}

setCollectionFileRestrictedDelivery(params: { hash: Hash; restrictedDelivery: boolean; }): Promise<LocRequestState> {
return this.restrictedDeliveryCommands.setCollectionFileRestrictedDelivery(params);
}
}

export interface LegalOfficerNonVoidedCommands {
voidLoc(params: VoidParams): Promise<VoidedLoc | VoidedCollectionLoc>;
}

export class LegalOfficerNonVoidedCommandsImpl extends LegalOfficerLocRequestCommands implements LegalOfficerNonVoidedCommands {
export class LegalOfficerNonVoidedCommandsImpl extends LegalOfficerCommands implements LegalOfficerNonVoidedCommands {

async voidLoc(params: VoidParams): Promise<VoidedLoc | VoidedCollectionLoc> {
await this.client.voidLoc({
Expand All @@ -1812,7 +1854,7 @@ export interface LegalOfficerLocWithSelectableIssuersCommands<T extends LocReque
}

export class LegalOfficerLocWithSelectableIssuersCommandsImpl<T extends LocRequestState>
extends LegalOfficerLocRequestCommands
extends LegalOfficerCommands
implements LegalOfficerLocWithSelectableIssuersCommands<T> {

async getVerifiedIssuers(): Promise<VerifiedIssuerWithSelect[]> {
Expand Down Expand Up @@ -2141,20 +2183,19 @@ export class ClosedCollectionLoc extends ClosedOrVoidCollectionLoc {

export class LegalOfficerClosedCollectionLocCommands
extends LegalOfficerNonVoidedCommandsImpl
implements LegalOfficerLocWithSelectableIssuersCommands<ClosedCollectionLoc> {
implements LegalOfficerLocWithSelectableIssuersCommands<ClosedCollectionLoc>, LegalOfficerRestrictedDeliveryCommands {

constructor(args: {
locId: UUID,
client: AuthenticatedLocClient,
request: ClosedCollectionLoc,
}) {
constructor(args: LegalOfficerCommandsConstructorArgs) {
super(args);

this.legalOfficerLocWithSelectableIssuersCommands = new LegalOfficerLocWithSelectableIssuersCommandsImpl(args);
this.restrictedDeliveryCommands = new LegalOfficerRestrictedDeliveryCommandsImpl(args);
}

private legalOfficerLocWithSelectableIssuersCommands: LegalOfficerLocWithSelectableIssuersCommands<ClosedCollectionLoc>;

private restrictedDeliveryCommands: LegalOfficerRestrictedDeliveryCommandsImpl;

async getVerifiedIssuers(): Promise<VerifiedIssuerWithSelect[]> {
return this.legalOfficerLocWithSelectableIssuersCommands.getVerifiedIssuers();
}
Expand All @@ -2166,6 +2207,13 @@ implements LegalOfficerLocWithSelectableIssuersCommands<ClosedCollectionLoc> {
async unselectIssuer(params: SelectUnselectIssuerParams): Promise<ClosedCollectionLoc> {
return this.legalOfficerLocWithSelectableIssuersCommands.unselectIssuer(params);
}

setCollectionFileRestrictedDelivery(params: {
hash: Hash,
restrictedDelivery: boolean,
}): Promise<LocRequestState> {
return this.restrictedDeliveryCommands.setCollectionFileRestrictedDelivery(params);
}
}

async function requestSof(locSharedState: LocSharedState, locId: UUID, itemId?: Hash): Promise<PendingRequest> {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/Token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export function validatePsp34TokenId(tokenId: string): TokenValidationResult {
}
}

function isAnyNumber(value: any): boolean {
function isAnyNumber(value: any): boolean { // eslint-disable-line @typescript-eslint/no-explicit-any
return typeof value === "number"
|| (typeof value === "string" && /[0-9]+/.test(value))
;
Expand Down
2 changes: 1 addition & 1 deletion packages/crossmint/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logion/crossmint",
"version": "0.1.26",
"version": "0.1.27-1",
"description": "logion SDK for Crossmint",
"main": "dist/index.js",
"packageManager": "[email protected]",
Expand Down
Loading

0 comments on commit 1dc6dfa

Please sign in to comment.