Skip to content

Commit

Permalink
differentiate between creator and author
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Sep 6, 2024
1 parent 3782386 commit 678502d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
9 changes: 8 additions & 1 deletion packages/api/src/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,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 @@ -310,6 +312,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 @@ -364,6 +369,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
105 changes: 105 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 @@ -2876,6 +2921,66 @@ describe('Record', () => {
expect(updateResultWithNullTags.status.code).to.equal(202);
expect(record.tags).to.not.exist; // removed
});

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,
dataFormat : 'text/plain'
}
});

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 678502d

Please sign in to comment.