Skip to content

Commit

Permalink
differentiate between Record creator and author (#893)
Browse files Browse the repository at this point in the history
Add a property to the `Record` class that denotes the record's `creator`.

When the record is an initial write, the `creator` and `author` will return the same.

Created this issue to add query/filter for creator: decentralized-identity/dwn-sdk-js#800
  • Loading branch information
LiranCohen authored Sep 7, 2024
1 parent 2ec2d21 commit 43a5078
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/brown-experts-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web5/api": patch
---

differentiate between Record creator and author
9 changes: 8 additions & 1 deletion packages/api/src/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,10 @@ export class Record implements RecordModel {

// Private variables for DWN `RecordsWrite` message properties.

/** The DID of the entity that authored the record. */
/** The DID of the entity that most recently authored or deleted the record. */
private _author: string;
/** The DID of the entity that originally created the record. */
private _creator: string;
/** Attestation JWS signature. */
private _attestation?: DwnMessage[DwnInterface.RecordsWrite]['attestation'];
/** Authorization signature(s). */
Expand Down Expand Up @@ -314,6 +316,9 @@ export class Record implements RecordModel {
/** DID that is the logical author of the Record. */
get author(): string { return this._author; }

/** DID that is the original creator of the Record. */
get creator(): string { return this._creator; }

/** Record's modified date */
get dateModified() { return this._descriptor.messageTimestamp; }

Expand Down Expand Up @@ -368,6 +373,8 @@ export class Record implements RecordModel {
// Store the author DID that originally signed the message as a convenience for developers, so
// that they don't have to decode the signer's DID from the JWS.
this._author = options.author;
// The creator is the author of the initial write, or the author of the record if there is no initial write.
this._creator = options.initialWrite ? getRecordAuthor(options.initialWrite) : options.author;

// Store the `connectedDid`, and optionally the `delegateDid` and `permissionsApi` in order to be able
// to perform operations on the record (update, delete, data) as a delegate of the connected DID.
Expand Down
103 changes: 103 additions & 0 deletions packages/api/tests/record.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2403,6 +2403,51 @@ describe('Record', () => {
});

describe('update()', () => {
let notesProtocol: DwnProtocolDefinition;

beforeEach(async () => {
const protocolUri = `http://example.com/notes-${TestDataGenerator.randomString(15)}`;

notesProtocol = {
published : true,
protocol : protocolUri,
types : {
note: {
schema: 'http://example.com/note'
},
request: {
schema: 'http://example.com/request'
}
},
structure: {
request: {
$actions: [{
who : 'anyone',
can : ['create', 'update', 'delete']
},{
who : 'recipient',
of : 'request',
can : ['co-update']
}]
},
note: {
}
}
};

// alice and bob both configure the protocol
const { status: aliceConfigStatus, protocol: aliceNotesProtocol } = await dwnAlice.protocols.configure({ message: { definition: notesProtocol } });
expect(aliceConfigStatus.code).to.equal(202);
const { status: aliceNotesProtocolSend } = await aliceNotesProtocol.send(aliceDid.uri);
expect(aliceNotesProtocolSend.code).to.equal(202);

const { status: bobConfigStatus, protocol: bobNotesProtocol } = await dwnBob.protocols.configure({ message: { definition: notesProtocol } });
expect(bobConfigStatus.code).to.equal(202);
const { status: bobNotesProtocolSend } = await bobNotesProtocol!.send(bobDid.uri);
expect(bobNotesProtocolSend.code).to.equal(202);

});

it('updates a local record on the local DWN', async () => {
const { status, record } = await dwnAlice.records.write({
data : 'Hello, world!',
Expand Down Expand Up @@ -2906,6 +2951,64 @@ describe('Record', () => {
expect(record.dataFormat).to.equal('application/json');
expect(await record.data.json()).to.deep.equal({ subject: 'another subject', body: 'another body' });
});

it('differentiates between creator and author', async () => {
const { status, record } = await dwnAlice.records.write({
data : 'Hello, Bob!',
message : {
recipient : bobDid.uri,
protocol : notesProtocol.protocol,
protocolPath : 'request',
schema : notesProtocol.types.request.schema,
}
});
expect(status.code).to.equal(202, 'create');
expect(record).to.not.be.undefined;
const { status: sendStatus } = await record.send();
expect(sendStatus.code).to.equal(202, 'send');

// bob reads the record
const readResult = await dwnBob.records.read({
protocol : notesProtocol.protocol,
from : aliceDid.uri,
message : {
filter: {
recordId: record.id
}
}
});
expect(readResult.status.code).to.equal(200, 'bob reads record');
expect(readResult.record).to.not.be.undefined;

const bobRecord = readResult.record;
const { status: storeStatus } = await bobRecord!.store();
expect(storeStatus.code).to.equal(202, 'store');
const { status: updateStatus } = await bobRecord.update({ data: 'Hello, Alice!' });
expect(updateStatus.code).to.equal(202, 'update');

const updatedData = await bobRecord.send(aliceDid.uri);
expect(updatedData.status.code).to.equal(202, 'send update');

// alice reads the record
const readResultAlice = await dwnAlice.records.read({
from : aliceDid.uri,
protocol : notesProtocol.protocol,
message : {
filter: {
recordId: record.id
}
}
});

expect(readResultAlice.status.code).to.equal(200, 'alice reads record');
expect(readResultAlice.record).to.not.be.undefined;
expect(await readResultAlice.record!.data.text()).to.equal('Hello, Alice!');

// alice is the creator
expect(readResultAlice.record!.creator).to.equal(aliceDid.uri);
// bob is the author
expect(readResultAlice.record!.author).to.equal(bobDid.uri);
});
});

describe('delete()', () => {
Expand Down

0 comments on commit 43a5078

Please sign in to comment.