Skip to content

Commit 3e5699d

Browse files
committed
create prefs do not prompt user
1 parent e73dba1 commit 3e5699d

1 file changed

Lines changed: 84 additions & 39 deletions

File tree

src/login/login.ts

Lines changed: 84 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function guessPreferencesFileUri (me: NamedNode): string {
8181
.replace('/public/', '/')
8282
.split('/')
8383
.slice(0, -1)
84-
.join('/') + '/Settings/Preferences.ttl'
84+
.join('/') + '/settings/prefs.ttl'
8585
}
8686

8787
function getMissingPreferencesFileUri (context: AuthenticationContext, err: unknown): string | null {
@@ -104,51 +104,84 @@ function getMissingPreferencesFileUri (context: AuthenticationContext, err: unkn
104104
return null
105105
}
106106

107-
async function createPreferencesFile (context: AuthenticationContext, uri: string): Promise<void> {
107+
async function ensurePreferencesFileRowInProfile (
108+
me: NamedNode,
109+
prefsNode: NamedNode,
110+
profileDoc: NamedNode
111+
): Promise<void> {
112+
const existingPreferencesFile = store.any(me, ns.space('preferencesFile'), undefined, profileDoc)
113+
114+
if (existingPreferencesFile && existingPreferencesFile.equals(prefsNode)) {
115+
return
116+
}
117+
118+
if (!store.updater) {
119+
throw new Error('Cannot create preferences file: store has no updater')
120+
}
121+
122+
const deletions = existingPreferencesFile
123+
? [st(me, ns.space('preferencesFile'), existingPreferencesFile, profileDoc)]
124+
: []
125+
const insertions = [st(me, ns.space('preferencesFile'), prefsNode, profileDoc)]
126+
127+
await new Promise<void>((resolve, reject) => {
128+
store.updater!.update(deletions as any, insertions as any, (_uri, ok, body) => {
129+
if (ok) {
130+
resolve()
131+
} else {
132+
reject(new Error(body || 'Unable to update preferencesFile in WebID profile'))
133+
}
134+
})
135+
})
136+
}
137+
138+
function buildPreferencesFileTurtle (me: NamedNode): string {
139+
const mbox = store.any(me, ns.foaf('mbox'))
140+
const mboxLine = mbox ? `\n<${me.uri}> foaf:mbox <${mbox.value}> .\n` : '\n'
141+
142+
return (
143+
'@prefix dct: <http://purl.org/dc/terms/>.\n' +
144+
'@prefix pim: <http://www.w3.org/ns/pim/space#>.\n' +
145+
'@prefix foaf: <http://xmlns.com/foaf/0.1/>.\n' +
146+
'@prefix solid: <http://www.w3.org/ns/solid/terms#>.\n\n' +
147+
'<>\n' +
148+
' a pim:ConfigurationFile;\n\n' +
149+
' dct:title "Preferences file" .\n' +
150+
mboxLine +
151+
`<${me.uri}>\n` +
152+
' solid:publicTypeIndex <publicTypeIndex.ttl> ;\n' +
153+
' solid:privateTypeIndex <privateTypeIndex.ttl> .\n'
154+
)
155+
}
156+
157+
async function writePreferencesFileDocument (uri: string, data: string): Promise<void> {
108158
if (!store.fetcher) {
109159
throw new Error('Cannot create preferences file: store has no fetcher')
110160
}
111-
const initialData = '# Preferences file created by solid-ui\n'
161+
112162
await store.fetcher.webOperation('PUT', uri, {
113-
data: initialData,
163+
data,
114164
contentType: 'text/turtle'
115165
})
116-
if (!context.me) {
117-
throw new Error('Cannot reload preferences file: no logged-in WebID')
118-
}
119-
context.preferencesFile = await loadPreferences(context.me as NamedNode)
120-
context.preferencesFileError = undefined
121166
}
122167

123-
function offerCreatePreferencesFile (
124-
context: AuthenticationContext,
125-
uri: string,
126-
baseMessage: string
127-
): void {
128-
if (context.div && context.dom) {
129-
const box = context.dom.createElement('div')
130-
box.appendChild(widgets.errorMessageBlock(context.dom, `${baseMessage} Create it now?`))
131-
const createButton = context.dom.createElement('button')
132-
createButton.textContent = 'Create preferences file'
133-
createButton.setAttribute('style', style.buttonStyle)
134-
createButton.addEventListener('click', () => {
135-
createButton.disabled = true
136-
createPreferencesFile(context, uri)
137-
.then(() => {
138-
box.appendChild(widgets.errorMessageBlock(context.dom as HTMLDocument, `Preferences file created: ${uri}`, '#dfd'))
139-
})
140-
.catch(error => {
141-
const message = formatDynamicError(error, 'Failed to create preferences file')
142-
box.appendChild(widgets.errorMessageBlock(context.dom as HTMLDocument, message))
143-
debug.error(message)
144-
createButton.disabled = false
145-
})
146-
})
147-
box.appendChild(createButton)
148-
context.div.appendChild(box)
149-
return
168+
async function createPreferencesFile (context: AuthenticationContext, uri: string): Promise<void> {
169+
const me = (context.me as NamedNode) || authn.currentUser()
170+
if (!me) {
171+
throw new Error('Cannot create preferences file: no logged-in WebID')
150172
}
151-
debug.warn(`${baseMessage} You can create it at: ${uri}`)
173+
context.me = me
174+
175+
const profileDoc = me.doc()
176+
const prefsNode = store.sym(uri)
177+
178+
await ensurePreferencesFileRowInProfile(me, prefsNode, profileDoc)
179+
180+
const prefsTurtle = buildPreferencesFileTurtle(me)
181+
await writePreferencesFileDocument(uri, prefsTurtle)
182+
183+
context.preferencesFile = await loadPreferences(me)
184+
context.preferencesFileError = undefined
152185
}
153186

154187
/**
@@ -255,12 +288,24 @@ export async function ensureLoadedPreferences (
255288
} else if (err instanceof FetchError) {
256289
if (err.status === 404) {
257290
m2 = 'Your preferences file was not found (404). It may not exist yet.'
258-
context.preferencesFileError = m2
259291
debug.warn(m2)
260292
const missingPreferencesFileUri = getMissingPreferencesFileUri(context, err)
261293
if (missingPreferencesFileUri) {
262-
offerCreatePreferencesFile(context, missingPreferencesFileUri, m2)
294+
try {
295+
await createPreferencesFile(context, missingPreferencesFileUri)
296+
debug.log(`Preferences file created automatically: ${missingPreferencesFileUri}`)
297+
return context
298+
} catch (createError) {
299+
const message = formatDynamicError(createError, 'Failed to create preferences file automatically')
300+
context.preferencesFileError = message
301+
debug.error(message)
302+
if (context.div && context.dom) {
303+
context.div.appendChild(widgets.errorMessageBlock(context.dom, message))
304+
}
305+
return context
306+
}
263307
}
308+
context.preferencesFileError = m2
264309
return context
265310
}
266311
m2 = formatDynamicError(err, 'Error reading your preferences file')

0 commit comments

Comments
 (0)