UNPKG

contacts-pane

Version:

Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.

387 lines (381 loc) 18.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.predMap = exports.wikidataClassMap = exports.wikidataParameters = exports.dbpediaParameters = exports.escoParameters = exports.wikidataClasses = exports.AUTOCOMPLETE_LIMIT = void 0; exports.getPreferredLanguages = getPreferredLanguages; exports.filterByLanguage = filterByLanguage; exports.loadFromBindings = loadFromBindings; exports.queryESCODataByName = queryESCODataByName; exports.queryPublicDataByName = queryPublicDataByName; exports.queryPublicDataSelect = queryPublicDataSelect; exports.queryPublicDataConstruct = queryPublicDataConstruct; exports.loadPublicDataThing = loadPublicDataThing; exports.getWikidataDetails = getWikidataDetails; exports.getWikidataDetailsOld = getWikidataDetailsOld; exports.getWikidataLocation = getWikidataLocation; exports.getDbpediaDetails = getDbpediaDetails; /* Logic to access public data stores * * including filtering resut by natural language etc */ const rdflib_1 = require("rdflib"); const solid_logic_1 = require("solid-logic"); const solid_ui_1 = require("solid-ui"); const instituteDetailsQuery = require("../lib/instituteDetailsQuery.js"); exports.AUTOCOMPLETE_LIMIT = 3000; // How many to get from server const subjectRegexp = /\$\(subject\)/g; // Schema.org seems to suggest NGOs are non-profit and Corporaions are for-profit // but doesn't have explicit classes exports.wikidataClasses = { Corporation: 'http://www.wikidata.org/entity/Q6881511', // Enterprise is for-profit EducationalOrganization: 'http://www.wikidata.org/entity/Q178706', // insitution GovernmentOrganization: 'http://www.wikidata.org/entity/Q327333', // government agency MedicalOrganization: 'http://www.wikidata.org/entity/Q4287745', MusicGroup: 'http://www.wikidata.org/entity/Q32178211', // music organization NGO: 'http://www.wikidata.org/entity/Q163740', // nonprofit organization @@ Occupation: 'http://www.wikidata.org/entity/Q28640', // Profession // Organization: 'http://www.wikidata.org/entity/Q43229', Project: 'http://www.wikidata.org/entity/Q170584', SportsOrganization: 'http://www.wikidata.org/entity/Q4438121', }; function getPreferredLanguages() { return __awaiter(this, void 0, void 0, function* () { return ['fr', 'en', 'de', 'it']; // @@ testing only -- code me later }); } exports.escoParameters = { label: 'ESCO', logo: 'https://ec.europa.eu/esco/portal/static_resource2/images/logo/logo_en.gif', searchByNameQuery: null, // No sparql endpoint searchByNameURI: 'https://ec.europa.eu/esco/api/search?language=$(language)&type=occupation&text=$(name)', endpoint: null, class: {} }; exports.dbpediaParameters = { label: 'DBPedia', logo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/73/DBpediaLogo.svg/263px-DBpediaLogo.svg.png', searchByNameQuery: `select distinct ?subject, ?name where { ?subject a $(class); rdfs:label ?name FILTER regex(?name, "$(name)", "i") } LIMIT $(limit)`, endpoint: 'https://dbpedia.org/sparql/', class: { AcademicInsitution: 'http://umbel.org/umbel/rc/EducationalOrganization' } }; exports.wikidataParameters = { label: 'WikiData', logo: 'https://www.wikimedia.org/static/images/project-logos/wikidatawiki.png', endpoint: 'https://query.wikidata.org/sparql', class: { AcademicInsitution: 'http://www.wikidata.org/entity/Q4671277', Enterprise: 'http://www.wikidata.org/entity/Q6881511', Business: 'http://www.wikidata.org/entity/Q4830453', NGO: 'http://www.wikidata.org/entity/Q79913', CharitableOrganization: 'http://www.wikidata.org/entity/Q708676', Insitute: 'http://www.wikidata.org/entity/Q1664720', }, searchByNameQuery: `SELECT ?subject ?name WHERE { ?klass wdt:P279* $(class) . ?subject wdt:P31 ?klass . ?subject rdfs:label ?name. FILTER regex(?name, "$(name)", "i") } LIMIT $(limit) `, // was SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" } insitituteDetailsQuery: `CONSTRUCT { wd:Q49108 schema:name ?itemLabel; schema:logo ?logo; schema:logo ?sealImage; schema:subOrganization ?subsidiary . ?subsidiary schema:name ?subsidiaryLabel . } WHERE { wd:Q49108 # rdfs:label ?itemLabel ; wdt:P154 ?logo; wdt:P158 ?sealImage ; wdt:P355 ?subsidiary . # ?subsidiary rdfs:label ?subsidiaryLabel . SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE], fr". } }` }; /* From an array of bindings with a names for each row, * remove dupliacte names for the same thing, leaving the user's * preferred language version */ function filterByLanguage(bindings, languagePrefs) { let uris = {}; bindings.forEach(binding => { const uri = binding.subject.value; uris[uri] = uris[uri] || []; uris[uri].push(binding); }); var languagePrefs2 = languagePrefs; languagePrefs2.reverse(); // prefered last var slimmed = []; for (const u in uris) { // needs hasOwnProperty ? const bindings = uris[u]; const sortMe = bindings.map(binding => { return [languagePrefs2.indexOf(binding.name['xml:lang']), binding]; }); sortMe.sort(); // best at th ebottom sortMe.reverse(); // best at the top slimmed.push(sortMe[0][1]); } // map u console.log(` Filter by language: ${bindings.length} -> ${slimmed.length}`); return slimmed; } exports.wikidataClassMap = { 'http://www.wikidata.org/entity/Q15936437': solid_ui_1.ns.schema('CollegeOrUniversity'), // research university 'http://www.wikidata.org/entity/Q1664720': solid_ui_1.ns.schema('EducationalOrganization'), // insitute @@ 'http://www.wikidata.org/entity/Q43229': solid_ui_1.ns.schema('Organization'), // research university 'http://www.wikidata.org/entity/Q3918': solid_ui_1.ns.schema('CollegeOrUniversity'), // university 'http://www.wikidata.org/entity/Q170584': solid_ui_1.ns.schema('Project'), // university 'http://www.wikidata.org/entity/Q327333': solid_ui_1.ns.schema('GovernmentOrganization'), // gobvt agency 'http://www.wikidata.org/entity/Q2221906': solid_ui_1.ns.schema('Place'), // geographic location }; exports.predMap = { class: solid_ui_1.ns.rdf('type'), // logo: ns.schema('logo'), sealImage: solid_ui_1.ns.schema('logo'), //image: ns.schema('image'), defaults to shema shortName: solid_ui_1.ns.foaf('nick'), subsidiary: solid_ui_1.ns.schema('subOrganization') }; function loadFromBindings(kb, solidSubject, bindings, doc) { var results = {}; console.log(`loadFromBindings: subject: ${solidSubject}`); console.log(` doc: ${doc}`); bindings.forEach(binding => { for (const key in binding) { const result = binding[key]; const combined = JSON.stringify(result); // ( result.type, result.value ) results[key] = results[key] || new Set(); results[key].add(combined); // remove duplicates } }); for (const key in results) { const values = results[key]; console.log(` results ${key} -> ${values}`); values.forEach(combined => { const result = JSON.parse(combined); const { type, value } = result; var obj; if (type === 'uri') { obj = kb.sym(value); } else if (type === 'literal') { obj = new rdflib_1.Literal(value, result.language, result.datatype); } else { throw new Error(`loadFromBindings: unexpected type: ${type}`); } if (key == 'type') { if (exports.wikidataClassMap[value]) { obj = exports.wikidataClassMap[value]; } else { console.warn('Unmapped Wikidata Class: ' + value); } } else if (key === 'coordinates') { // const latlong = value // Like 'Point(-71.106111111 42.375)' console.log(' @@@ hey a point: ' + value); const regexp = /.*\(([-0-9\.-]*) ([-0-9\.-]*)\)/; const match = regexp.exec(value); const float = solid_ui_1.ns.xsd('float'); const latitude = new rdflib_1.Literal(match[1], null, float); const longitude = new rdflib_1.Literal(match[2], null, float); kb.add(solidSubject, solid_ui_1.ns.schema('longitude'), longitude, doc); kb.add(solidSubject, solid_ui_1.ns.schema('latitude'), latitude, doc); } else if (exports.predMap[key]) { const pred = exports.predMap[key] || solid_ui_1.ns.schema(key); // fallback to just using schema.org kb.add(solidSubject, pred, obj, doc); // @@ deal with non-string and objects console.log(` public data ${pred} ${obj}.`); } }); } } /* ESCO sopecific */ /* Query all entities of given class and partially matching name */ function queryESCODataByName(filter, theClass, queryTarget) { return __awaiter(this, void 0, void 0, function* () { const queryURI = queryTarget.searchByNameURI .replace('$(name)', filter) .replace('$(limit)', '' + exports.AUTOCOMPLETE_LIMIT) .replace('$(class)', theClass); console.log('Querying ESCO data - uri: ' + queryURI); const options = { credentials: 'omit', headers: { 'Accept': 'application/json' } }; // CORS var response; response = yield solid_logic_1.store.fetcher.webOperation('GET', queryURI, options); //complain('Error querying db of organizations: ' + err) const text = response.responseText; console.log(' Query result text' + text.slice(0, 500) + '...'); if (text.length === 0) throw new Error('Wot no text back from ESCO query ' + queryURI); const json = JSON.parse(text); console.log(' Query result JSON' + JSON.stringify(json, null, 4).slice(0, 500) + '...'); const results = json._embedded.results; // Array const bindings = results.map(result => { const name = result.title; const uri = result.uri; // like http://data.europa.eu/esco/occupation/57af9090-55b4-4911-b2d0-86db01c00b02 return { name: { value: name, type: 'literal' }, uri: { type: 'IRI', value: uri } }; // simulate SPARQL bindings }); return bindings; // return queryPublicDataSelect(sparql, queryTarget) }); } /* Query all entities of given class and partially matching name */ function queryPublicDataByName(filter, theClass, queryTarget) { return __awaiter(this, void 0, void 0, function* () { const sparql = queryTarget.searchByNameQuery .replace('$(name)', filter) .replace('$(limit)', '' + exports.AUTOCOMPLETE_LIMIT) .replace('$(class)', theClass); console.log('Querying public data - sparql: ' + sparql); return queryPublicDataSelect(sparql, queryTarget); }); } function queryPublicDataSelect(sparql, queryTarget) { return __awaiter(this, void 0, void 0, function* () { const myUrlWithParams = new URL(queryTarget.endpoint); myUrlWithParams.searchParams.append("query", sparql); const queryURI = myUrlWithParams.href; console.log(' queryPublicDataSelect uri: ' + queryURI); const options = { credentials: 'omit', headers: { 'Accept': 'application/json' } }; // CORS var response; response = yield solid_logic_1.store.fetcher.webOperation('GET', queryURI, options); //complain('Error querying db of organizations: ' + err) const text = response.responseText; // console.log(' Query result text' + text.slice(0,100) + '...') if (text.length === 0) throw new Error('Wot no text back from query ' + queryURI); const json = JSON.parse(text); console.log(' Query result JSON' + JSON.stringify(json, null, 4).slice(0, 100) + '...'); const bindings = json.results.bindings; return bindings; }); } function queryPublicDataConstruct(sparql, pubicId, queryTarget) { return __awaiter(this, void 0, void 0, function* () { console.log('queryPublicDataConstruct: sparql:', sparql); const myUrlWithParams = new URL(queryTarget.endpoint); myUrlWithParams.searchParams.append("query", sparql); const queryURI = myUrlWithParams.href; console.log(' queryPublicDataConstruct uri: ' + queryURI); const options = { credentials: 'omit', // CORS headers: { 'Accept': 'text/turtle' } }; const response = yield solid_logic_1.store.fetcher.webOperation('GET', queryURI, options); const text = response.responseText; const report = text.lenth > 500 ? text.slice(0, 200) + ' ... ' + text.slice(-200) : text; console.log(' queryPublicDataConstruct result text:' + report); if (text.length === 0) throw new Error('queryPublicDataConstruct: No text back from construct query:' + queryURI); (0, rdflib_1.parse)(text, solid_logic_1.store, pubicId.uri, 'text/turtle'); return; }); } function loadPublicDataThing(kb, subject, publicDataID) { return __awaiter(this, void 0, void 0, function* () { if (publicDataID.uri.startsWith('https://dbpedia.org/resource/')) { return getDbpediaDetails(kb, subject, publicDataID); } else if (publicDataID.uri.match(/^https?:\/\/www\.wikidata\.org\/entity\/.*/)) { const QId = publicDataID.uri.split('/')[4]; const dataURI = `http://www.wikidata.org/wiki/Special:EntityData/${QId}.ttl`; // In fact loading the data URI gives much to much irrelevant data, from wikidata. yield getWikidataDetails(kb, subject, publicDataID); // await getWikidataLocation(kb, subject, publicDataID) -- should get that in the details query now } else { const iDToFetch = publicDataID.uri.startsWith('http:') ? kb.sym('https:' + publicDataID.uri.slice(5)) : publicDataID; return kb.fetcher.load(iDToFetch, { credentials: 'omit', headers: { 'Accept': 'text/turtle' } }); } }); } function getWikidataDetails(kb, solidSubject, publicDataID) { return __awaiter(this, void 0, void 0, function* () { const subjRegexp = /wd:Q49108/g; const sparql = instituteDetailsQuery.replace(subjRegexp, publicDataID); yield queryPublicDataConstruct(sparql, publicDataID, exports.wikidataParameters); console.log('getWikidataDetails: loaded.', publicDataID); }); } function getWikidataDetailsOld(kb, solidSubject, publicDataID) { return __awaiter(this, void 0, void 0, function* () { const sparql = `select distinct * where { optional { $(subject) wdt:P31 ?class } # instance of optional { $(subject) wdt:P154 ?logo } optional { $(subject) wdt:P158 ?sealImage } # optional { $(subject) wdt:P159 ?headquartersLocation } optional { $(subject) wdt:P17 ?country } optional { $(subject) wdt:P18 ?image } optional { $(subject) wdt:P1813 ?shortName } optional { $(subject) wdt:P355 ?subsidiary } # SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en,de,it" } }` .replace(subjectRegexp, publicDataID); const bindings = yield queryPublicDataSelect(sparql, exports.wikidataParameters); loadFromBindings(kb, publicDataID, bindings, publicDataID.doc()); //arg2 was solidSubject }); } function getWikidataLocation(kb, solidSubject, publicDataID) { return __awaiter(this, void 0, void 0, function* () { const sparql = `select distinct * where { $(subject) wdt:P276 ?location . optional { ?location wdt:P2044 ?elevation } optional { ?location wdt:P131 ?region } optional { ?location wdt:P625 ?coordinates } optional { ?location wdt:P17 ?country } # SERVICE wikibase:label { bd:serviceParam wikibase:language "fr,en,de,it" } }`.replace(subjectRegexp, publicDataID); console.log(' location query sparql:' + sparql); const bindings = yield queryPublicDataSelect(sparql, exports.wikidataParameters); console.log(' location query bindings:', bindings); loadFromBindings(kb, publicDataID, bindings, publicDataID.doc()); // was solidSubject }); } function getDbpediaDetails(kb, solidSubject, publicDataID) { return __awaiter(this, void 0, void 0, function* () { // Note below the string form of the named node with <> works in SPARQL const sparql = `select distinct ?city, ?state, ?country, ?homepage, ?logo, ?lat, ?long, WHERE { OPTIONAL { <${publicDataID}> <http://dbpedia.org/ontology/city> ?city } OPTIONAL { ${publicDataID} <http://dbpedia.org/ontology/state> ?state } OPTIONAL { ${publicDataID} <http://dbpedia.org/ontology/country> ?country } OPTIONAL { ${publicDataID} foaf:homepage ?homepage } OPTIONAL { ${publicDataID} foaf:lat ?lat; foaf:long ?long } OPTIONAL { ${publicDataID} <http://dbpedia.org/ontology/country> ?country } }`; const predMap = { city: solid_ui_1.ns.vcard('locality'), state: solid_ui_1.ns.vcard('region'), country: solid_ui_1.ns.vcard('country-name'), homepage: solid_ui_1.ns.foaf('homepage'), lat: solid_ui_1.ns.geo('latitude'), long: solid_ui_1.ns.geo('longitude'), }; const bindings = yield queryPublicDataSelect(sparql, exports.dbpediaParameters); bindings.forEach(binding => { const uri = binding.subject.value; // @@ To be written const name = binding.name.value; }); }); } //# sourceMappingURL=publicData.js.map