contacts-pane 2.6.4 → 2.6.5-4b7e5154
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +0 -0
- package/.github/workflows/ci.yml +0 -0
- package/.nvmrc +0 -0
- package/LICENSE.md +0 -0
- package/Makefile +0 -0
- package/README.md +0 -0
- package/card.ai +0 -0
- package/card.png +0 -0
- package/contactLogic.js +35 -6
- package/contactsPane.js +55 -4
- package/diff.txt +0 -0
- package/exampleOfOpenData/mit-wikidata-details.ttl +0 -0
- package/exampleOfOpenData/mit-wikidata-query.sparql +0 -0
- package/exampleOfOpenData/wikidata-get.json +0 -0
- package/groupMembershipControl.js +30 -5
- package/individual.js +0 -0
- package/individualForm.js +0 -0
- package/lib/autocompleteBar.js +0 -0
- package/lib/autocompleteField.js +0 -0
- package/lib/autocompletePicker.js +0 -0
- package/lib/forms.js +0 -0
- package/lib/instituteDetailsQuery.js +0 -0
- package/lib/publicData.js +0 -0
- package/lib/vcard.js +0 -0
- package/mintNewAddressBook.js +0 -0
- package/mugshotGallery.js +0 -0
- package/organizationForm.js +0 -0
- package/organizationForm.ttl +0 -0
- package/package.json +11 -11
- package/shapes/contacts-shapes.ttl +0 -0
- package/src/autocompleteBar.ts +0 -0
- package/src/autocompleteField.ts +0 -0
- package/src/autocompletePicker.ts +0 -0
- package/src/forms.ttl +0 -0
- package/src/instituteDetailsQuery.sparql +0 -0
- package/src/publicData.ts +0 -0
- package/src/vcard.ttl +0 -0
- package/toolsPane.js +66 -16
- package/webidControl.js +18 -7
package/.eslintrc
CHANGED
|
File without changes
|
package/.github/workflows/ci.yml
CHANGED
|
File without changes
|
package/.nvmrc
CHANGED
|
File without changes
|
package/LICENSE.md
CHANGED
|
File without changes
|
package/Makefile
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/card.ai
CHANGED
|
File without changes
|
package/card.png
CHANGED
|
File without changes
|
package/contactLogic.js
CHANGED
|
@@ -138,7 +138,7 @@ export async function addPersonToGroup (thing, group) {
|
|
|
138
138
|
const pname = kb.any(thing, ns.vcard('fn'))
|
|
139
139
|
const gname = kb.any(group, ns.vcard('fn'))
|
|
140
140
|
if (!pname) { return alert('No vcard name known for ' + thing) }
|
|
141
|
-
const already = kb.holds(
|
|
141
|
+
const already = kb.holds(thing, ns.vcard('fn'), null, group.doc())
|
|
142
142
|
if (already) {
|
|
143
143
|
return alert(
|
|
144
144
|
'ALREADY added ' + pname + ' to group ' + gname
|
|
@@ -147,14 +147,18 @@ export async function addPersonToGroup (thing, group) {
|
|
|
147
147
|
const message = 'Add ' + pname + ' to group ' + gname + '?'
|
|
148
148
|
if (!confirm(message)) return
|
|
149
149
|
const ins = [
|
|
150
|
-
$rdf.st(group, ns.vcard('hasMember'), thing, group.doc()),
|
|
151
150
|
$rdf.st(thing, ns.vcard('fn'), pname, group.doc())
|
|
152
151
|
]
|
|
153
|
-
// find person webIDs
|
|
152
|
+
// find person webIDs and insert in vcard:hasMember
|
|
154
153
|
const webIDs = getPersonas(kb, thing).map(webid => webid.value)
|
|
155
|
-
webIDs.
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
if (webIDs.length) {
|
|
155
|
+
webIDs.forEach(webid => {
|
|
156
|
+
ins.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), thing, group.doc()))
|
|
157
|
+
ins.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc()))
|
|
158
|
+
})
|
|
159
|
+
} else {
|
|
160
|
+
ins.push($rdf.st(group, ns.vcard('hasMember'), thing, group.doc()))
|
|
161
|
+
}
|
|
158
162
|
try {
|
|
159
163
|
await updater.update([], ins)
|
|
160
164
|
// to allow refresh of card groupList
|
|
@@ -165,3 +169,28 @@ export async function addPersonToGroup (thing, group) {
|
|
|
165
169
|
}
|
|
166
170
|
return thing
|
|
167
171
|
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Find persons member of a group
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
export function groupMembers (kb, group) {
|
|
178
|
+
const a = kb.each(group, ns.vcard('hasMember'), null, group.doc())
|
|
179
|
+
let b = []
|
|
180
|
+
a.forEach(item => {
|
|
181
|
+
/* const contacts = kb.each(item, ns.owl('sameAs'), null, group.doc())
|
|
182
|
+
if (contacts.length) {
|
|
183
|
+
if (!kb.any(contacts[0], ns.vard('fn'))) b = b.concat(item) // this is the old data model
|
|
184
|
+
else b = b.concat(contacts)
|
|
185
|
+
} else { b = b.concat(item) }
|
|
186
|
+
b = b.concat(item) */
|
|
187
|
+
|
|
188
|
+
// to keep compatibility with old data model
|
|
189
|
+
// check if item is a contact, else it is a WebID and parse 'sameAs' for contacts
|
|
190
|
+
b = kb.any(item, ns.vcard('fn'), null, group.doc()) ? b.concat(item) : b.concat(kb.each(item, ns.owl('sameAs'), null, group.doc()))
|
|
191
|
+
})
|
|
192
|
+
const strings = new Set(b.map(contact => contact.uri)) // remove dups
|
|
193
|
+
b = [...strings].map(uri => kb.sym(uri))
|
|
194
|
+
return b
|
|
195
|
+
}
|
|
196
|
+
|
package/contactsPane.js
CHANGED
|
@@ -15,11 +15,12 @@ to change its state according to an ontology, comment on it, etc.
|
|
|
15
15
|
/* global alert, confirm */
|
|
16
16
|
|
|
17
17
|
import { authn } from 'solid-logic'
|
|
18
|
-
import { addPersonToGroup, saveNewContact, saveNewGroup } from './contactLogic'
|
|
18
|
+
import { addPersonToGroup, saveNewContact, saveNewGroup, groupMembers } from './contactLogic'
|
|
19
19
|
import * as UI from 'solid-ui'
|
|
20
20
|
import { mintNewAddressBook } from './mintNewAddressBook'
|
|
21
21
|
import { renderIndividual } from './individual'
|
|
22
22
|
import { toolsPane } from './toolsPane'
|
|
23
|
+
import { groupMembership } from './groupMembershipControl'
|
|
23
24
|
|
|
24
25
|
// const $rdf = UI.rdf
|
|
25
26
|
const ns = UI.ns
|
|
@@ -217,8 +218,25 @@ export default {
|
|
|
217
218
|
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))
|
|
218
219
|
await kb.fetcher.load(nameEmailIndex)
|
|
219
220
|
|
|
221
|
+
// - delete person's WebID's in each Group
|
|
220
222
|
// - delete the references to it in group files and save them back
|
|
221
|
-
//
|
|
223
|
+
// - delete the reference in people.ttl and save it back
|
|
224
|
+
|
|
225
|
+
// find all Groups
|
|
226
|
+
const groups = groupMembership(person)
|
|
227
|
+
let removeFromGroups = []
|
|
228
|
+
// find person WebID's
|
|
229
|
+
groups.map( group => {
|
|
230
|
+
const webids = kb.each(null, ns.owl('sameAs'), person, group.doc())
|
|
231
|
+
// for each check in each Group that it is not used by an other person then delete
|
|
232
|
+
webids.map( webid => {
|
|
233
|
+
if (kb.statementsMatching(webid, ns.owl('sameAs'), null, group.doc()).length = 1) {
|
|
234
|
+
removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), webid, group.doc()))
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
// console.log(removeFromGroups)
|
|
239
|
+
await kb.updater.updateMany(removeFromGroups)
|
|
222
240
|
await deleteThingAndDoc(person)
|
|
223
241
|
await deleteRecursive(kb, container)
|
|
224
242
|
refreshNames() // "Doesn't work" -- maybe does now with waiting for async
|
|
@@ -417,8 +435,7 @@ export default {
|
|
|
417
435
|
const groups = Object.keys(selectedGroups).map(groupURI => kb.sym(groupURI))
|
|
418
436
|
groups.forEach(group => {
|
|
419
437
|
if (selectedGroups[group.value]) {
|
|
420
|
-
|
|
421
|
-
cards = cards.concat(a)
|
|
438
|
+
cards = cards.concat(groupMembers(kb, group))
|
|
422
439
|
}
|
|
423
440
|
})
|
|
424
441
|
cards.sort(compareForSort) // @@ sort by name not UID later
|
|
@@ -578,8 +595,42 @@ export default {
|
|
|
578
595
|
const groups = groupsInOrder()
|
|
579
596
|
utils.syncTableToArrayReOrdered(groupsMainTable, groups, renderGroupRow)
|
|
580
597
|
refreshGroupsSelected()
|
|
598
|
+
checkDataModel(groups)
|
|
581
599
|
} // syncGroupTable
|
|
582
600
|
|
|
601
|
+
async function checkDataModel(groups) {
|
|
602
|
+
// check if migration is needed in groups
|
|
603
|
+
async function updateDataModel(groups) {
|
|
604
|
+
let ds = []
|
|
605
|
+
let ins = []
|
|
606
|
+
groups.forEach(group => {
|
|
607
|
+
let vcardOrWebids = kb.statementsMatching(null, ns.owl('sameAs'), null, group.doc()).map(st => st.subject)
|
|
608
|
+
const strings = new Set(vcardOrWebids.map(contact => contact.uri)) // remove dups
|
|
609
|
+
vcardOrWebids = [...strings].map(uri => kb.sym(uri))
|
|
610
|
+
vcardOrWebids.forEach(item => {
|
|
611
|
+
if (kb.each(item, ns.vcard('fn'), null, group.doc()).length) {
|
|
612
|
+
// delete item, it is an old data model, item is a card not a webid.
|
|
613
|
+
ds = ds.concat(kb
|
|
614
|
+
.statementsMatching(item, ns.owl('sameAs'), null, group.doc())
|
|
615
|
+
.concat(kb.statementsMatching(undefined, undefined, item, group.doc())))
|
|
616
|
+
// add card webids to group
|
|
617
|
+
const webids = kb.each(item, ns.owl('sameAs'), null, group.doc())
|
|
618
|
+
webids.forEach(webid => {
|
|
619
|
+
ins = ins.concat($rdf.st(webid, ns.owl('sameAs'), item, group.doc()))
|
|
620
|
+
.concat($rdf.st(group, ns.vcard('hasMember'), webid, group.doc()))
|
|
621
|
+
})
|
|
622
|
+
}
|
|
623
|
+
})
|
|
624
|
+
})
|
|
625
|
+
if (ds.length && confirm('Groups data model need to be updated ?')) {
|
|
626
|
+
await kb.updater.updateMany(ds, ins)
|
|
627
|
+
alert('Update done')
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
await kb.fetcher.load(groups)
|
|
631
|
+
updateDataModel(groups)
|
|
632
|
+
} // checkDataModel
|
|
633
|
+
|
|
583
634
|
// Click on New Group button
|
|
584
635
|
async function newGroupClickHandler (_event) {
|
|
585
636
|
cardMain.innerHTML = ''
|
package/diff.txt
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
// Render a control to record the group memberships we have for this agent
|
|
3
3
|
import * as UI from 'solid-ui'
|
|
4
|
+
import { store } from 'solid-logic'
|
|
4
5
|
|
|
5
6
|
// const $rdf = UI.rdf
|
|
6
7
|
const ns = UI.ns
|
|
@@ -8,14 +9,33 @@ const ns = UI.ns
|
|
|
8
9
|
// const widgets = UI.widgets
|
|
9
10
|
const utils = UI.utils
|
|
10
11
|
// const style = UI.style
|
|
12
|
+
const kb = store
|
|
11
13
|
|
|
12
14
|
// Groups the person is a member of
|
|
15
|
+
export function groupMembership (person) {
|
|
16
|
+
let groups = kb.statementsMatching(null, ns.owl('sameAs'), person).map(st => st.why)
|
|
17
|
+
.concat(kb.each(null, ns.vcard('hasMember'), person))
|
|
18
|
+
const strings = new Set(groups.map(group => group.uri)) // remove dups
|
|
19
|
+
groups = [...strings].map(uri => kb.sym(uri))
|
|
20
|
+
return groups
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
export async function renderGroupMemberships (person, context) {
|
|
14
24
|
// Remove a person from a group
|
|
15
25
|
async function removeFromGroup (thing, group) {
|
|
16
26
|
const pname = kb.any(thing, ns.vcard('fn'))
|
|
17
27
|
const gname = kb.any(group, ns.vcard('fn'))
|
|
18
|
-
|
|
28
|
+
// find all WebIDs of thing
|
|
29
|
+
const thingwebids = kb.each(null, ns.owl('sameAs'), thing, group.doc())
|
|
30
|
+
// WebID can be deleted only if not used in another thing
|
|
31
|
+
let webids = []
|
|
32
|
+
thingwebids.map(webid => {
|
|
33
|
+
if (kb.statementsMatching(webid, ns.owl('sameAs'), thing, group.doc())) webids = webids.concat(webid)
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
let thingOrWebid = thing
|
|
37
|
+
if (webids.length > 0) thingOrWebid = webids[0]
|
|
38
|
+
const groups = kb.each(null, ns.vcard('hasMember'), thingOrWebid) // in all groups a person has same structure
|
|
19
39
|
if (groups.length < 2) {
|
|
20
40
|
alert(
|
|
21
41
|
'Must be a member of at least one group. Add to another group first.'
|
|
@@ -24,9 +44,14 @@ export async function renderGroupMemberships (person, context) {
|
|
|
24
44
|
}
|
|
25
45
|
const message = 'Remove ' + pname + ' from group ' + gname + '?'
|
|
26
46
|
if (confirm(message)) {
|
|
27
|
-
|
|
47
|
+
let del = kb
|
|
28
48
|
.statementsMatching(person, undefined, undefined, group.doc())
|
|
29
49
|
.concat(kb.statementsMatching(undefined, undefined, person, group.doc()))
|
|
50
|
+
webids.map(webid => {
|
|
51
|
+
if (kb.statementsMatching(webid, ns.owl('sameAs'), undefined, group.doc()).length < 2) {
|
|
52
|
+
del = del.concat(kb.statementsMatching(undefined, undefined, webid, group.doc()))
|
|
53
|
+
}
|
|
54
|
+
})
|
|
30
55
|
kb.updater.update(del, [], function (uri, ok, err) {
|
|
31
56
|
if (!ok) {
|
|
32
57
|
const message = 'Error removing member from group ' + group + ': ' + err
|
|
@@ -52,10 +77,10 @@ export async function renderGroupMemberships (person, context) {
|
|
|
52
77
|
return tr
|
|
53
78
|
}
|
|
54
79
|
|
|
80
|
+
// find all groups where person has membership
|
|
55
81
|
function syncGroupList () {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
utils.syncTableToArray(groupList, groups, newRowForGroup)
|
|
82
|
+
// person and/or WebIDs to be changed
|
|
83
|
+
utils.syncTableToArray(groupList, groupMembership(person), newRowForGroup)
|
|
59
84
|
}
|
|
60
85
|
|
|
61
86
|
async function loadGroupsFromBook (book = null) {
|
package/individual.js
CHANGED
|
File without changes
|
package/individualForm.js
CHANGED
|
File without changes
|
package/lib/autocompleteBar.js
CHANGED
|
File without changes
|
package/lib/autocompleteField.js
CHANGED
|
File without changes
|
|
File without changes
|
package/lib/forms.js
CHANGED
|
File without changes
|
|
File without changes
|
package/lib/publicData.js
CHANGED
|
File without changes
|
package/lib/vcard.js
CHANGED
|
File without changes
|
package/mintNewAddressBook.js
CHANGED
|
File without changes
|
package/mugshotGallery.js
CHANGED
|
File without changes
|
package/organizationForm.js
CHANGED
|
File without changes
|
package/organizationForm.ttl
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contacts-pane",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.5-4b7e5154",
|
|
4
4
|
"description": "Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.",
|
|
5
5
|
"main": "./contactsPane.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"lint": "eslint '*.js'",
|
|
11
11
|
"lint-fix": "eslint '*.js' --fix",
|
|
12
12
|
"test": "npm run lint",
|
|
13
|
-
"prepublishOnly": "npm test && npm run build",
|
|
14
|
-
"postpublish": "git push origin main --follow-tags"
|
|
13
|
+
"ignore:prepublishOnly": "npm test && npm run build",
|
|
14
|
+
"ignore:postpublish": "git push origin main --follow-tags"
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
@@ -37,17 +37,17 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://github.com/solid/contacts-pane",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"pane-registry": "2.4.
|
|
41
|
-
"rdflib": "^2.2.
|
|
42
|
-
"solid-logic": "2.0.
|
|
43
|
-
"solid-ui": "2.4.
|
|
40
|
+
"pane-registry": "2.4.13",
|
|
41
|
+
"rdflib": "^2.2.21",
|
|
42
|
+
"solid-logic": "2.0.1",
|
|
43
|
+
"solid-ui": "2.4.24"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
47
|
-
"@typescript-eslint/parser": "^5.
|
|
48
|
-
"eslint": "^8.
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
|
47
|
+
"@typescript-eslint/parser": "^5.43.0",
|
|
48
|
+
"eslint": "^8.27.0",
|
|
49
49
|
"eslint-plugin-import": "^2.26.0",
|
|
50
|
-
"husky": "^8.0.
|
|
50
|
+
"husky": "^8.0.2",
|
|
51
51
|
"lint-staged": "^13.0.3",
|
|
52
52
|
"typescript": "^4.8.2",
|
|
53
53
|
"typescript-transpile-only": "0.0.4"
|
|
File without changes
|
package/src/autocompleteBar.ts
CHANGED
|
File without changes
|
package/src/autocompleteField.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/src/forms.ttl
CHANGED
|
File without changes
|
|
File without changes
|
package/src/publicData.ts
CHANGED
|
File without changes
|
package/src/vcard.ttl
CHANGED
|
File without changes
|
package/toolsPane.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as UI from 'solid-ui'
|
|
6
6
|
import { store } from 'solid-logic'
|
|
7
|
-
import { saveNewGroup, addPersonToGroup } from './contactLogic'
|
|
7
|
+
import { saveNewGroup, addPersonToGroup, groupMembers } from './contactLogic'
|
|
8
8
|
export function toolsPane (
|
|
9
9
|
selectAllGroups,
|
|
10
10
|
selectedGroups,
|
|
@@ -85,7 +85,9 @@ export function toolsPane (
|
|
|
85
85
|
function stats () {
|
|
86
86
|
const totalCards = kb.each(undefined, VCARD('inAddressBook'), book).length
|
|
87
87
|
log('' + totalCards + ' cards loaded. ')
|
|
88
|
-
|
|
88
|
+
let groups = kb.each(book, VCARD('includesGroup'))
|
|
89
|
+
const strings = new Set(groups.map(group => group.uri)) // remove dups
|
|
90
|
+
groups = [...strings].map(uri => kb.sym(uri))
|
|
89
91
|
log('' + groups.length + ' total groups. ')
|
|
90
92
|
const gg = []
|
|
91
93
|
for (const g in selectedGroups) {
|
|
@@ -137,7 +139,7 @@ export function toolsPane (
|
|
|
137
139
|
|
|
138
140
|
for (let i = 0; i < gg.length; i++) {
|
|
139
141
|
const g = kb.sym(gg[i])
|
|
140
|
-
const a = kb
|
|
142
|
+
const a = groupMembers(kb, g)
|
|
141
143
|
log(UI.utils.label(g) + ': ' + a.length + ' members')
|
|
142
144
|
for (let j = 0; j < a.length; j++) {
|
|
143
145
|
const card = a[j]
|
|
@@ -357,6 +359,7 @@ export function toolsPane (
|
|
|
357
359
|
const other = stats.nameLessIndex[cardText]
|
|
358
360
|
if (other) {
|
|
359
361
|
log(' Matches with ' + other)
|
|
362
|
+
// alain not sure it works we may need to concat with 'sameAs' group.doc (.map(st => st.why))
|
|
360
363
|
const cardGroups = kb.each(null, ns.vcard('hasMember'), card)
|
|
361
364
|
const otherGroups = kb.each(null, ns.vcard('hasMember'), other)
|
|
362
365
|
for (let j = 0; j < cardGroups.length; j++) {
|
|
@@ -432,9 +435,9 @@ export function toolsPane (
|
|
|
432
435
|
for (let i = 0; i < stats.uniques.length; i++) {
|
|
433
436
|
stats.uniquesSet[stats.uniques[i].uri] = true
|
|
434
437
|
}
|
|
435
|
-
stats.groupMembers =
|
|
436
|
-
|
|
437
|
-
.map(
|
|
438
|
+
stats.groupMembers = []
|
|
439
|
+
kb.each(null, ns.vcard('hasMember'))
|
|
440
|
+
.map(group => { stats.groupMembers = stats.groupMembers.concat(groupMembers(kb, group)) })
|
|
438
441
|
log(' Naive group members ' + stats.groupMembers.length)
|
|
439
442
|
stats.groupMemberSet = []
|
|
440
443
|
for (let j = 0; j < stats.groupMembers.length; j++) {
|
|
@@ -575,7 +578,10 @@ export function toolsPane (
|
|
|
575
578
|
log(' Regenerating group of uniques...' + cleanGroup)
|
|
576
579
|
const data = sz.statementsToN3(sts)
|
|
577
580
|
|
|
578
|
-
return kb.fetcher.webOperation('PUT', cleanGroup, {
|
|
581
|
+
return kb.fetcher.webOperation('PUT', cleanGroup, {
|
|
582
|
+
data: data,
|
|
583
|
+
contentType: 'text/turtle'
|
|
584
|
+
})
|
|
579
585
|
})
|
|
580
586
|
.then(() => {
|
|
581
587
|
log(' Done uniques group ' + cleanGroup)
|
|
@@ -615,12 +621,14 @@ export function toolsPane (
|
|
|
615
621
|
.then(scanForDuplicates)
|
|
616
622
|
.then(checkGroupMembers)
|
|
617
623
|
.then(checkAllNameless)
|
|
618
|
-
.then((
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
+
.then(() => {
|
|
625
|
+
return new Promise(function (resolve, reject) {
|
|
626
|
+
if (confirm('Write new clean versions?')) {
|
|
627
|
+
resolve(true)
|
|
628
|
+
} else {
|
|
629
|
+
reject()
|
|
630
|
+
}
|
|
631
|
+
})
|
|
624
632
|
})
|
|
625
633
|
.then(saveCleanPeople)
|
|
626
634
|
.then(saveAllGroups)
|
|
@@ -660,13 +668,15 @@ export function toolsPane (
|
|
|
660
668
|
|
|
661
669
|
const reverseIndex = {}
|
|
662
670
|
const groupless = []
|
|
663
|
-
|
|
664
|
-
|
|
671
|
+
let groups = kb.each(book, VCARD('includesGroup'))
|
|
672
|
+
const strings = new Set(groups.map(group => group.uri)) // remove dups
|
|
673
|
+
groups = [...strings].map(uri => kb.sym(uri))
|
|
665
674
|
log('' + groups.length + ' total groups. ')
|
|
666
675
|
|
|
667
676
|
for (let i = 0; i < groups.length; i++) {
|
|
668
677
|
const g = groups[i]
|
|
669
|
-
const a = kb
|
|
678
|
+
const a = groupMembers(kb, g)
|
|
679
|
+
|
|
670
680
|
log(UI.utils.label(g) + ': ' + a.length + ' members')
|
|
671
681
|
for (let j = 0; j < a.length; j++) {
|
|
672
682
|
kb.allAliases(a[j]).forEach(function (y) {
|
|
@@ -714,6 +724,46 @@ export function toolsPane (
|
|
|
714
724
|
fixGrouplessButton.style.cssText = buttonStyle
|
|
715
725
|
fixGrouplessButton.textContent = 'Put all individuals with no group in a new group'
|
|
716
726
|
fixGrouplessButton.addEventListener('click', _event => fixGroupless(book))
|
|
727
|
+
|
|
728
|
+
async function fixToOldDataModel (book) {
|
|
729
|
+
async function updateToOldDataModel(groups) {
|
|
730
|
+
let ds = []
|
|
731
|
+
let ins = []
|
|
732
|
+
groups.forEach(group => {
|
|
733
|
+
let vcardOrWebids = kb.statementsMatching(null, ns.owl('sameAs'), null, group.doc()).map(st => st.subject)
|
|
734
|
+
const strings = new Set(vcardOrWebids.map(contact => contact.uri)) // remove dups
|
|
735
|
+
vcardOrWebids = [...strings].map(uri => kb.sym(uri))
|
|
736
|
+
vcardOrWebids.forEach(item => {
|
|
737
|
+
if (!kb.each(item, ns.vcard('fn'), null, group.doc()).length) {
|
|
738
|
+
// delete item this is a new data model, item is a webid not a card.
|
|
739
|
+
ds = ds.concat(kb
|
|
740
|
+
.statementsMatching(item, ns.owl('sameAs'), null, group.doc())
|
|
741
|
+
.concat(kb.statementsMatching(undefined, undefined, item, group.doc())))
|
|
742
|
+
// add webid card to group
|
|
743
|
+
const cards = kb.each(item, ns.owl('sameAs'), null, group.doc())
|
|
744
|
+
cards.forEach(card => {
|
|
745
|
+
ins = ins.concat($rdf.st(card, ns.owl('sameAs'), item, group.doc()))
|
|
746
|
+
.concat($rdf.st(group, ns.vcard('hasMember'), card, group.doc()))
|
|
747
|
+
})
|
|
748
|
+
}
|
|
749
|
+
})
|
|
750
|
+
})
|
|
751
|
+
if (ds.length && confirm('Groups can be updated to old data model ?')) {
|
|
752
|
+
await kb.updater.updateMany(ds, ins)
|
|
753
|
+
alert('Update done')
|
|
754
|
+
} else { if (!ds.length) alert('Nothing to update.\nAll Groups already use the old data model.')}
|
|
755
|
+
}
|
|
756
|
+
let groups = kb.each(book, VCARD('includesGroup'))
|
|
757
|
+
const strings = new Set(groups.map(group => group.uri)) // remove dups
|
|
758
|
+
groups = [...strings].map(uri => kb.sym(uri))
|
|
759
|
+
updateToOldDataModel(groups)
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const fixToOldDataModelButton = pane.appendChild(dom.createElement('button'))
|
|
763
|
+
fixToOldDataModelButton.style.cssText = buttonStyle
|
|
764
|
+
fixToOldDataModelButton.textContent = 'Revert groups to old data model'
|
|
765
|
+
fixToOldDataModelButton.addEventListener('click', _event => fixToOldDataModel(book))
|
|
766
|
+
|
|
717
767
|
} // main
|
|
718
768
|
main()
|
|
719
769
|
return pane
|
package/webidControl.js
CHANGED
|
@@ -51,12 +51,18 @@ export async function addWebIDToContacts (person, webid, urlType, kb) {
|
|
|
51
51
|
$rdf.st(vcardURLThing, ns.rdf('type'), urlType, person.doc()),
|
|
52
52
|
$rdf.st(vcardURLThing, ns.vcard('value'), webid, person.doc())
|
|
53
53
|
]
|
|
54
|
+
// insert WebID in groups
|
|
55
|
+
// replace person with WebID in vcard:hasMember (WebID may already exist)
|
|
56
|
+
// insert owl:sameAs
|
|
54
57
|
const groups = kb.each(null, ns.vcard('hasMember'), person)
|
|
58
|
+
let deletables = []
|
|
55
59
|
groups.forEach(group => {
|
|
56
|
-
|
|
60
|
+
deletables = deletables.concat(kb.statementsMatching(group, ns.vcard('hasMember'), person, group.doc()))
|
|
61
|
+
insertables.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc())) // May exist; do we need to check?
|
|
62
|
+
insertables.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), person, group.doc()))
|
|
57
63
|
})
|
|
58
64
|
try {
|
|
59
|
-
await updateMany(
|
|
65
|
+
await updateMany(deletables, insertables)
|
|
60
66
|
} catch (err) { throw new Error(`Could not create webId ${WEBID_NOUN}: ${webid}.`) }
|
|
61
67
|
}
|
|
62
68
|
|
|
@@ -79,12 +85,17 @@ export async function removeWebIDFromContacts (person, webid, urlType, kb) {
|
|
|
79
85
|
await kb.updater.update(deletables, [])
|
|
80
86
|
|
|
81
87
|
// remove webIDs from groups
|
|
82
|
-
const groups = kb.each(null, ns.vcard('hasMember'),
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
const groups = kb.each(null, ns.vcard('hasMember'), kb.sym(webid))
|
|
89
|
+
let removeFromGroups = []
|
|
90
|
+
const insertInGroups = []
|
|
91
|
+
groups.forEach(async group => {
|
|
92
|
+
removeFromGroups = removeFromGroups.concat(kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), person, group.doc()))
|
|
93
|
+
insertInGroups.push($rdf.st(group, ns.vcard('hasMember'), person, group.doc()))
|
|
94
|
+
if (kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), null, group.doc()).length < 2) {
|
|
95
|
+
removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), kb.sym(webid), group.doc()))
|
|
96
|
+
}
|
|
86
97
|
})
|
|
87
|
-
await updateMany(removeFromGroups)
|
|
98
|
+
await updateMany(removeFromGroups, insertInGroups)
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
// Trace things the same as this - other IDs for same thing
|