Skip to content

Commit

Permalink
Save context metadata provided by LMS app with new annotations
Browse files Browse the repository at this point in the history
When the embedder frame (eg. our LMS app) provides context metadata to be saved
with annotations via the `annotationMetadata` config property, save that with
new annotations in the `metadata` field.

We add this information only when an annotation is created, and not on
subsequent edits, because the main use case in the LMS context is to record the
assignment where the annotation was created. If the user edits that annotation
subsequently in another assignment, we don't want it to be "moved" by updating
the `metadata` field.

Part of hypothesis/lms#5698
  • Loading branch information
robertknight committed Oct 19, 2023
1 parent 088ed0a commit 4fe2f5b
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
11 changes: 10 additions & 1 deletion src/sidebar/services/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
Annotation,
SavedAnnotation,
} from '../../types/api';
import type { AnnotationEventType } from '../../types/config';
import type { AnnotationEventType, SidebarSettings } from '../../types/config';
import * as metadata from '../helpers/annotation-metadata';
import {
defaultPermissions,
Expand All @@ -24,15 +24,18 @@ import type { APIService } from './api';
export class AnnotationsService {
private _activity: AnnotationActivityService;
private _api: APIService;
private _settings: SidebarSettings;
private _store: SidebarStore;

constructor(
annotationActivity: AnnotationActivityService,
api: APIService,
settings: SidebarSettings,
store: SidebarStore,
) {
this._activity = annotationActivity;
this._api = api;
this._settings = settings;
this._store = store;
}

Expand Down Expand Up @@ -109,6 +112,12 @@ export class AnnotationsService {
if (metadata.isHighlight(annotation)) {
annotation.permissions = privatePermissions(userid);
}

// Attach information about the current context (eg. LMS assignment).
if (this._settings.annotationMetadata) {
annotation.metadata = { ...this._settings.annotationMetadata };
}

return annotation;
}

Expand Down
25 changes: 24 additions & 1 deletion src/sidebar/services/test/annotations-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe('AnnotationsService', () => {
let fakeAnnotationActivity;
let fakeApi;
let fakeMetadata;
let fakeSettings;
let fakeStore;

let fakeDefaultPermissions;
Expand Down Expand Up @@ -46,6 +47,8 @@ describe('AnnotationsService', () => {
isPublic: sinon.stub(),
};

fakeSettings = {};

fakeStore = {
addAnnotations: sinon.stub(),
annotationSaveFinished: sinon.stub(),
Expand Down Expand Up @@ -77,7 +80,12 @@ describe('AnnotationsService', () => {
},
});

svc = new AnnotationsService(fakeAnnotationActivity, fakeApi, fakeStore);
svc = new AnnotationsService(
fakeAnnotationActivity,
fakeApi,
fakeSettings,
fakeStore,
);
});

afterEach(() => {
Expand Down Expand Up @@ -118,6 +126,21 @@ describe('AnnotationsService', () => {
assert.equal(annotation.user, 'acct:[email protected]');
assert.isOk(annotation.$tag);
assert.isString(annotation.$tag);

// `annotationMetadata` config not set, so this field should also not be set.
assert.isUndefined(annotation.metadata);
});

it('adds metadata from `annotationMetadata` setting to annotation', () => {
fakeStore.focusedGroupId.returns('mygroup');
fakeSettings.annotationMetadata = {
lms: { assignment_id: '1234' },
};

svc.create({}, now);

const annotation = getLastAddedAnnotation();
assert.deepEqual(annotation.metadata, fakeSettings.annotationMetadata);
});

describe('annotation permissions', () => {
Expand Down
9 changes: 9 additions & 0 deletions src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,15 @@ export type APIAnnotationData = {
};

user_info?: UserInfo;

/**
* An opaque object that contains metadata about the current context,
* provided by the embedder via the `annotationMetadata` config.
*
* The Hypothesis LMS app uses this field to attach information about the
* current assignment, course etc. to annotations.
*/
metadata?: object;
};

/**
Expand Down
9 changes: 9 additions & 0 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,15 @@ export type ConfigFromAnnotator = ConfigFromHost & {
* allow arbitrary web pages to set.
*/
export type ConfigFromEmbedder = ConfigFromHost & {
/**
* Metadata about the context which the client should store with new
* annotations in the `metadata` field.
*
* The Hypothesis LMS app uses this field to attach information about the
* current assignment, course etc. to annotations.
*/
annotationMetadata?: object;

/**
* Feature flags to enable. When a flag is listed here, it will be turned
* on even if disabled in the H user profile.
Expand Down

0 comments on commit 4fe2f5b

Please sign in to comment.