contacts-pane
Version:
Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.
387 lines (381 loc) • 18.8 kB
JavaScript
;
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