-
Notifications
You must be signed in to change notification settings - Fork 42
/
basicPreferences.ts
160 lines (142 loc) · 4.81 KB
/
basicPreferences.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import { authn, icons, ns, widgets } from 'solid-ui'
import { NamedNode, parse, IndexedFormula } from 'rdflib'
import { renderTrustedApplicationsOptions } from './trustedApplications/trustedApplicationsPane'
import preferencesFormText from './preferencesFormText.ttl'
import ontologyData from './ontologyData.ttl'
import { PaneDefinition } from 'pane-registry'
export const basicPreferencesPane: PaneDefinition = {
icon: icons.iconBase + 'noun_Sliders_341315_000000.svg',
name: 'basicPreferences',
label: _subject => {
return null
},
// Render the pane
// The subject should be the logged in user.
render: (subject, context) => {
const dom = context.dom
const store = context.session.store
function complainIfBad (ok: Boolean, mess: any) {
if (ok) return
container.appendChild(widgets.errorMessageBlock(dom, mess, '#fee'))
}
const container = dom.createElement('div')
const formArea = container.appendChild(dom.createElement('div'))
function loadData (doc: NamedNode, turtle: String) {
doc = doc.doc() // remove # from URI if nec
if (!store.holds(undefined, undefined, undefined, doc)) {
// If not loaded already
;(parse as any)(turtle, store, doc.uri, 'text/turtle', null) // Load form directly
}
}
const preferencesForm = store.sym(
'urn:uuid:93774ba1-d3b6-41f2-85b6-4ae27ffd2597#this'
)
loadData(preferencesForm, preferencesFormText)
const ontologyExtra = store.sym(
'urn:uuid:93774ba1-d3b6-41f2-85b6-4ae27ffd2597-ONT'
)
loadData(ontologyExtra, ontologyData)
async function doRender () {
const renderContext = await authn.logInLoadPreferences({
dom,
div: container
})
if (!renderContext.preferencesFile) {
// Could be CORS
console.log(
'Not doing private class preferences as no access to preferences file. ' +
renderContext.preferencesFileError
)
return
}
addDeletionLinks(container, store, renderContext.me)
const appendedForm = widgets.appendForm(
dom,
formArea,
{},
renderContext.me,
preferencesForm,
renderContext.preferencesFile,
complainIfBad
)
appendedForm.style.borderStyle = 'none'
const trustedApplicationSettings = renderTrustedApplicationsOptions(
renderContext.dom
)
container.appendChild(trustedApplicationSettings)
}
doRender()
return container
}
}
export default basicPreferencesPane
// ends
function addDeletionLinks (
container: HTMLElement,
kb: IndexedFormula,
profile: NamedNode
): void {
const podServerNodes = kb.each(
profile,
ns.space('storage'),
null,
profile.doc()
)
const podServers = podServerNodes.map(node => node.value)
podServers.forEach(async server => {
const deletionLink = await generateDeletionLink(server)
if (deletionLink) {
container.appendChild(deletionLink)
}
})
}
async function generateDeletionLink (
podServer: string
): Promise<HTMLElement | null> {
const link = document.createElement('a')
link.textContent = `Delete your account at ${podServer}`
const deletionUrl = await getDeletionUrlForServer(podServer)
if (typeof deletionUrl !== 'string') {
return null
}
link.href = deletionUrl
return link
}
/**
* Hacky way to get the deletion link to a Pod
*
* This function infers the deletion link by assuming the URL structure of Node Solid server.
* In the future, Solid will hopefully provide a standardised way of discovering the deletion link:
* https://github.com/solid/data-interoperability-panel/issues/18
*
* If NSS is in multi-user mode (the case on inrupt.net and solid.community), the deletion URL for
* vincent.dev.inrupt.net would be at dev.inrupt.net/account/delete. In single-user mode, the
* deletion URL would be at vincent.dev.inrupt.net/account/delete.
*
* @param server Pod server containing the user's account.
* @returns URL of the page that Node Solid Server would offer to delete the account, or null if
* the URLs we tried give invalid responses.
*/
async function getDeletionUrlForServer (
server: string
): Promise<string | null> {
const singleUserUrl = new URL(server)
const multiUserUrl = new URL(server)
multiUserUrl.pathname = singleUserUrl.pathname = '/account/delete'
const hostnameParts = multiUserUrl.hostname.split('.')
// Remove `vincent.` from `vincent.dev.inrupt.net`, for example:
multiUserUrl.hostname = hostnameParts.slice(1).join('.')
const multiUserNssResponse = await fetch(multiUserUrl.href, {
method: 'HEAD'
})
if (multiUserNssResponse.ok) {
return multiUserUrl.href
}
const singleUserNssResponse = await fetch(singleUserUrl.href, {
method: 'HEAD'
})
if (singleUserNssResponse.ok) {
return singleUserUrl.href
}
return null
}