contacts-pane
Advanced tools
Comparing version 2.4.9 to 2.4.12-beta4
// Logic for solid contacts | ||
import * as UI from 'solid-ui' | ||
import { store } from 'solid-logic' | ||
import { getPersonas } from './webidControl' | ||
@@ -9,3 +10,3 @@ | ||
const utils = UI.utils | ||
const kb = UI.store | ||
const kb = store | ||
const updater = kb.updater | ||
@@ -33,2 +34,3 @@ | ||
export async function saveNewContact (book, name, selectedGroups, klass) { | ||
await kb.fetcher.load(book.doc()) | ||
const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex')) | ||
@@ -65,5 +67,5 @@ | ||
try { | ||
await updateMany([], agenda) // @@ in future, updater.updateMany | ||
await updater.updateMany([], agenda) // @@ in future, updater.updateMany | ||
} catch (e) { | ||
console.log("Error: can't update " + person + ' as new contact:' + e) | ||
console.error("Error: can't update " + person + ' as new contact:' + e) | ||
throw new Error('Updating new contact: ' + e) | ||
@@ -84,2 +86,3 @@ } | ||
export async function saveNewGroup (book, name) { | ||
await kb.fetcher.load(book.doc()) | ||
const gix = kb.any(book, ns.vcard('groupIndex')) | ||
@@ -90,3 +93,3 @@ | ||
const doc = group.doc() | ||
console.log(' New group will be: ' + group + '\n') | ||
// console.log(' New group will be: ' + group + '\n') | ||
try { | ||
@@ -134,3 +137,3 @@ await kb.fetcher.load(gix) | ||
for (const ty in types) { | ||
console.log(' drop object type includes: ' + ty) // @@ Allow email addresses and phone numbers to be dropped? | ||
// console.log(' drop object type includes: ' + ty) // @@ Allow email addresses and phone numbers to be dropped? | ||
} | ||
@@ -144,3 +147,3 @@ if (!(ns.vcard('Individual').uri in types || | ||
if (!pname) { return alert('No vcard name known for ' + thing) } | ||
const already = kb.holds(group, ns.vcard('hasMember'), thing, group.doc()) | ||
const already = kb.holds(thing, ns.vcard('fn'), null, group.doc()) | ||
if (already) { | ||
@@ -154,10 +157,14 @@ return alert( | ||
const ins = [ | ||
$rdf.st(group, ns.vcard('hasMember'), thing, group.doc()), | ||
$rdf.st(thing, ns.vcard('fn'), pname, group.doc()) | ||
] | ||
// find person webIDs | ||
// find person webIDs and insert in vcard:hasMember | ||
const webIDs = getPersonas(kb, thing).map(webid => webid.value) | ||
webIDs.forEach(webid => { | ||
ins.push($rdf.st(thing, ns.owl('sameAs'), kb.sym(webid), group.doc())) | ||
}) | ||
if (webIDs.length) { | ||
webIDs.forEach(webid => { | ||
ins.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), thing, group.doc())) | ||
ins.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc())) | ||
}) | ||
} else { | ||
ins.push($rdf.st(group, ns.vcard('hasMember'), thing, group.doc())) | ||
} | ||
try { | ||
@@ -167,3 +174,3 @@ await updater.update([], ins) | ||
kb.fetcher.unload(group.doc()) | ||
kb.fetcher.load(group.doc()) | ||
await kb.fetcher.load(group.doc()) | ||
} catch (e) { | ||
@@ -174,1 +181,62 @@ throw new Error(`Error adding ${pname} to group ${gname}:` + e) | ||
} | ||
/** | ||
* Find persons member of a group | ||
*/ | ||
export function groupMembers (kb, group) { | ||
const a = kb.each(group, ns.vcard('hasMember'), null, group.doc()) | ||
let b = [] | ||
a.forEach(item => { | ||
/* const contacts = kb.each(item, ns.owl('sameAs'), null, group.doc()) | ||
if (contacts.length) { | ||
if (!kb.any(contacts[0], ns.vard('fn'))) b = b.concat(item) // this is the old data model | ||
else b = b.concat(contacts) | ||
} else { b = b.concat(item) } | ||
b = b.concat(item) */ | ||
// to keep compatibility with old data model | ||
// check if item is a contact, else it is a WebID and parse 'sameAs' for contacts | ||
b = kb.any(item, ns.vcard('fn'), null, group.doc()) ? b.concat(item) : b.concat(kb.each(item, ns.owl('sameAs'), null, group.doc())) | ||
}) | ||
const strings = new Set(b.map(contact => contact.uri)) // remove dups | ||
b = [...strings].map(uri => kb.sym(uri)) | ||
return b | ||
} | ||
export function isLocal(group, item) { | ||
const tree = group.dir().dir().dir() | ||
const local = item.uri && item.uri.startsWith(tree.uri) | ||
// console.log(` isLocal ${local} for ${item.uri} in group ${group} tree ${tree.uri}`) | ||
return local | ||
} | ||
export function getSameAs(kb, item, doc) { | ||
return kb.each(item, ns.owl('sameAs'), null, doc).concat( | ||
kb.each(null, ns.owl('sameAs'), item, doc)) | ||
} | ||
export async function getDataModelIssues(groups) { | ||
let del = [] | ||
let ins = [] | ||
groups.forEach(group => { | ||
const members = kb.each(group, ns.vcard('hasMember'), null, group.doc()) | ||
members.forEach((member) => { | ||
const others = getSameAs(kb, member, group.doc()) | ||
if (others.length && isLocal(group, member)) { // Problem: local ID used instead of webID | ||
for (const other of others) { | ||
if (!isLocal(group, other)) { // Let's use this one as the immediate member for CSS ACLs' | ||
// console.warn(`getDataModelIssues: Need to swap ${member} to ${other}`) | ||
del.push($rdf.st(group, ns.vcard('hasMember'), member, group.doc())) | ||
ins.push($rdf.st(group, ns.vcard('hasMember'), other, group.doc())) | ||
break | ||
} | ||
// console.log('getDataModelIssues: ??? expected id not to be local ' + other) | ||
} // other | ||
} // if | ||
}) // member | ||
}) // next group | ||
return {del, ins } | ||
} // getDataModelIssues | ||
// Ends |
@@ -17,7 +17,10 @@ /* Contact AddressBook Pane | ||
import { authn } from 'solid-logic' | ||
import { addPersonToGroup, saveNewContact, saveNewGroup, groupMembers } from './contactLogic' | ||
import * as UI from 'solid-ui' | ||
import { toolsPane } from './toolsPane' | ||
import { mintNewAddressBook } from './mintNewAddressBook' | ||
import { renderIndividual } from './individual' | ||
import { saveNewContact, saveNewGroup, addPersonToGroup } from './contactLogic' | ||
import { toolsPane } from './toolsPane' | ||
import { groupMembership } from './groupMembershipControl' | ||
import { getDataModelIssues } from './contactLogic' | ||
@@ -67,3 +70,3 @@ // const $rdf = UI.rdf | ||
function newAddressBookButton (thisAddressBook) { | ||
return UI.authn.newAppInstance( | ||
return UI.login.newAppInstance( | ||
dom, | ||
@@ -84,3 +87,3 @@ { noun: 'address book', appPathSegment: 'contactorator.timbl.com' }, | ||
const div = dom.createElement('div') | ||
const me = UI.authn.currentUser() // If already logged on | ||
const me = authn.currentUser() // If already logged on | ||
@@ -92,3 +95,3 @@ UI.aclControl.preventBrowserDropEvents(dom) // protect drag and drop | ||
asyncRender().then( | ||
() => console.log('contctsPane Rendered ' + subject), | ||
() => console.log('contactsPane Rendered ' + subject), | ||
err => complain('' + err)) | ||
@@ -103,3 +106,3 @@ return div | ||
let me = UI.authn.currentUser() | ||
let me = authn.currentUser() | ||
@@ -224,4 +227,21 @@ const context = { | ||
// - delete person's WebID's in each Group | ||
// - delete the references to it in group files and save them back | ||
// - delete the reference in people.ttl and save it back | ||
// - delete the reference in people.ttl and save it back | ||
// find all Groups | ||
const groups = groupMembership(person) | ||
let removeFromGroups = [] | ||
// find person WebID's | ||
groups.map( group => { | ||
const webids = getSameAs(kb, person, group.doc()) | ||
// for each check in each Group that it is not used by an other person then delete | ||
webids.map( webid => { | ||
if (getSameAs(kb, webid, group.doc()).length = 1) { | ||
removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), webid, group.doc())) | ||
} | ||
}) | ||
}) | ||
// console.log(removeFromGroups) | ||
await kb.updater.updateMany(removeFromGroups) | ||
await deleteThingAndDoc(person) | ||
@@ -302,4 +322,6 @@ await deleteRecursive(kb, container) | ||
async function loadAllGroups () { | ||
await kb.fetcher.load(groupIndex) | ||
const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : [] | ||
await kb.fetcher.load(gs) | ||
return gs | ||
} | ||
@@ -426,4 +448,3 @@ | ||
if (selectedGroups[group.value]) { | ||
const a = kb.each(group, ns.vcard('hasMember'), null, group.doc()) | ||
cards = cards.concat(a) | ||
cards = cards.concat(groupMembers(kb, group)) | ||
} | ||
@@ -588,4 +609,18 @@ }) | ||
refreshGroupsSelected() | ||
// await checkDataModel(groups) | ||
} // syncGroupTable | ||
async function checkDataModel () { | ||
// await kb.fetcher.load(groups) // asssume loaded already | ||
const groups = await loadAllGroups() | ||
const { del, ins } = await getDataModelIssues(groups) | ||
if (del.length && confirm(`Groups data model need to be updated? (${del.length})`)) { | ||
await kb.updater.updateMany(del, ins) | ||
alert('Update done') | ||
} | ||
} // checkDataModel | ||
// Click on New Group button | ||
@@ -596,3 +631,3 @@ async function newGroupClickHandler (_event) { | ||
try { | ||
await fetch.load(groupIndex) | ||
await kb.fetcher.load(groupIndex) | ||
} catch (e) { | ||
@@ -641,3 +676,3 @@ console.log('Error: Group index NOT loaded:' + e + '\n') | ||
await kb.fetcher.load(nameEmailIndex) | ||
console.log('Name index loaded async' + nameEmailIndex) | ||
// console.log('Name index loaded async' + nameEmailIndex) | ||
@@ -791,3 +826,3 @@ const name = await UI.widgets | ||
if (!me) newContactButton.setAttribute('disabled', 'true') | ||
UI.authn.checkUser().then(webId => { | ||
authn.checkUser().then(webId => { | ||
if (webId) { | ||
@@ -808,3 +843,3 @@ me = webId | ||
if (!me) newOrganizationButton.setAttribute('disabled', 'true') | ||
UI.authn.checkUser().then(webId => { | ||
authn.checkUser().then(webId => { | ||
if (webId) { | ||
@@ -856,2 +891,6 @@ me = webId | ||
div.appendChild(dom.createElement('hr')) | ||
// const groups = await loadAllGroups() @@@ | ||
checkDataModel().then(()=> {console.log('async checkDataModel done.')}) | ||
// div.appendChild(newAddressBookButton(book)) // later | ||
@@ -877,3 +916,3 @@ // end of AddressBook instance | ||
// If we have a main address book, then render this group as a guest group within it | ||
UI.authn | ||
UI.login | ||
.findAppInstances(context, ns.vcard('AddressBook')) | ||
@@ -906,3 +945,3 @@ .then(function (context) { | ||
me = UI.authn.currentUser() | ||
me = authn.currentUser() | ||
if (!me) { | ||
@@ -912,3 +951,3 @@ console.log( | ||
) | ||
UI.authn.logInLoadProfile(context).then( | ||
UI.login.ensureLoadedProfile(context).then( | ||
context => { | ||
@@ -915,0 +954,0 @@ console.log('Logged in as ' + context.me) |
// Render a control to record the group memberships we have for this agent | ||
import * as UI from 'solid-ui' | ||
import { store } from 'solid-logic' | ||
@@ -10,6 +11,14 @@ // const $rdf = UI.rdf | ||
const utils = UI.utils | ||
const kb = UI.store | ||
// const style = UI.style | ||
const kb = store | ||
// Groups the person is a member of | ||
export function groupMembership (person) { | ||
let groups = kb.statementsMatching(null, ns.owl('sameAs'), person).map(st => st.why) | ||
.concat(kb.each(null, ns.vcard('hasMember'), person)) | ||
const strings = new Set(groups.map(group => group.uri)) // remove dups | ||
groups = [...strings].map(uri => kb.sym(uri)) | ||
return groups | ||
} | ||
export async function renderGroupMemberships (person, context) { | ||
@@ -20,3 +29,13 @@ // Remove a person from a group | ||
const gname = kb.any(group, ns.vcard('fn')) | ||
const groups = kb.each(null, ns.vcard('hasMember'), thing) | ||
// find all WebIDs of thing | ||
const thingwebids = kb.each(null, ns.owl('sameAs'), thing, group.doc()) | ||
// WebID can be deleted only if not used in another thing | ||
let webids = [] | ||
thingwebids.map(webid => { | ||
if (kb.statementsMatching(webid, ns.owl('sameAs'), thing, group.doc())) webids = webids.concat(webid) | ||
} | ||
) | ||
let thingOrWebid = thing | ||
if (webids.length > 0) thingOrWebid = webids[0] | ||
const groups = kb.each(null, ns.vcard('hasMember'), thingOrWebid) // in all groups a person has same structure | ||
if (groups.length < 2) { | ||
@@ -30,5 +49,10 @@ alert( | ||
if (confirm(message)) { | ||
const del = kb | ||
let del = kb | ||
.statementsMatching(person, undefined, undefined, group.doc()) | ||
.concat(kb.statementsMatching(undefined, undefined, person, group.doc())) | ||
webids.map(webid => { | ||
if (kb.statementsMatching(webid, ns.owl('sameAs'), undefined, group.doc()).length < 2) { | ||
del = del.concat(kb.statementsMatching(undefined, undefined, webid, group.doc())) | ||
} | ||
}) | ||
kb.updater.update(del, [], function (uri, ok, err) { | ||
@@ -43,3 +67,3 @@ if (!ok) { | ||
kb.fetcher.unload(group.doc()) | ||
kb.fetcher.load(group.doc()) | ||
await kb.fetcher.load(group.doc()) | ||
syncGroupList() | ||
@@ -60,9 +84,9 @@ } | ||
// find all groups where person has membership | ||
function syncGroupList () { | ||
const groups = kb.each(null, ns.vcard('hasMember'), person) | ||
utils.syncTableToArray(groupList, groups, newRowForGroup) | ||
// person and/or WebIDs to be changed | ||
utils.syncTableToArray(groupList, groupMembership(person), newRowForGroup) | ||
} | ||
async function loadGroupsFromBook (book = undefined) { | ||
async function loadGroupsFromBook (book = null) { | ||
if (!book) { | ||
@@ -80,2 +104,3 @@ book = kb.any(undefined, ns.vcard('includesGroup')) | ||
const { dom } = context | ||
const kb = context.session.store | ||
const groupList = dom.createElement('table') | ||
@@ -82,0 +107,0 @@ |
import * as UI from 'solid-ui' | ||
import { authn, store } from 'solid-logic' | ||
import { renderMugshotGallery } from './mugshotGallery' | ||
@@ -10,3 +11,3 @@ import { renderWebIdControl, renderPublicIdControl } from './webidControl' | ||
const ns = UI.ns | ||
const kb = UI.store | ||
const kb = store | ||
const style = UI.style | ||
@@ -72,3 +73,3 @@ | ||
UI.authn.checkUser() // kick off async operation @@@ use async version | ||
authn.checkUser() // kick off async operation @@@ use async version | ||
@@ -75,0 +76,0 @@ div.appendChild(renderMugshotGallery(dom, subject)) |
@@ -1,3 +0,5 @@ | ||
const UI = require('solid-ui') | ||
import * as UI from 'solid-ui' | ||
import { solidLogicSingleton } from 'solid-logic' | ||
const { setACLUserPublic } = solidLogicSingleton.acl | ||
// const mime = require('mime-types') | ||
@@ -15,3 +17,3 @@ // const toolsPane0 = require('./toolsPane') | ||
return new Promise(function (resolve, reject) { | ||
UI.authn.logInLoadProfile(context).then( | ||
UI.login.ensureLoadedProfile(context).then( | ||
context => { | ||
@@ -124,4 +126,3 @@ // 20180713 | ||
UI.authn | ||
.setACLUserPublic(dest, me, aclOptions) | ||
setACLUserPublic(dest, me, aclOptions) | ||
.then(() => doNextTask()) | ||
@@ -128,0 +129,0 @@ .catch(err => { |
import * as UI from 'solid-ui' | ||
import { store } from 'solid-logic' | ||
import * as mime from 'mime-types' | ||
@@ -7,3 +8,3 @@ | ||
const utils = UI.utils | ||
const kb = UI.store | ||
const kb = store | ||
@@ -120,3 +121,3 @@ /* Mugshot Gallery | ||
for (const u of uris) { | ||
var thing = $rdf.sym(u) // Attachment needs text label to disinguish I think not icon. | ||
let thing = $rdf.sym(u) // Attachment needs text label to disinguish I think not icon. | ||
console.log('Dropped on mugshot thing ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg' | ||
@@ -130,4 +131,5 @@ if (u.startsWith('http') && u.indexOf('#') < 0) { | ||
const options = { withCredentials: false, credentials: 'omit' } | ||
let result | ||
try { | ||
var result = await kb.fetcher.webOperation('GET', thing.uri, options) | ||
result = await kb.fetcher.webOperation('GET', thing.uri, options) | ||
} catch (err) { | ||
@@ -204,4 +206,14 @@ complain( | ||
if (image) { | ||
img.setAttribute('src', image.uri) | ||
// img.setAttribute('src', image.uri) use token and works with NSS but not with CSS | ||
// we need to get image with authenticated fetch | ||
store.fetcher._fetch(image.uri) | ||
.then(function(response) { | ||
return response.blob() | ||
}) | ||
.then(function(myBlob) { | ||
const objectURL = URL.createObjectURL(myBlob) | ||
img.setAttribute('src', objectURL) | ||
}) | ||
UI.widgets.makeDraggable(img, image) | ||
} | ||
@@ -208,0 +220,0 @@ return img |
{ | ||
"name": "contacts-pane", | ||
"version": "2.4.9", | ||
"version": "2.4.12-beta4", | ||
"description": "Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.", | ||
@@ -9,8 +9,9 @@ "main": "./contactsPane.js", | ||
"clean": "rm -rf lib", | ||
"build-lib": "mkdir lib && npx eslint *.js && make", | ||
"build-lib": "mkdir lib && make && npx tsc-transpile-only src/*.ts --outDir lib", | ||
"lint": "eslint '*.js'", | ||
"lint-fix": "eslint '*.js' --fix", | ||
"test": "npm run lint", | ||
"prepublishOnly": "npm test && npm run build", | ||
"postpublish": "git push origin master --follow-tags" | ||
"test": "npm run lint && npm run build && npx tsc --target es2015 --moduleResolution node --allowSyntheticDefaultImports __tests__/unit/*.ts && jest __tests__/unit/*test.ts", | ||
"jest": "jest __tests__/unit/*test.ts", | ||
"prepublishOnly": "npm run lint && npm run build && npm run jest", | ||
"postpublish": "git push origin main --follow-tags" | ||
}, | ||
@@ -41,11 +42,22 @@ "repository": { | ||
"dependencies": { | ||
"pane-registry": "^2.3.5", | ||
"rdflib": "^2.2.2", | ||
"solid-ui": "^2.4.2" | ||
"solid-ui": "^2.4.33-beta4" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^7.18.0", | ||
"husky": "^4.3.8", | ||
"lint-staged": "^10.5.3", | ||
"standard": "^16.0.3" | ||
"@babel/cli": "^7.24.1", | ||
"@babel/core": "^7.24.3", | ||
"@babel/preset-env": "^7.24.3", | ||
"@babel/preset-typescript": "^7.24.1", | ||
"@testing-library/jest-dom": "^6.4.2", | ||
"@types/jest": "^29.5.12", | ||
"@typescript-eslint/eslint-plugin": "^6.21.0", | ||
"@typescript-eslint/parser": "^6.21.0", | ||
"eslint": "^8.57.0", | ||
"eslint-plugin-import": "^2.29.1", | ||
"husky": "^8.0.3", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"jest-fetch-mock": "^3.0.3", | ||
"lint-staged": "^13.3.0", | ||
"typescript": "^5.4.3", | ||
"typescript-transpile-only": "0.0.4" | ||
}, | ||
@@ -52,0 +64,0 @@ "husky": { |
@@ -6,3 +6,4 @@ // The tools pane is for managing and debugging and maintaining solid contacts databases | ||
import * as UI from 'solid-ui' | ||
import { saveNewGroup, addPersonToGroup } from './contactLogic' | ||
import { store } from 'solid-logic' | ||
import { saveNewGroup, addPersonToGroup, groupMembers } from './contactLogic' | ||
export function toolsPane ( | ||
@@ -17,3 +18,3 @@ selectAllGroups, | ||
const dom = dataBrowserContext.dom | ||
const kb = UI.store | ||
const kb = store | ||
const ns = UI.ns | ||
@@ -73,3 +74,3 @@ const VCARD = ns.vcard | ||
try { | ||
await UI.authn.registrationControl(context, book, ns.vcard('AddressBook')) | ||
await UI.login.registrationControl(context, book, ns.vcard('AddressBook')) | ||
} catch (e) { | ||
@@ -90,3 +91,5 @@ UI.widgets.complain(context, 'registrationControl: ' + e) | ||
log('' + totalCards + ' cards loaded. ') | ||
const groups = kb.each(book, VCARD('includesGroup')) | ||
let groups = kb.each(book, VCARD('includesGroup')) | ||
const strings = new Set(groups.map(group => group.uri)) // remove dups | ||
groups = [...strings].map(uri => kb.sym(uri)) | ||
log('' + groups.length + ' total groups. ') | ||
@@ -143,3 +146,3 @@ const gg = [] | ||
const g = kb.sym(gg[i]) | ||
const a = kb.each(g, ns.vcard('hasMember')) | ||
const a = groupMembers(kb, g) | ||
log(UI.utils.label(g) + ': ' + a.length + ' members') | ||
@@ -168,3 +171,3 @@ for (let j = 0; j < a.length; j++) { | ||
UI.store.fetcher.nowOrWhenFetched( | ||
store.fetcher.nowOrWhenFetched( | ||
stats.nameEmailIndex, | ||
@@ -365,2 +368,3 @@ undefined, | ||
log(' Matches with ' + other) | ||
// alain not sure it works we may need to concat with 'sameAs' group.doc (.map(st => st.why)) | ||
const cardGroups = kb.each(null, ns.vcard('hasMember'), card) | ||
@@ -441,5 +445,5 @@ const otherGroups = kb.each(null, ns.vcard('hasMember'), other) | ||
} | ||
stats.groupMembers = kb | ||
.statementsMatching(null, ns.vcard('hasMember')) | ||
.map(st => st.object) | ||
stats.groupMembers = [] | ||
kb.each(null, ns.vcard('hasMember')) | ||
.map(group => { stats.groupMembers = stats.groupMembers.concat(groupMembers(kb, group)) }) | ||
log(' Naive group members ' + stats.groupMembers.length) | ||
@@ -585,3 +589,6 @@ stats.groupMemberSet = [] | ||
return kb.fetcher.webOperation('PUT', cleanGroup, { data }) | ||
return kb.fetcher.webOperation('PUT', cleanGroup, { | ||
data: data, | ||
contentType: 'text/turtle' | ||
}) | ||
}) | ||
@@ -626,8 +633,10 @@ .then(() => { | ||
.then(checkAllNameless) | ||
.then((resolve, reject) => { | ||
if (confirm('Write new clean versions?')) { | ||
resolve(true) | ||
} else { | ||
reject() | ||
} | ||
.then(() => { | ||
return new Promise(function (resolve, reject) { | ||
if (confirm('Write new clean versions?')) { | ||
resolve(true) | ||
} else { | ||
reject() | ||
} | ||
}) | ||
}) | ||
@@ -672,4 +681,5 @@ .then(saveCleanPeople) | ||
const groupless = [] | ||
const groups = kb.each(book, VCARD('includesGroup')) | ||
let groups = kb.each(book, VCARD('includesGroup')) | ||
const strings = new Set(groups.map(group => group.uri)) // remove dups | ||
groups = [...strings].map(uri => kb.sym(uri)) | ||
log('' + groups.length + ' total groups. ') | ||
@@ -679,3 +689,4 @@ | ||
const g = groups[i] | ||
const a = kb.each(g, ns.vcard('hasMember')) | ||
const a = groupMembers(kb, g) | ||
log(UI.utils.label(g) + ': ' + a.length + ' members') | ||
@@ -728,2 +739,42 @@ for (let j = 0; j < a.length; j++) { | ||
fixGrouplessButton.addEventListener('click', _event => fixGroupless(book)) | ||
async function fixToOldDataModel (book) { | ||
async function updateToOldDataModel(groups) { | ||
let ds = [] | ||
let ins = [] | ||
groups.forEach(group => { | ||
let vcardOrWebids = kb.statementsMatching(null, ns.owl('sameAs'), null, group.doc()).map(st => st.subject) | ||
const strings = new Set(vcardOrWebids.map(contact => contact.uri)) // remove dups | ||
vcardOrWebids = [...strings].map(uri => kb.sym(uri)) | ||
vcardOrWebids.forEach(item => { | ||
if (!kb.each(item, ns.vcard('fn'), null, group.doc()).length) { | ||
// delete item this is a new data model, item is a webid not a card. | ||
ds = ds.concat(kb | ||
.statementsMatching(item, ns.owl('sameAs'), null, group.doc()) | ||
.concat(kb.statementsMatching(undefined, undefined, item, group.doc()))) | ||
// add webid card to group | ||
const cards = kb.each(item, ns.owl('sameAs'), null, group.doc()) | ||
cards.forEach(card => { | ||
ins = ins.concat($rdf.st(card, ns.owl('sameAs'), item, group.doc())) | ||
.concat($rdf.st(group, ns.vcard('hasMember'), card, group.doc())) | ||
}) | ||
} | ||
}) | ||
}) | ||
if (ds.length && confirm('Groups can be updated to old data model ?')) { | ||
await kb.updater.updateMany(ds, ins) | ||
alert('Update done') | ||
} else { if (!ds.length) alert('Nothing to update.\nAll Groups already use the old data model.')} | ||
} | ||
let groups = kb.each(book, VCARD('includesGroup')) | ||
const strings = new Set(groups.map(group => group.uri)) // remove dups | ||
groups = [...strings].map(uri => kb.sym(uri)) | ||
updateToOldDataModel(groups) | ||
} | ||
const fixToOldDataModelButton = pane.appendChild(dom.createElement('button')) | ||
fixToOldDataModelButton.style.cssText = buttonStyle | ||
fixToOldDataModelButton.textContent = 'Revert groups to old data model' | ||
fixToOldDataModelButton.addEventListener('click', _event => fixToOldDataModel(book)) | ||
} // main | ||
@@ -730,0 +781,0 @@ main() |
// Render a control to record the webids we have for this agent | ||
/* eslint-disable multiline-ternary */ | ||
import * as UI from 'solid-ui' | ||
import { store } from 'solid-logic' | ||
import { updateMany } from './contactLogic' | ||
// import { renderAutoComplete } from './lib/autocompletePicker' // dbpediaParameters | ||
import { renderAutocompleteControl } from './lib/autocompleteBar' | ||
// import { wikidataParameters, loadPublicDataThing, wikidataClasses } from './lib/publicData' // dbpediaParameters | ||
@@ -10,3 +14,3 @@ const $rdf = UI.rdf | ||
const utils = UI.utils | ||
const kb = UI.store | ||
const kb = store | ||
const style = UI.style | ||
@@ -38,3 +42,3 @@ | ||
try { | ||
const url = new URL(webid) | ||
const _url = new URL(webid) | ||
} catch (error) { | ||
@@ -52,8 +56,14 @@ throw new Error(`${WEBID_NOUN}: ${webid} is not a valid url.`) | ||
] | ||
// insert WebID in groups | ||
// replace person with WebID in vcard:hasMember (WebID may already exist) | ||
// insert owl:sameAs | ||
const groups = kb.each(null, ns.vcard('hasMember'), person) | ||
let deletables = [] | ||
groups.forEach(group => { | ||
insertables.push($rdf.st(person, ns.owl('sameAs'), kb.sym(webid), group.doc())) | ||
deletables = deletables.concat(kb.statementsMatching(group, ns.vcard('hasMember'), person, group.doc())) | ||
insertables.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc())) // May exist; do we need to check? | ||
insertables.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), person, group.doc())) | ||
}) | ||
try { | ||
await updateMany([], insertables) | ||
await updateMany(deletables, insertables) | ||
} catch (err) { throw new Error(`Could not create webId ${WEBID_NOUN}: ${webid}.`) } | ||
@@ -81,8 +91,13 @@ } | ||
// remove webIDs from groups | ||
const groups = kb.each(null, ns.vcard('hasMember'), person) | ||
const removeFromGroups = [] | ||
groups.forEach(group => { | ||
removeFromGroups.push($rdf.st(person, ns.owl('sameAs'), kb.sym(webid), group.doc())) | ||
const groups = kb.each(null, ns.vcard('hasMember'), kb.sym(webid)) | ||
let removeFromGroups = [] | ||
const insertInGroups = [] | ||
groups.forEach(async group => { | ||
removeFromGroups = removeFromGroups.concat(kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), person, group.doc())) | ||
insertInGroups.push($rdf.st(group, ns.vcard('hasMember'), person, group.doc())) | ||
if (kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), null, group.doc()).length < 2) { | ||
removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), kb.sym(webid), group.doc())) | ||
} | ||
}) | ||
await updateMany(removeFromGroups) | ||
await updateMany(removeFromGroups, insertInGroups) | ||
} | ||
@@ -250,2 +265,3 @@ | ||
widgets.publicData.loadPublicDataThing(kb, person, persona).then(_resp => { | ||
// loadPublicDataThing(kb, person, persona).then(_resp => { | ||
try { | ||
@@ -307,4 +323,6 @@ main = renderNamedPane(dom, persona, paneName, dataBrowserContext) | ||
if (options.editable) { // test | ||
options.manualURIEntry = true // introduced in solid-ui 2.4.2 | ||
options.queryParams = options.queryParams || wikidataParameters | ||
div.appendChild(await widgets.renderAutocompleteControl(dom, person, options, addOneIdAndRefresh)) | ||
div.appendChild(await renderAutocompleteControl(dom, person, options, addOneIdAndRefresh)) | ||
// div.appendChild(await widgets.renderAutocompleteControl(dom, person, options, addOneIdAndRefresh)) | ||
} | ||
@@ -311,0 +329,0 @@ const profileArea = div.appendChild(dom.createElement('div')) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
557145
1
51
6247
0
17
1
+ Addeddebug@4.4.0(transitive)
+ Addedms@2.1.3(transitive)
- Removedpane-registry@^2.3.5
- Removedrdflib@^2.2.2
Updatedsolid-ui@^2.4.33-beta4