contacts-pane 2.6.3 → 2.6.4-2fcf4012

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 CHANGED
File without changes
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(group, ns.vcard('hasMember'), thing, group.doc())
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.forEach(webid => {
156
- ins.push($rdf.st(thing, ns.owl('sameAs'), kb.sym(webid), group.doc()))
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,20 @@ 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
+ b = contacts.length ? b.concat(contacts) : b.concat(item)
183
+ })
184
+ const strings = new Set(b.map(contact => contact.uri)) // remove dups
185
+ b = [...strings].map(uri => kb.sym(uri))
186
+ return b
187
+ }
188
+
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
- // - delete the reference in people.ttl and save it back
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
- const a = kb.each(group, ns.vcard('hasMember'), null, group.doc())
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
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
- const groups = kb.each(null, ns.vcard('hasMember'), thing)
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
- const del = kb
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
- const groups = kb.each(null, ns.vcard('hasMember'), person)
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
File without changes
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
@@ -1,6 +1,7 @@
1
1
  import * as UI from 'solid-ui'
2
- import { setACLUserPublic } from 'solid-logic'
2
+ import { solidLogicSingleton } from 'solid-logic'
3
3
 
4
+ const { setACLUserPublic } = solidLogicSingleton.acl
4
5
  // const mime = require('mime-types')
5
6
  // const toolsPane0 = require('./toolsPane')
6
7
  // const toolsPane = toolsPane0.toolsPane
package/mugshotGallery.js CHANGED
@@ -200,8 +200,18 @@ export function renderMugshotGallery (dom, subject) {
200
200
  droppedFileHandler
201
201
  )
202
202
  if (image) {
203
- img.setAttribute('src', image.uri)
203
+ // img.setAttribute('src', image.uri) use token and works with NSS but not with CSS
204
+ // we need to get image with authenticated fetch
205
+ store.fetcher._fetch(image.uri)
206
+ .then(function(response) {
207
+ return response.blob()
208
+ })
209
+ .then(function(myBlob) {
210
+ const objectURL = URL.createObjectURL(myBlob)
211
+ img.setAttribute('src', objectURL)
212
+ })
204
213
  UI.widgets.makeDraggable(img, image)
214
+
205
215
  }
206
216
  return img
207
217
  }
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contacts-pane",
3
- "version": "2.6.3",
3
+ "version": "2.6.4-2fcf4012",
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,19 +37,19 @@
37
37
  },
38
38
  "homepage": "https://github.com/solid/contacts-pane",
39
39
  "dependencies": {
40
- "pane-registry": "^2.4.10",
41
- "rdflib": "^2.2.19",
42
- "solid-logic": "^1.3.17",
43
- "solid-ui": "^2.4.22"
40
+ "pane-registry": "2.4.12",
41
+ "rdflib": "^2.2.20",
42
+ "solid-logic": "2.0.0",
43
+ "solid-ui": "2.4.23"
44
44
  },
45
45
  "devDependencies": {
46
- "@typescript-eslint/eslint-plugin": "^5.19.0",
47
- "@typescript-eslint/parser": "^5.19.0",
48
- "eslint": "^8.13.0",
46
+ "@typescript-eslint/eslint-plugin": "^5.36.1",
47
+ "@typescript-eslint/parser": "^5.36.1",
48
+ "eslint": "^8.23.0",
49
49
  "eslint-plugin-import": "^2.26.0",
50
- "husky": "^7.0.4",
51
- "lint-staged": "^12.3.7",
52
- "typescript": "^4.6.3",
50
+ "husky": "^8.0.1",
51
+ "lint-staged": "^13.0.3",
52
+ "typescript": "^4.8.2",
53
53
  "typescript-transpile-only": "0.0.4"
54
54
  },
55
55
  "husky": {
File without changes
File without changes
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
- const groups = kb.each(book, VCARD('includesGroup'))
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.each(g, ns.vcard('hasMember'))
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 = kb
436
- .statementsMatching(null, ns.vcard('hasMember'))
437
- .map(st => st.object)
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, { data })
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((resolve, reject) => {
619
- if (confirm('Write new clean versions?')) {
620
- resolve(true)
621
- } else {
622
- reject()
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
- const groups = kb.each(book, VCARD('includesGroup'))
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.each(g, ns.vcard('hasMember'))
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) {
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
- insertables.push($rdf.st(person, ns.owl('sameAs'), kb.sym(webid), group.doc()))
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([], insertables)
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'), person)
83
- const removeFromGroups = []
84
- groups.forEach(group => {
85
- removeFromGroups.push($rdf.st(person, ns.owl('sameAs'), kb.sym(webid), group.doc()))
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