contacts-pane 3.0.2 → 3.0.3
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/README.md +53 -1
- package/dist/contactsPane.js +6487 -763
- package/dist/contactsPane.js.map +1 -1
- package/dist/contactsPane.min.js +2 -0
- package/dist/contactsPane.min.js.map +1 -0
- package/dist/styles/contactsPane.css +602 -0
- package/dist/styles/contactsRDFFormsEnforced.css +513 -0
- package/dist/styles/groupMembership.css +115 -0
- package/dist/styles/individual.css +12 -0
- package/dist/styles/localUtils.css +49 -0
- package/dist/styles/mugshotGallery.css +17 -0
- package/dist/styles/toolsPane.css +43 -0
- package/dist/styles/utilities.css +69 -0
- package/dist/styles/webidControl.css +90 -0
- package/package.json +23 -17
- package/dist/autocompleteBar.d.ts +0 -3
- package/dist/autocompleteBar.d.ts.map +0 -1
- package/dist/autocompleteBar.js +0 -90
- package/dist/autocompleteBar.js.map +0 -1
- package/dist/autocompleteField.d.ts +0 -20
- package/dist/autocompleteField.d.ts.map +0 -1
- package/dist/autocompleteField.js +0 -165
- package/dist/autocompleteField.js.map +0 -1
- package/dist/autocompletePicker.d.ts +0 -15
- package/dist/autocompletePicker.d.ts.map +0 -1
- package/dist/autocompletePicker.js +0 -253
- package/dist/autocompletePicker.js.map +0 -1
- package/dist/contactLogic.js +0 -223
- package/dist/contactLogic.js.map +0 -1
- package/dist/groupMembershipControl.js +0 -107
- package/dist/groupMembershipControl.js.map +0 -1
- package/dist/individual.js +0 -115
- package/dist/individual.js.map +0 -1
- package/dist/mintNewAddressBook.js +0 -145
- package/dist/mintNewAddressBook.js.map +0 -1
- package/dist/mugshotGallery.js +0 -264
- package/dist/mugshotGallery.js.map +0 -1
- package/dist/publicData.d.ts +0 -82
- package/dist/publicData.d.ts.map +0 -1
- package/dist/publicData.js +0 -421
- package/dist/publicData.js.map +0 -1
- package/dist/toolsPane.js +0 -671
- package/dist/toolsPane.js.map +0 -1
- package/dist/webidControl.js +0 -320
- package/dist/webidControl.js.map +0 -1
package/dist/toolsPane.js
DELETED
|
@@ -1,671 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.toolsPane = toolsPane;
|
|
7
|
-
var UI = _interopRequireWildcard(require("solid-ui"));
|
|
8
|
-
var _solidLogic = require("solid-logic");
|
|
9
|
-
var _contactLogic = require("./contactLogic");
|
|
10
|
-
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
11
|
-
// The tools pane is for managing and debugging and maintaining solid contacts databases
|
|
12
|
-
//
|
|
13
|
-
/* global confirm, $rdf */
|
|
14
|
-
|
|
15
|
-
function toolsPane(selectAllGroups, selectedGroups, groupsMainTable, book, dataBrowserContext, me) {
|
|
16
|
-
const dom = dataBrowserContext.dom;
|
|
17
|
-
const kb = _solidLogic.store;
|
|
18
|
-
const ns = UI.ns;
|
|
19
|
-
const VCARD = ns.vcard;
|
|
20
|
-
const buttonStyle = 'font-size: 100%; margin: 0.8em; padding:0.5em;';
|
|
21
|
-
const pane = dom.createElement('div');
|
|
22
|
-
const table = pane.appendChild(dom.createElement('table'));
|
|
23
|
-
table.setAttribute('style', 'font-size:120%; margin: 1em; border: 0.1em #ccc ;');
|
|
24
|
-
const headerRow = table.appendChild(dom.createElement('tr'));
|
|
25
|
-
headerRow.textContent = UI.utils.label(book) + ' - tools';
|
|
26
|
-
headerRow.setAttribute('style', 'min-width: 20em; padding: 1em; font-size: 150%; border-bottom: 0.1em solid red; margin-bottom: 2em;');
|
|
27
|
-
const statusRow = table.appendChild(dom.createElement('tr'));
|
|
28
|
-
const statusBlock = statusRow.appendChild(dom.createElement('div'));
|
|
29
|
-
statusBlock.setAttribute('style', 'padding: 2em;');
|
|
30
|
-
const MainRow = table.appendChild(dom.createElement('tr'));
|
|
31
|
-
const box = MainRow.appendChild(dom.createElement('table'));
|
|
32
|
-
table.appendChild(dom.createElement('tr')); // bottomRow
|
|
33
|
-
|
|
34
|
-
const context = {
|
|
35
|
-
target: book,
|
|
36
|
-
me,
|
|
37
|
-
noun: 'address book',
|
|
38
|
-
div: pane,
|
|
39
|
-
dom,
|
|
40
|
-
statusRegion: statusBlock
|
|
41
|
-
};
|
|
42
|
-
function complain(message) {
|
|
43
|
-
console.log(message);
|
|
44
|
-
statusBlock.appendChild(UI.widgets.errorMessageBlock(dom, message, 'pink'));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Body of main pane function
|
|
48
|
-
async function main() {
|
|
49
|
-
box.appendChild(UI.aclControl.ACLControlBox5(book.dir(), dataBrowserContext, 'book', kb, function (ok, body) {
|
|
50
|
-
if (!ok) box.innerHTML = 'ACL control box Failed: ' + body;
|
|
51
|
-
}));
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
try {
|
|
55
|
-
await UI.login.registrationControl(context, book, ns.vcard('AddressBook'));
|
|
56
|
-
} catch (e) {
|
|
57
|
-
UI.widgets.complain(context, 'registrationControl: ' + e);
|
|
58
|
-
}
|
|
59
|
-
console.log('Registration control finished.');
|
|
60
|
-
|
|
61
|
-
// Output stats in line mode form
|
|
62
|
-
const logSpace = MainRow.appendChild(dom.createElement('pre'));
|
|
63
|
-
function log(message) {
|
|
64
|
-
console.log(message);
|
|
65
|
-
logSpace.textContent += message + '\n';
|
|
66
|
-
}
|
|
67
|
-
function stats() {
|
|
68
|
-
const totalCards = kb.each(undefined, VCARD('inAddressBook'), book).length;
|
|
69
|
-
log('' + totalCards + ' cards loaded. ');
|
|
70
|
-
let groups = kb.each(book, VCARD('includesGroup'));
|
|
71
|
-
const strings = new Set(groups.map(group => group.uri)); // remove dups
|
|
72
|
-
groups = [...strings].map(uri => kb.sym(uri));
|
|
73
|
-
log('' + groups.length + ' total groups. ');
|
|
74
|
-
const gg = [];
|
|
75
|
-
for (const g in selectedGroups) {
|
|
76
|
-
gg.push(g);
|
|
77
|
-
}
|
|
78
|
-
log('' + gg.length + ' selected groups. ');
|
|
79
|
-
}
|
|
80
|
-
async function loadIndexHandler(_event) {
|
|
81
|
-
loadIndexButton.setAttribute('style', 'background-color: #ffc;');
|
|
82
|
-
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'));
|
|
83
|
-
try {
|
|
84
|
-
await kb.fetcher.load(nameEmailIndex);
|
|
85
|
-
} catch (e) {
|
|
86
|
-
loadIndexButton.setAttribute('style', 'background-color: #fcc;');
|
|
87
|
-
log('Error: People index has NOT been loaded' + e + '\n');
|
|
88
|
-
}
|
|
89
|
-
loadIndexButton.setAttribute('style', 'background-color: #cfc;');
|
|
90
|
-
log(' People index has been loaded\n');
|
|
91
|
-
} // loadIndexHandler
|
|
92
|
-
const loadIndexButton = pane.appendChild(dom.createElement('button'));
|
|
93
|
-
loadIndexButton.textContent = 'Load main index';
|
|
94
|
-
loadIndexButton.style.cssText = buttonStyle;
|
|
95
|
-
loadIndexButton.addEventListener('click', loadIndexHandler);
|
|
96
|
-
const statButton = pane.appendChild(dom.createElement('button'));
|
|
97
|
-
statButton.textContent = 'Statistics';
|
|
98
|
-
statButton.style.cssText = buttonStyle;
|
|
99
|
-
statButton.addEventListener('click', stats);
|
|
100
|
-
const checkAccessButton = pane.appendChild(dom.createElement('button'));
|
|
101
|
-
checkAccessButton.textContent = 'Check individual card access of selected groups';
|
|
102
|
-
checkAccessButton.style.cssText = buttonStyle;
|
|
103
|
-
async function checkAcces(_event) {
|
|
104
|
-
function doCard(card) {
|
|
105
|
-
UI.acl.fixIndividualCardACL(card, log, function (ok, message) {
|
|
106
|
-
if (ok) {
|
|
107
|
-
log('Success for ' + UI.utils.label(card));
|
|
108
|
-
} else {
|
|
109
|
-
log('Failure for ' + UI.utils.label(card) + ': ' + message);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
const gg = [];
|
|
114
|
-
for (const g in selectedGroups) {
|
|
115
|
-
gg.push(g);
|
|
116
|
-
}
|
|
117
|
-
for (let i = 0; i < gg.length; i++) {
|
|
118
|
-
const g = kb.sym(gg[i]);
|
|
119
|
-
const a = (0, _contactLogic.groupMembers)(kb, g);
|
|
120
|
-
log(UI.utils.label(g) + ': ' + a.length + ' members');
|
|
121
|
-
for (let j = 0; j < a.length; j++) {
|
|
122
|
-
const card = a[j];
|
|
123
|
-
log(UI.utils.label(card));
|
|
124
|
-
doCard(card);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
checkAccessButton.addEventListener('click', checkAcces);
|
|
129
|
-
|
|
130
|
-
// ///////////////////////////////////////////////////////////////////////////
|
|
131
|
-
//
|
|
132
|
-
// DUPLICATES CHECK
|
|
133
|
-
const checkDuplicates = pane.appendChild(dom.createElement('button'));
|
|
134
|
-
checkDuplicates.textContent = 'Find duplicate cards';
|
|
135
|
-
checkDuplicates.style.cssText = buttonStyle;
|
|
136
|
-
checkDuplicates.addEventListener('click', function (_event) {
|
|
137
|
-
const stats = {}; // global god context
|
|
138
|
-
|
|
139
|
-
stats.book = book;
|
|
140
|
-
stats.nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'));
|
|
141
|
-
log('Loading name index...');
|
|
142
|
-
_solidLogic.store.fetcher.nowOrWhenFetched(stats.nameEmailIndex, undefined, function (_ok, _message) {
|
|
143
|
-
log('Loaded name index.');
|
|
144
|
-
stats.cards = [];
|
|
145
|
-
stats.duplicates = [];
|
|
146
|
-
stats.definitive = [];
|
|
147
|
-
stats.nameless = [];
|
|
148
|
-
stats.exactDuplicates = [];
|
|
149
|
-
stats.nameOnlyDuplicates = [];
|
|
150
|
-
stats.uniquesSet = [];
|
|
151
|
-
stats.groupProblems = [];
|
|
152
|
-
|
|
153
|
-
// Erase one card and all its files -> (err)
|
|
154
|
-
//
|
|
155
|
-
/*
|
|
156
|
-
function eraseOne (card) {
|
|
157
|
-
return new Promise(function (resolve, reject) {
|
|
158
|
-
function removeFromMainIndex () {
|
|
159
|
-
var indexBit = kb.connectedStatements(card, stats.nameEmailIndex)
|
|
160
|
-
log('Bits of the name index file:' + indexBit)
|
|
161
|
-
log('Patching main index file...')
|
|
162
|
-
kb.updater.update(indexBit, [], function (uri, ok, body) {
|
|
163
|
-
if (ok) {
|
|
164
|
-
log('Success')
|
|
165
|
-
resolve(null)
|
|
166
|
-
} else {
|
|
167
|
-
log('Error patching index file! ' + body)
|
|
168
|
-
reject('Error patching index file! ' + body)
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
}
|
|
172
|
-
var filesToDelete = [ card.doc() ]
|
|
173
|
-
var photos = kb.each(card, ns.vcard('hasPhoto')) // could be > 1
|
|
174
|
-
if (photos.length) {
|
|
175
|
-
filesToDelete = filesToDelete.concat(photos)
|
|
176
|
-
}
|
|
177
|
-
filesToDelete.push(card.dir()) // the folder last
|
|
178
|
-
log('Files to delete: ' + filesToDelete)
|
|
179
|
-
if (!confirm('DELETE card ' + card.dir() + ' for "' + kb.any(card, VCARD('fn')) + '", with ' + kb.each(card).length + 'statements?')) {
|
|
180
|
-
return resolve('Cancelled by user')
|
|
181
|
-
}
|
|
182
|
-
function deleteNextFile () {
|
|
183
|
-
var resource = filesToDelete.shift()
|
|
184
|
-
if (!resource) {
|
|
185
|
-
log('All deleted')
|
|
186
|
-
removeFromMainIndex()
|
|
187
|
-
resolve()
|
|
188
|
-
}
|
|
189
|
-
log('Deleting ... ' + resource)
|
|
190
|
-
kb.fetcher.delete(resource)
|
|
191
|
-
.then(function () {
|
|
192
|
-
log('Deleted ok: ' + resource)
|
|
193
|
-
deleteNextFile()
|
|
194
|
-
})
|
|
195
|
-
.catch(function (e) {
|
|
196
|
-
var err = '*** ERROR deleting ' + resource + ': ' + e
|
|
197
|
-
log(err)
|
|
198
|
-
if (confirm('Patch out index file for card ' + card.dir() + ' EVEN THOUGH card DELETE errors?')) {
|
|
199
|
-
removeFromMainIndex()
|
|
200
|
-
} else {
|
|
201
|
-
reject(err)
|
|
202
|
-
}
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
deleteNextFile()
|
|
206
|
-
}) // Promise
|
|
207
|
-
} // erase one
|
|
208
|
-
*/
|
|
209
|
-
// Check actual records to see which are exact matches - slow
|
|
210
|
-
stats.nameDupLog = kb.sym(book.dir().uri + 'dedup-nameDupLog.ttl');
|
|
211
|
-
stats.exactDupLog = kb.sym(book.dir().uri + 'dedup-exactDupLog.ttl');
|
|
212
|
-
/*
|
|
213
|
-
function checkOne (card) {
|
|
214
|
-
return new Promise(function (resolve, reject) {
|
|
215
|
-
var name = kb.anyValue(card, ns.vcard('fn'))
|
|
216
|
-
var other = stats.definitive[name]
|
|
217
|
-
kb.fetcher.load([card, other]).then(function (xhrs) {
|
|
218
|
-
var exclude = {}
|
|
219
|
-
exclude[ns.vcard('hasUID').uri] = true
|
|
220
|
-
exclude[ns.dc('created').uri] = true
|
|
221
|
-
exclude[ns.dc('modified').uri] = true
|
|
222
|
-
function filtered (x) {
|
|
223
|
-
return kb.statementsMatching(null, null, null, x.doc()).filter(function (st) {
|
|
224
|
-
return !exclude[st.predicate.uri]
|
|
225
|
-
})
|
|
226
|
-
}
|
|
227
|
-
var desc = filtered(card)
|
|
228
|
-
var desc2 = filtered(other)
|
|
229
|
-
// var desc = connectedStatements(card, card.doc(), exclude)
|
|
230
|
-
// var desc2 = connectedStatements(other, other.doc(), exclude)
|
|
231
|
-
if (desc.length !== desc2.length) {
|
|
232
|
-
log('CARDS to NOT match lengths ')
|
|
233
|
-
stats.nameOnlyDuplicates.push(card)
|
|
234
|
-
return resolve(false)
|
|
235
|
-
}
|
|
236
|
-
if (!desc.length) {
|
|
237
|
-
log('@@@@@@ Zero length ')
|
|
238
|
-
stats.nameOnlyDuplicates.push(card)
|
|
239
|
-
return resolve(false)
|
|
240
|
-
}
|
|
241
|
-
// //////// Compare the two
|
|
242
|
-
// Cheat: serialize and compare
|
|
243
|
-
// var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')
|
|
244
|
-
// var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')
|
|
245
|
-
var cardText = (new $rdf.Serializer(kb)).setBase(card.doc().uri).statementsToN3(desc)
|
|
246
|
-
var otherText = (new $rdf.Serializer(kb)).setBase(other.doc().uri).statementsToN3(desc2)
|
|
247
|
-
//
|
|
248
|
-
// log('Name: ' + name + ', statements: ' + desc.length)
|
|
249
|
-
// log('___________________________________________')
|
|
250
|
-
// log('KEEPING: ' + other.doc() + '\n' + cardText)
|
|
251
|
-
// log('___________________________________________')
|
|
252
|
-
// log('DELETING: '+ card.doc() + '\n' + otherText)
|
|
253
|
-
// log('___________________________________________')
|
|
254
|
-
//
|
|
255
|
-
if (cardText !== otherText) {
|
|
256
|
-
log('Texts differ')
|
|
257
|
-
stats.nameOnlyDuplicates.push(card)
|
|
258
|
-
return resolve(false)
|
|
259
|
-
}
|
|
260
|
-
var cardGroups = kb.each(null, ns.vcard('hasMember'), card)
|
|
261
|
-
var otherGroups = kb.each(null, ns.vcard('hasMember'), other)
|
|
262
|
-
for (var j = 0; j < cardGroups.length; j++) {
|
|
263
|
-
var found = false
|
|
264
|
-
for (var k = 0; k < otherGroups.length; k++) {
|
|
265
|
-
if (otherGroups[k].sameTerm(cardGroups[j])) { found = true }
|
|
266
|
-
}
|
|
267
|
-
if (!found) {
|
|
268
|
-
log('This one groups: ' + cardGroups)
|
|
269
|
-
log('Other one groups: ' + otherGroups)
|
|
270
|
-
log('Cant delete this one because it has a group, ' + cardGroups[j] + ', which the other does not.')
|
|
271
|
-
stats.nameOnlyDuplicates.push(card)
|
|
272
|
-
return resolve(false)
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
console.log('Group check done -- exact duplicate: ' + card)
|
|
276
|
-
stats.exactDuplicates.push(card)
|
|
277
|
-
resolve(true)
|
|
278
|
-
}).catch(function (e) {
|
|
279
|
-
log('Cant load a card! ' + [card, other] + ': ' + e)
|
|
280
|
-
stats.nameOnlyDuplicates.push(card)
|
|
281
|
-
resolve(false)
|
|
282
|
-
// if (confirm('Patch out index file for card ' + card.dir() + ' EVEN THOUGH card READ errors?')){
|
|
283
|
-
// removeFromMainIndex()
|
|
284
|
-
// }
|
|
285
|
-
})
|
|
286
|
-
})
|
|
287
|
-
} // checkOne
|
|
288
|
-
*/
|
|
289
|
-
stats.nameOnlyErrors = [];
|
|
290
|
-
stats.nameLessZeroData = [];
|
|
291
|
-
stats.nameLessIndex = [];
|
|
292
|
-
stats.namelessUniques = [];
|
|
293
|
-
stats.nameOnlyDuplicatesGroupDiff = [];
|
|
294
|
-
function checkOneNameless(card) {
|
|
295
|
-
return new Promise(function (resolve) {
|
|
296
|
-
kb.fetcher.load(card).then(function (_xhr) {
|
|
297
|
-
log(' Nameless check ' + card);
|
|
298
|
-
const exclude = {};
|
|
299
|
-
exclude[ns.vcard('hasUID').uri] = true;
|
|
300
|
-
exclude[ns.dc('created').uri] = true;
|
|
301
|
-
exclude[ns.dc('modified').uri] = true;
|
|
302
|
-
function filtered(x) {
|
|
303
|
-
return kb.statementsMatching(null, null, null, x.doc()).filter(function (st) {
|
|
304
|
-
return !exclude[st.predicate.uri];
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
const desc = filtered(card);
|
|
308
|
-
// var desc = connectedStatements(card, card.doc(), exclude)
|
|
309
|
-
// var desc2 = connectedStatements(other, other.doc(), exclude)
|
|
310
|
-
if (!desc.length) {
|
|
311
|
-
log(' Zero length ' + card);
|
|
312
|
-
stats.nameLessZeroData.push(card);
|
|
313
|
-
return resolve(false);
|
|
314
|
-
}
|
|
315
|
-
// Compare the two
|
|
316
|
-
// Cheat: serialize and compare
|
|
317
|
-
// var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')
|
|
318
|
-
// var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')
|
|
319
|
-
const cardText = new $rdf.Serializer(kb).setBase(card.doc().uri).statementsToN3(desc);
|
|
320
|
-
const other = stats.nameLessIndex[cardText];
|
|
321
|
-
if (other) {
|
|
322
|
-
log(' Matches with ' + other);
|
|
323
|
-
// alain not sure it works we may need to concat with 'sameAs' group.doc (.map(st => st.why))
|
|
324
|
-
const cardGroups = kb.each(null, ns.vcard('hasMember'), card);
|
|
325
|
-
const otherGroups = kb.each(null, ns.vcard('hasMember'), other);
|
|
326
|
-
for (let j = 0; j < cardGroups.length; j++) {
|
|
327
|
-
let found = false;
|
|
328
|
-
for (let k = 0; k < otherGroups.length; k++) {
|
|
329
|
-
if (otherGroups[k].sameTerm(cardGroups[j])) found = true;
|
|
330
|
-
}
|
|
331
|
-
if (!found) {
|
|
332
|
-
log('This one groups: ' + cardGroups);
|
|
333
|
-
log('Other one groups: ' + otherGroups);
|
|
334
|
-
log('Cant skip this one because it has a group, ' + cardGroups[j] + ', which the other does not.');
|
|
335
|
-
stats.nameOnlyDuplicatesGroupDiff.push(card);
|
|
336
|
-
return resolve(false);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
console.log('Group check done -- exact duplicate: ' + card);
|
|
340
|
-
} else {
|
|
341
|
-
log('First nameless like: ' + card.doc());
|
|
342
|
-
log('___________________________________________');
|
|
343
|
-
log(cardText);
|
|
344
|
-
log('___________________________________________');
|
|
345
|
-
stats.nameLessIndex[cardText] = card;
|
|
346
|
-
stats.namelessUniques.push(card);
|
|
347
|
-
}
|
|
348
|
-
resolve(true);
|
|
349
|
-
}).catch(function (e) {
|
|
350
|
-
log('Cant load a nameless card!: ' + e);
|
|
351
|
-
stats.nameOnlyErrors.push(card);
|
|
352
|
-
resolve(false);
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
} // checkOneNameless
|
|
356
|
-
|
|
357
|
-
function checkAllNameless() {
|
|
358
|
-
stats.namelessToCheck = stats.namelessToCheck || stats.nameless.slice();
|
|
359
|
-
log('Nameless check left: ' + stats.namelessToCheck.length);
|
|
360
|
-
return new Promise(function (resolve) {
|
|
361
|
-
const x = stats.namelessToCheck.shift();
|
|
362
|
-
if (!x) {
|
|
363
|
-
log('namelessUniques: ' + stats.namelessUniques.length);
|
|
364
|
-
log('namelessUniques: ' + stats.namelessUniques);
|
|
365
|
-
if (stats.namelessUniques.length > 0 && confirm('Add all ' + stats.namelessUniques.length + ' nameless cards to the rescued set?')) {
|
|
366
|
-
stats.uniques = stats.uniques.concat(stats.namelessUniques);
|
|
367
|
-
for (let k = 0; k < stats.namelessUniques.length; k++) {
|
|
368
|
-
stats.uniqueSet[stats.namelessUniques[k].uri] = true;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return resolve(true);
|
|
372
|
-
}
|
|
373
|
-
checkOneNameless(x).then(function (exact) {
|
|
374
|
-
log(' Nameless check returns ' + exact);
|
|
375
|
-
checkAllNameless(); // loop
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
function checkGroupMembers() {
|
|
380
|
-
return new Promise(function (resolve) {
|
|
381
|
-
// var inUniques = 0
|
|
382
|
-
log('Groups loaded');
|
|
383
|
-
for (let i = 0; i < stats.uniques.length; i++) {
|
|
384
|
-
stats.uniquesSet[stats.uniques[i].uri] = true;
|
|
385
|
-
}
|
|
386
|
-
stats.groupMembers = [];
|
|
387
|
-
kb.each(null, ns.vcard('hasMember')).forEach(group => {
|
|
388
|
-
stats.groupMembers = stats.groupMembers.concat((0, _contactLogic.groupMembers)(kb, group));
|
|
389
|
-
});
|
|
390
|
-
log(' Naive group members ' + stats.groupMembers.length);
|
|
391
|
-
stats.groupMemberSet = [];
|
|
392
|
-
for (let j = 0; j < stats.groupMembers.length; j++) {
|
|
393
|
-
stats.groupMemberSet[stats.groupMembers[j].uri] = stats.groupMembers[j];
|
|
394
|
-
}
|
|
395
|
-
stats.groupMembers2 = [];
|
|
396
|
-
for (const g in stats.groupMemberSet) {
|
|
397
|
-
stats.groupMembers2.push(stats.groupMemberSet[g]);
|
|
398
|
-
}
|
|
399
|
-
log(' Compact group members ' + stats.groupMembers2.length);
|
|
400
|
-
if ($rdf.keepThisCodeForLaterButDisableFerossConstantConditionPolice) {
|
|
401
|
-
// Don't inspect as seems groups membership is complete
|
|
402
|
-
for (let i = 0; i < stats.groupMembers.length; i++) {
|
|
403
|
-
const card = stats.groupMembers[i];
|
|
404
|
-
if (stats.uniquesSet[card.uri]) {
|
|
405
|
-
// inUniques += 1
|
|
406
|
-
} else {
|
|
407
|
-
log(' Not in uniques: ' + card);
|
|
408
|
-
stats.groupProblems.push(card);
|
|
409
|
-
if (stats.duplicateSet[card.uri]) {
|
|
410
|
-
log(' ** IN duplicates alas:' + card);
|
|
411
|
-
} else {
|
|
412
|
-
log(' **** WTF?');
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
log('Problem cards: ' + stats.groupProblems.length);
|
|
417
|
-
} // if
|
|
418
|
-
resolve(true);
|
|
419
|
-
});
|
|
420
|
-
} // checkGroupMembers
|
|
421
|
-
|
|
422
|
-
function scanForDuplicates() {
|
|
423
|
-
return new Promise(function (resolve) {
|
|
424
|
-
stats.cards = kb.each(undefined, VCARD('inAddressBook'), stats.book);
|
|
425
|
-
log('' + stats.cards.length + ' total cards');
|
|
426
|
-
let c, card, name;
|
|
427
|
-
for (c = 0; c < stats.cards.length; c++) {
|
|
428
|
-
card = stats.cards[c];
|
|
429
|
-
name = kb.anyValue(card, ns.vcard('fn'));
|
|
430
|
-
if (!name) {
|
|
431
|
-
stats.nameless.push(card);
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
if (stats.definitive[name] === card) {
|
|
435
|
-
// pass
|
|
436
|
-
} else if (stats.definitive[name]) {
|
|
437
|
-
const n = stats.duplicates.length;
|
|
438
|
-
if (n < 100 || n < 1000 && n % 10 === 0 || n % 100 === 0) {
|
|
439
|
-
// log('' + n + ') Possible duplicate ' + card + ' of: ' + definitive[name])
|
|
440
|
-
}
|
|
441
|
-
stats.duplicates.push(card);
|
|
442
|
-
} else {
|
|
443
|
-
stats.definitive[name] = card;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
stats.duplicateSet = [];
|
|
447
|
-
for (let i = 0; i < stats.duplicates.length; i++) {
|
|
448
|
-
stats.duplicateSet[stats.duplicates[i].uri] = stats.duplicates[i];
|
|
449
|
-
}
|
|
450
|
-
stats.namelessSet = [];
|
|
451
|
-
for (let i = 0; i < stats.nameless.length; i++) {
|
|
452
|
-
stats.namelessSet[stats.nameless[i].uri] = stats.nameless[i];
|
|
453
|
-
}
|
|
454
|
-
stats.uniques = [];
|
|
455
|
-
stats.uniqueSet = [];
|
|
456
|
-
for (let i = 0; i < stats.cards.length; i++) {
|
|
457
|
-
const uri = stats.cards[i].uri;
|
|
458
|
-
if (!stats.duplicateSet[uri] && !stats.namelessSet[uri]) {
|
|
459
|
-
stats.uniques.push(stats.cards[i]);
|
|
460
|
-
stats.uniqueSet[uri] = stats.cards[i];
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
log('Uniques: ' + stats.uniques.length);
|
|
464
|
-
log('' + stats.nameless.length + ' nameless cards.');
|
|
465
|
-
log('' + stats.duplicates.length + ' name-duplicate cards, leaving ' + (stats.cards.length - stats.duplicates.length));
|
|
466
|
-
resolve(true);
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Save a new clean version
|
|
471
|
-
function saveCleanPeople() {
|
|
472
|
-
let cleanPeople;
|
|
473
|
-
return Promise.resolve().then(() => {
|
|
474
|
-
cleanPeople = kb.sym(stats.book.dir().uri + 'clean-people.ttl');
|
|
475
|
-
let sts = [];
|
|
476
|
-
for (let i = 0; i < stats.uniques.length; i++) {
|
|
477
|
-
sts = sts.concat(kb.connectedStatements(stats.uniques[i], stats.nameEmailIndex));
|
|
478
|
-
}
|
|
479
|
-
const sz = new $rdf.Serializer(kb).setBase(stats.nameEmailIndex.uri);
|
|
480
|
-
log('Serializing index of uniques...');
|
|
481
|
-
const data = sz.statementsToN3(sts);
|
|
482
|
-
return kb.fetcher.webOperation('PUT', cleanPeople, {
|
|
483
|
-
data,
|
|
484
|
-
contentType: 'text/turtle'
|
|
485
|
-
});
|
|
486
|
-
}).then(function () {
|
|
487
|
-
log('Done uniques log ' + cleanPeople);
|
|
488
|
-
return true;
|
|
489
|
-
}).catch(function (e) {
|
|
490
|
-
log('Error saving uniques: ' + e);
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
function saveCleanGroup(g) {
|
|
494
|
-
let cleanGroup;
|
|
495
|
-
return Promise.resolve().then(() => {
|
|
496
|
-
const s = g.uri.replace('/Group/', '/NewGroup/');
|
|
497
|
-
cleanGroup = kb.sym(s);
|
|
498
|
-
let sts = [];
|
|
499
|
-
for (let i = 0; i < stats.uniques.length; i++) {
|
|
500
|
-
sts = sts.concat(kb.connectedStatements(stats.uniques[i], g.doc()));
|
|
501
|
-
}
|
|
502
|
-
const sz = new $rdf.Serializer(kb).setBase(g.uri);
|
|
503
|
-
log(' Regenerating group of uniques...' + cleanGroup);
|
|
504
|
-
const data = sz.statementsToN3(sts);
|
|
505
|
-
return kb.fetcher.webOperation('PUT', cleanGroup, {
|
|
506
|
-
data,
|
|
507
|
-
contentType: 'text/turtle'
|
|
508
|
-
});
|
|
509
|
-
}).then(() => {
|
|
510
|
-
log(' Done uniques group ' + cleanGroup);
|
|
511
|
-
return true;
|
|
512
|
-
}).catch(e => {
|
|
513
|
-
log('Error saving : ' + e);
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
function saveAllGroups() {
|
|
517
|
-
log('Saving ALL GROUPS');
|
|
518
|
-
return Promise.all(stats.groupObjects.map(saveCleanGroup));
|
|
519
|
-
}
|
|
520
|
-
const getAndSortGroups = function () {
|
|
521
|
-
let groups = [];
|
|
522
|
-
if (stats.book) {
|
|
523
|
-
const books = [stats.book];
|
|
524
|
-
books.forEach(function (book) {
|
|
525
|
-
const gs = book ? kb.each(book, ns.vcard('includesGroup')) : [];
|
|
526
|
-
const gs2 = gs.map(function (g) {
|
|
527
|
-
return [book, kb.any(g, ns.vcard('fn')), g];
|
|
528
|
-
});
|
|
529
|
-
groups = groups.concat(gs2);
|
|
530
|
-
});
|
|
531
|
-
groups.sort();
|
|
532
|
-
}
|
|
533
|
-
return groups;
|
|
534
|
-
};
|
|
535
|
-
const groups = getAndSortGroups(); // Needed?
|
|
536
|
-
|
|
537
|
-
stats.groupObjects = groups.map(gstr => gstr[2]);
|
|
538
|
-
log('Loading ' + stats.groupObjects.length + ' groups... ');
|
|
539
|
-
kb.fetcher.load(stats.groupObjects).then(scanForDuplicates).then(checkGroupMembers).then(checkAllNameless).then(() => {
|
|
540
|
-
return new Promise(function (resolve, reject) {
|
|
541
|
-
if (confirm('Write new clean versions?')) {
|
|
542
|
-
resolve(true);
|
|
543
|
-
} else {
|
|
544
|
-
reject(new Error('User cancelled writing clean versions'));
|
|
545
|
-
}
|
|
546
|
-
});
|
|
547
|
-
}).then(saveCleanPeople).then(saveAllGroups).then(function () {
|
|
548
|
-
log('Done!');
|
|
549
|
-
});
|
|
550
|
-
});
|
|
551
|
-
});
|
|
552
|
-
async function fixGroupless(book) {
|
|
553
|
-
const groupless = await getGroupless(book);
|
|
554
|
-
if (groupless.length === 0) {
|
|
555
|
-
log('No groupless cards found.');
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
const groupOfUngrouped = await (0, _contactLogic.saveNewGroup)(book, 'ZSortThese');
|
|
559
|
-
if (confirm(`Add the ${groupless.length} cards without groups to a ZSortThese group?`)) {
|
|
560
|
-
for (const person of groupless) {
|
|
561
|
-
log(' adding ' + person);
|
|
562
|
-
await (0, _contactLogic.addPersonToGroup)(person, groupOfUngrouped);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
log('People moved to group.');
|
|
566
|
-
}
|
|
567
|
-
async function getGroupless(book) {
|
|
568
|
-
const groupIndex = kb.any(book, ns.vcard('groupIndex'));
|
|
569
|
-
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'));
|
|
570
|
-
try {
|
|
571
|
-
await kb.fetcher.load([nameEmailIndex, groupIndex]);
|
|
572
|
-
const groups = kb.each(book, ns.vcard('includesGroup'));
|
|
573
|
-
await kb.fetcher.load(groups);
|
|
574
|
-
} catch (e) {
|
|
575
|
-
complain('Error loading stuff:' + e);
|
|
576
|
-
}
|
|
577
|
-
const reverseIndex = {};
|
|
578
|
-
const groupless = [];
|
|
579
|
-
let groups = kb.each(book, VCARD('includesGroup'));
|
|
580
|
-
const strings = new Set(groups.map(group => group.uri)); // remove dups
|
|
581
|
-
groups = [...strings].map(uri => kb.sym(uri));
|
|
582
|
-
log('' + groups.length + ' total groups. ');
|
|
583
|
-
for (let i = 0; i < groups.length; i++) {
|
|
584
|
-
const g = groups[i];
|
|
585
|
-
const a = (0, _contactLogic.groupMembers)(kb, g);
|
|
586
|
-
log(UI.utils.label(g) + ': ' + a.length + ' members');
|
|
587
|
-
for (let j = 0; j < a.length; j++) {
|
|
588
|
-
kb.allAliases(a[j]).forEach(function (y) {
|
|
589
|
-
reverseIndex[y.uri] = g;
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
const cards = kb.each(undefined, VCARD('inAddressBook'), book);
|
|
594
|
-
log('' + cards.length + ' total cards');
|
|
595
|
-
for (let c = 0; c < cards.length; c++) {
|
|
596
|
-
if (!reverseIndex[cards[c].uri]) {
|
|
597
|
-
groupless.push(cards[c]);
|
|
598
|
-
log(' groupless ' + UI.utils.label(cards[c]));
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
log('' + groupless.length + ' groupless cards.');
|
|
602
|
-
return groupless;
|
|
603
|
-
}
|
|
604
|
-
const checkGroupless = pane.appendChild(dom.createElement('button'));
|
|
605
|
-
checkGroupless.style.cssText = buttonStyle;
|
|
606
|
-
checkGroupless.textContent = 'Find individuals with no group';
|
|
607
|
-
checkGroupless.addEventListener('click', function (_event) {
|
|
608
|
-
log('Loading groups...');
|
|
609
|
-
selectAllGroups(selectedGroups, groupsMainTable, async function (ok, message) {
|
|
610
|
-
if (!ok) {
|
|
611
|
-
log('Load all groups: failed: ' + message);
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'));
|
|
615
|
-
try {
|
|
616
|
-
await kb.fetcher.load(nameEmailIndex);
|
|
617
|
-
} catch (e) {
|
|
618
|
-
complain(e);
|
|
619
|
-
}
|
|
620
|
-
log('Loaded groups and name index.');
|
|
621
|
-
getGroupless(book);
|
|
622
|
-
log('Groupless list finished..');
|
|
623
|
-
}); // select all groups then
|
|
624
|
-
});
|
|
625
|
-
const fixGrouplessButton = pane.appendChild(dom.createElement('button'));
|
|
626
|
-
fixGrouplessButton.style.cssText = buttonStyle;
|
|
627
|
-
fixGrouplessButton.textContent = 'Put all individuals with no group in a new group';
|
|
628
|
-
fixGrouplessButton.addEventListener('click', _event => fixGroupless(book));
|
|
629
|
-
async function fixToOldDataModel(book) {
|
|
630
|
-
async function updateToOldDataModel(groups) {
|
|
631
|
-
let ds = [];
|
|
632
|
-
let ins = [];
|
|
633
|
-
groups.forEach(group => {
|
|
634
|
-
let vcardOrWebids = kb.statementsMatching(null, ns.owl('sameAs'), null, group.doc()).map(st => st.subject);
|
|
635
|
-
const strings = new Set(vcardOrWebids.map(contact => contact.uri)); // remove dups
|
|
636
|
-
vcardOrWebids = [...strings].map(uri => kb.sym(uri));
|
|
637
|
-
vcardOrWebids.forEach(item => {
|
|
638
|
-
if (!kb.each(item, ns.vcard('fn'), null, group.doc()).length) {
|
|
639
|
-
// delete item this is a new data model, item is a webid not a card.
|
|
640
|
-
ds = ds.concat(kb.statementsMatching(item, ns.owl('sameAs'), null, group.doc()).concat(kb.statementsMatching(undefined, undefined, item, group.doc())));
|
|
641
|
-
// add webid card to group
|
|
642
|
-
const cards = kb.each(item, ns.owl('sameAs'), null, group.doc());
|
|
643
|
-
cards.forEach(card => {
|
|
644
|
-
ins = ins.concat($rdf.st(card, ns.owl('sameAs'), item, group.doc())).concat($rdf.st(group, ns.vcard('hasMember'), card, group.doc()));
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
if (ds.length && confirm('Groups can be updated to old data model ?')) {
|
|
650
|
-
await kb.updater.updateMany(ds, ins);
|
|
651
|
-
alert('Update done');
|
|
652
|
-
} else {
|
|
653
|
-
if (!ds.length) alert('Nothing to update.\nAll Groups already use the old data model.');
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
let groups = kb.each(book, VCARD('includesGroup'));
|
|
657
|
-
const strings = new Set(groups.map(group => group.uri)); // remove dups
|
|
658
|
-
groups = [...strings].map(uri => kb.sym(uri));
|
|
659
|
-
updateToOldDataModel(groups);
|
|
660
|
-
}
|
|
661
|
-
const fixToOldDataModelButton = pane.appendChild(dom.createElement('button'));
|
|
662
|
-
fixToOldDataModelButton.style.cssText = buttonStyle;
|
|
663
|
-
fixToOldDataModelButton.textContent = 'Revert groups to old data model';
|
|
664
|
-
fixToOldDataModelButton.addEventListener('click', _event => fixToOldDataModel(book));
|
|
665
|
-
} // main
|
|
666
|
-
main();
|
|
667
|
-
return pane;
|
|
668
|
-
} // toolsPane
|
|
669
|
-
|
|
670
|
-
// ends
|
|
671
|
-
//# sourceMappingURL=toolsPane.js.map
|