|
| 1 | +import type { NamedNode, Quad, Quad_Object, Term } from '@rdfjs/types'; |
| 2 | +import { DataFactory } from 'n3'; |
| 3 | +import { stringToTerm } from 'rdf-string'; |
| 4 | +import type { PodStore, ResourceIdentifier } from '@solid/community-server'; |
| 5 | +import { StorageDescriber } from '@solid/community-server'; |
| 6 | +import quad = DataFactory.quad; |
| 7 | +import namedNode = DataFactory.namedNode; |
| 8 | +import type { AccountStore, AccountSettings } from '../../identity/interaction/account/util/AccountStore'; |
| 9 | + |
| 10 | +/** |
| 11 | + * Adds triples to the storage description resource, based on the settings of |
| 12 | + * the account that created the storage. |
| 13 | + * |
| 14 | + * The resource identifier of the storage is used as subject. |
| 15 | + */ |
| 16 | +export class AccountSettingsStorageDescriber extends StorageDescriber { |
| 17 | + private readonly terms: ReadonlyMap<NamedNode, keyof AccountSettings>; |
| 18 | + |
| 19 | + public constructor( |
| 20 | + private podStore: PodStore, |
| 21 | + private accountStore: AccountStore, |
| 22 | + terms: Record<string, keyof AccountSettings>, |
| 23 | + ) { |
| 24 | + super(); |
| 25 | + |
| 26 | + const termMap = new Map<NamedNode, keyof AccountSettings>(); |
| 27 | + for (const [ predicate, settingsKey ] of Object.entries(terms)) { |
| 28 | + |
| 29 | + const predTerm = stringToTerm(predicate); |
| 30 | + if (predTerm.termType !== 'NamedNode') { |
| 31 | + throw new Error('Predicate needs to be a named node.'); |
| 32 | + } |
| 33 | + |
| 34 | + termMap.set(predTerm, settingsKey); |
| 35 | + } |
| 36 | + |
| 37 | + this.terms = termMap; |
| 38 | + } |
| 39 | + |
| 40 | + public async handle(target: ResourceIdentifier): Promise<Quad[]> { |
| 41 | + const subject = namedNode(target.path); |
| 42 | + const pod = await this.podStore.findByBaseUrl(target.path); |
| 43 | + if (!pod) throw new Error(`Cannot find pod for storage path ${target.path}`); |
| 44 | + |
| 45 | + const quads: Quad[] = []; |
| 46 | + for await (const quad of this.generateTriples(subject, pod.accountId)) { |
| 47 | + quads.push(quad); |
| 48 | + } |
| 49 | + |
| 50 | + return quads; |
| 51 | + } |
| 52 | + |
| 53 | + private async* generateTriples(subject: NamedNode, account: string): AsyncGenerator<Quad> { |
| 54 | + |
| 55 | + for (const [ predicate, settingsKey ] of this.terms.entries()) { |
| 56 | + |
| 57 | + const settingsValue = await this.accountStore.getSetting(account, settingsKey); |
| 58 | + if (settingsValue === undefined) continue; |
| 59 | + |
| 60 | + const objects = (Array.isArray(settingsValue) ? settingsValue : [ settingsValue ]).map((value): Quad_Object => { |
| 61 | + let term: Term; |
| 62 | + |
| 63 | + try { |
| 64 | + term = stringToTerm(`${value}`); |
| 65 | + } catch { |
| 66 | + term = stringToTerm(`"${value}"`); |
| 67 | + } |
| 68 | + |
| 69 | + return term as Quad_Object; |
| 70 | + }); |
| 71 | + |
| 72 | + for (const object of objects) { |
| 73 | + yield quad(subject, predicate, object); |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | +} |
0 commit comments