researchstudio-sat / webofneeds

Finding people to cooperate with. Protocol, not platform. Decentralized. Linked Data. Open Source.
http://researchstudio-sat.github.io/webofneeds/
Apache License 2.0
63 stars 20 forks source link

Add/show Location #688

Closed fkleedorfer closed 7 years ago

pheara commented 8 years ago

comparing map tools:

Result: Leaflet (as we don't need the features offered by open-layers.)

pheara commented 8 years ago

As for the design: I think for the workflow it might be faster to prefill the "default address" and allow the user to change the location, e.g. by picking one of the previously entered addresses (extractable from ownNeeds) or searching for a new address.

pheara commented 8 years ago

ui-design for location picker

pheara commented 8 years ago

As of a64b50b5c211c3f6c19eb707232db6eb21a571dd the component queries nominatim after text-input – allowing selection among the results – as well as following a click directly on the map. Also it can display an alternative transport-focussed layer. Thus the following TODOs are still open:

pheara commented 8 years ago

As of f3a6914fdb06dd11a96516879af56286c13333ca current location works, markers get placed, the input veriefied and posted to the server. The following TODOs are open:

pheara commented 8 years ago

The location information of owned needs doesn't show up in the state, but is in the rdfstore. The culprit is the sparql-query for needs in the linkeddata-service-won.js. It assumes a flat-ish structure, where the location information is actually nested.

A need example:

 need:946717029499422700
            a                     won:Need ;
            won:hasBasicNeedType  won:DoTogether ;
            won:hasContent        [ a                          won:NeedContent ;
                                    dc:title                   "play Tennis" ;
                                    won:hasContentDescription  [ a                       won:NeedModality ;
                                                                 won:hasBoundsNorthWest  [ a              geo:Point ;
                                                                                           geo:latitude   "32.534779" ;
                                                                                           geo:longitude  "-117.309805"
                                                                                         ] ;
                                                                 won:hasBoundsSouthEast  [ a              geo:Point ;
                                                                                           geo:latitude   "33.114249" ;
                                                                                           geo:longitude  "-116.905722"
                                                                                         ] ;
                                                                 won:hasLocation         [ a               geo:Point ;
                                                                                           won:hasAddress  "San Diego, San Diego County, Kalifornien, Vereinigte Staaten von Amerika" ;
                                                                                           geo:latitude    "32.717421" ;
                                                                                           geo:longitude   "-117.162771"
                                                                                         ]
                                                               ]
                                  ] ;
            won:hasFacet          won:OwnerFacet ;
            cert:key              [ cert:PublicKey  [ a                       woncrypt:ECCPublicKey ;
                                                      woncrypt:ecc_algorithm  "EC" ;
                                                      woncrypt:ecc_curveId    "secp384r1" ;
                                                      woncrypt:ecc_qx         "841becab91d1ab2daddad922068fa60a0ef8dac216c670531a23f9c693b599abba0acabbc5136df95aa2768c852e31f8" ;
                                                      woncrypt:ecc_qy         "7b94ff8b10bb216a1279be37566abc020292a0f04a9c8e57a4b4818146da230a9388d6b2d137b6b089a8ffe99973fb6a"
                                                    ] ] .
}

The following query pulls the correct triples for the need by selecting everything attached to the content-node. However it returns a list of triples that aren't fit for use by the app yet.

var need = "<https://satsrv04.researchstudio.at:8889/won/resource/need/9064553301577927000>";
var query = 
`
prefix won: <http://purl.org/webofneeds/model#>
construct {${need} ?b ?c. ?c ?d ?e. ?e ?f ?g. ?g ?h ?i} where {
    {
          ${need} won:hasBasicNeedType ?c.
          ${need} ?b ?c 
    }
    UNION
    {
          ${need} won:hasContent ?c.
          ${need} ?b ?c 
    }
    UNION
    {
          ${need} won:hasContent ?c.
          ?c ?d ?e.
    }
    UNION
    {
          ${need} won:hasContent ?c.
          ?c ?d ?e.
          ?e ?f ?g.
    }
    UNION
    {
          ${need} won:hasContent ?c.
          ?c ?d ?e.
          ?e ?f ?g.
          ?g ?h ?i.
    }
}
`

store4dbg.execute(query, (s, rs) => {
  console.log(rs);
  rs.triples.map(t => console.log(t.subject.nominalValue, t.predicate.nominalValue, t.object.nominalValue))
})

So we could either use that query and write a custom triple2json-converter-function or take an entirely different route and use rdfstore.getNode(<uri>) recursively on the content-node.

pheara commented 8 years ago

For transforming the result of this query, a naive approach – that assumes an acyclic content-node subgraph – would be:

    function triples2json(rootUri, triples) {
        const resultJson = {};
        const rootTriples = triples.filter(t => t.subject.nominalValue === rootUri);
        for(var t of rootTriples) {
            const predicate = won.getLocalName(t.predicate.nominalValue);
            switch(t.object.interfaceName) {
                case "Literal":
                    // This is the simple case. we can just add it to our result object
                    var literal = t.object.nominalValue;
                    resultJson[predicate] = literal;
                    break;

                case "NamedNode":
                    var namedNodeUri = t.object.nominalValue;
                    var isUsedAsSubject = (triples.filter(t_ => t_.subject.nominalValue === namedNodeUri).length > 0);
                    if(isUsedAsSubject) {
                        // treat like blank node
                        resultJson[predicate] = triples2json(namedNodeUri, triples);
                    } else {
                        // treat like literal node
                        resultJson[predicate] = namedNodeUri;
                    }
                    break;

                case "BlankNode":
                    var blankNodeUri = t.object.nominalValue;
                    resultJson[predicate] = triples2json(blankNodeUri, triples);
                    break;

                default:
                    throw new Exception("Encountered triple with object of unknown type: "
                        + t.object.interfaceName + "\n" +
                        t.subject.nominalValue + " " +
                        t.predicate.nominalValue + " " +
                        t.object.nominalValue + " "
                    );
            }
        }

        return resultJson;
    }
pheara commented 8 years ago

A more stable and refined variant would transform the query results to jsonld and then frame along the lines of:

{
  "@context": {
    "won" : "http://purl.org/webofneeds/model#"
  },
  "@type": "won:Need",
  "won:hasContent": {
    "@type": "won:NeedContent"
  }  
}
pheara commented 8 years ago

This gives us properties with prefixes however (which is good as it avoids name-clashes, see #712) and thus require a lot of refactoring to go from the current, flattened version to the framed version.

Before (=current):

{
  "uri": "https://satsrv04.researchstudio.at:8889/won/resource/need/9064553301577927000",
  "basicNeedType": "http://purl.org/webofneeds/model#DoTogether",
  "title": "program together",
  "tags": null,
  "textDescription": null,
  "creationDate": "2016-08-02T10:57:04.62Z",
  "state": "http://purl.org/webofneeds/model#Active",
  "hasConnections": [
    "https://satsrv04.researchstudio.at:8889/won/resource/connection/ado1r5wo3n72wb56473j",
    "https://satsrv04.researchstudio.at:8889/won/resource/connection/uk4nbty32nsvgy5a8e9m"
  ]
}

After:

{
  "@context": {
    "msg": "http://purl.org/webofneeds/message#",
    "conn": "https://satsrv04.researchstudio.at:8889/won/resource/connection/",
    "woncrypt": "http://purl.org/webofneeds/woncrypt#",
    "signature": "http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#",
    "need": "https://satsrv04.researchstudio.at:8889/won/resource/need/",
    "xsd": "http://www.w3.org/2001/XMLSchema#",
    "cert": "http://www.w3.org/ns/auth/cert#",
    "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
    "local": "https://satsrv04.researchstudio.at:8889/won/resource/",
    "geo": "http://www.w3.org/2003/01/geo/wgs84_pos#",
    "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    "won": "http://purl.org/webofneeds/model#",
    "ldp": "http://www.w3.org/ns/ldp#",
    "event": "https://satsrv04.researchstudio.at:8889/won/resource/event/",
    "sioc": "http://rdfs.org/sioc/ns#",
    "dc": "http://purl.org/dc/elements/1.1/"
  },
  "@graph": [
    {
      "@id": "need:9064553301577927000",
      "@type": "won:Need",
      "http://purl.org/dc/terms/created": {
        "@type": "xsd:dateTime",
        "@value": "2016-08-02T10:57:04.62Z"
      },
      "won:hasBasicNeedType": {
        "@id": "won:DoTogether"
      },
      "won:hasConnections": {
        "@id": "need:9064553301577927000/connections/"
      },
      "won:hasContent": {
        "@id": "_:b4",
        "@type": "won:NeedContent",
        "dc:title": "program together",
        "won:hasContentDescription": {
          "@id": "_:b5",
          "@type": "won:NeedModality",
          "won:hasBoundsNorthWest": {
            "@id": "_:b6",
            "@type": "geo:Point",
            "geo:latitude": "48.213814",
            "geo:longitude": "16.340870"
          },
          "won:hasBoundsSouthEast": {
            "@id": "_:b2",
            "@type": "geo:Point",
            "geo:latitude": "48.236309",
            "geo:longitude": "16.370149"
          },
          "won:hasLocation": {
            "@id": "_:b7",
            "@type": "geo:Point",
            "won:hasAddress": "Alsergrund, Wien, 1090, Österreich",
            "geo:latitude": "48.225073",
            "geo:longitude": "16.358398"
          }
        }
      },
      "won:hasEventContainer": {
        "@id": "need:9064553301577927000#events",
        "@type": "won:EventContainer",
        "rdfs:member": [
          {
            "@id": "event:3223454307305560000"
          },
          {
            "@id": "event:dywdp7fjnl4ngqvhe7e5"
          }
        ]
      },
      "won:hasFacet": {
        "@id": "won:OwnerFacet"
      },
      "won:hasWonNode": {
        "@id": "https://satsrv04.researchstudio.at:8889/won/resource"
      },
      "won:isInState": {
        "@id": "won:Active"
      },
      "cert:key": {
        "@id": "_:b3",
        "cert:PublicKey": {
          "@id": "_:b1",
          "@type": "woncrypt:ECCPublicKey",
          "woncrypt:ecc_algorithm": "EC",
          "woncrypt:ecc_curveId": "secp384r1",
          "woncrypt:ecc_qx": "37f9b7cc083266e0cb7345d9a62619a2cf406503740395d2d69c617ac1e54b90c98e15501fab76739ce4a5bc5a680e48",
          "woncrypt:ecc_qy": "46d802a5e187523f23ac08e4be5217536b230313ab7ad48db543b1bcb4b3307635a719e1d6895c13f6c5864fbe5ccd60"
        }
      }
    }
  ]
}

Generated with the frame:

{
  "@context": {
    "msg" : "http://purl.org/webofneeds/message#",
    "conn" : "https://satsrv04.researchstudio.at:8889/won/resource/connection/",
    "woncrypt" : "http://purl.org/webofneeds/woncrypt#",
    "signature" : "http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#",
    "need" : "https://satsrv04.researchstudio.at:8889/won/resource/need/",
    "xsd" : "http://www.w3.org/2001/XMLSchema#",
    "cert" : "http://www.w3.org/ns/auth/cert#",
    "rdfs" : "http://www.w3.org/2000/01/rdf-schema#",
    "local" : "https://satsrv04.researchstudio.at:8889/won/resource/",
    "geo" : "http://www.w3.org/2003/01/geo/wgs84_pos#",
    "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    "won" : "http://purl.org/webofneeds/model#",
    "ldp" : "http://www.w3.org/ns/ldp#",
    "event" : "https://satsrv04.researchstudio.at:8889/won/resource/event/",
    "sioc" : "http://rdfs.org/sioc/ns#",
    "dc" : "http://purl.org/dc/elements/1.1/"
  },
  "@type": "won:Need",
  "won:hasContent": {
    "@type": "won:NeedContent"
  }  
}
pheara commented 8 years ago

Note: The sparql-query needs to be limited in a way, that it includes the event containers but excludes the content of the events themselves. The depth of the query above accidentally does that, but should it change it might cause bugs. We need the list of eventUris along with the need but not the events themselves (that will be stored elsewhere in the state).

We could also filter out other stuff we don't need (e.g. the crypto-info) in the app that way to make the stored state smaller.

pheara commented 8 years ago

To go from the triples we get to jsonld, the function jsonld.promises.fromRdf should be helpful.

pheara commented 8 years ago

Rdfstorejs probably registers a parser (like the this one) with jsonld.js somewhere that translates between their triple structures, so they can handle jsonld.

pheara commented 8 years ago

Apparently there's a far simpler geo ontology we can use, that also looks to be more of a standard.

pheara commented 8 years ago

An even easier option for transformation to jsonld would be to create and pass them in the 'normalized' format, e.g.:

_:c14n0 <http://schema.org/latitude> "40.75"^^<http://www.w3.org/2001/XMLSchema#float> .
_:c14n0 <http://schema.org/longitude> "73.98"^^<http://www.w3.org/2001/XMLSchema#float> .
_:c14n1 <http://schema.org/description> "The Empire State Building is a 102-story landmark in New York City." .
_:c14n1 <http://schema.org/geo> _:c14n0 .
_:c14n1 <http://schema.org/image> <http://www.civil.usherbrooke.ca/cours/gci215a/empire-state-building.jpg> .
_:c14n1 <http://schema.org/name> "The Empire State Building" .

rdfstorejs translates from it here

pheara commented 8 years ago

To delay a lot of refactoring due to added prefixes, we can use the 'compact' jsonld-form like in the first example here and define aliases for all predicates that are already in use.

pheara commented 8 years ago

Using a need like the one above, jsonld.toRDF produced the following n-quad structure:

@default : Array[0]
https://satsrv04.researchstudio.at:8889/won/resource/event/4801209644582595000#envelope-sig : Array[11]
    0 : Object
        object : Object
            type : "IRI"
            value : "http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#GraphSigningMethod"
            __proto__ : Object
        predicate : Object
            type : "IRI"
            value : "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
            __proto__ : Object
        subject : Object
            type : "blank node"
            value : "_:b0"
            __proto__ : Object
        __proto__ : Object
    1 : Object
        object : Object
        predicate : Object
        subject : Object
        __proto__ : Object
    2 : Object
    3 : Object
    4 : Object
    5 : Object
    6 : Object
    7 : Object
    8 : Object
    9 : Object
    10 : Object
    length : 11
    __proto__ : Array[0]
https://satsrv04.researchstudio.at:8889/won/resource/event/4801209644582595000#need : Array[28]
https://satsrv04.researchstudio.at:8889/won/resource/event/4801209644582595000#need-sig : Array[11]
https://satsrv04.researchstudio.at:8889/won/resource/need/2348825695750928400#sysinfo : Array[11]

that can then be fed into jsonld.fromRDF( … jsonld.frame( … )) with an intermediate result of:

[Object, Object, Object, Object]
  0 : Object
    @graph : Array[2]
      0 : Object
        @id : "_:b0"
        @type : Array[1]
        http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#hasDigestMethod : Array[1]
          0 : Object
            @id : "http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#dm-sha-256"
            __proto__ : Object
            length : 1
            __proto__ : Array[0]
        http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#hasGraphCanonicalizationMethod : Array[1]
        http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#hasGraphDigestMethod : Array[1]
        http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#hasGraphSerializationMethod : Array[1]
        http://icp.it-risk.iwvi.uni-koblenz.de/ontologies/signature.owl#hasSignatureMethod : Array[1]
        __proto__ : Object
      1 : Object
        length : 2
        __proto__ : Array[0]
    @id : "https://satsrv04.researchstudio.at:8889/won/resource/event/4801209644582595000#envelope-sig"
    __proto__ : Object
  1 : Object
  2 : Object
  3 : Object
  length : 4

and final framed result of:

Object {@context: Object, @graph: Array[1]}
  @context : Object
  @graph : Array[1]
    0 : Object
      @id : "need:2348825695750928400"
      @type : "won:Need"
      cert:key : Object
      http://purl.org/dc/terms/created : Object
      won:hasBasicNeedType : Object
      won:hasConnections : Object
      won:hasContent : Object
      won:hasEventContainer : Object
        @id : "need:2348825695750928400#events"
        @type : "won:EventContainer"
        rdfs:member : Array[4]
        __proto__ : Object
      won:hasFacet : Object
      won:hasWonNode : Object
      won:isInState : Object
      __proto__ : Object
    length : 1
    __proto__ : Array[0]
  __proto__ : Object

All of the above were generated using the following snippet:

//context.compactArrays=true //for compact
//context.useNativeTypes=true //for fromRDF
//console.log('original: ', doc)
jsonld.toRDF(doc, {}, (err, triples) => {
  console.log('triples: ', triples);
  jsonld.fromRDF(triples, context, (err, complexJsonLd) => {
    console.log('complexJsonLd: ', complexJsonLd);
    //jsonld.compact(complexJsonLd, context, (err, compacted) => console.log('compacted: ', compacted));
    jsonld.frame(complexJsonLd, frame, (err, framed) => console.log('framed: ', framed));
  })
})
pheara commented 8 years ago

Open TODOs as of 418ccde87bccea1ab25c620f93e6dc3d81d1ba4b :

fkleedorfer commented 8 years ago

Downranking this item. There are more pressing things to do