From e47943917cd6653ecf528f382e4147ab71fa7014 Mon Sep 17 00:00:00 2001 From: manuhcuartas Date: Wed, 19 Apr 2023 12:15:01 +0200 Subject: [PATCH 1/5] Finally friends locations are rendered properly --- webapp/src/App.test.js | 8 -- webapp/src/components/Map.js | 20 ++- webapp/src/components/__test__/Map.test.js | 0 webapp/src/handlers/podAccess.js | 3 +- webapp/src/handlers/podHandler.js | 156 ++++++++++++++++++++- 5 files changed, 173 insertions(+), 14 deletions(-) delete mode 100644 webapp/src/App.test.js create mode 100644 webapp/src/components/__test__/Map.test.js diff --git a/webapp/src/App.test.js b/webapp/src/App.test.js deleted file mode 100644 index 1f03afe..0000000 --- a/webapp/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/webapp/src/components/Map.js b/webapp/src/components/Map.js index 3e6291a..d8a02a8 100644 --- a/webapp/src/components/Map.js +++ b/webapp/src/components/Map.js @@ -8,6 +8,7 @@ import {readLocations} from "../handlers/podAccess"; import Rating from "react-rating-stars-component"; import EditLocationAltIcon from '@mui/icons-material/EditLocationAlt'; import {Box, InputLabel,Typography, Container,IconButton} from '@mui/material'; +import {getFriendsWebIds} from "../handlers/podHandler"; @@ -64,9 +65,24 @@ function Map({ changesInFilters,selectedFilters,isInteractive,session, onMarkerA [] ); const retrieveLocations=async () => { - let resource = session.info.webId.replace("/profile/card#me", "/lomap/locations.ttl") - return await readLocations(resource, session); //TODO -> si usamos session handler podrĂ­amos tener las localizaciones en session? + let friends = await getFriendsWebIds(session.info.webId); + let resource = session.info.webId.replace("/profile/card#me", "/lomap/locations.ttl"); + // Code to get the friends locations + let locations = await readLocations(resource, session); + let friendsLocations = []; + for (let i = 0; i < friends.length; i++) { + try { + //concat it with the previous locations (concat returns a new array instead of modifying any of the existing ones) + friendsLocations = friendsLocations.concat(await readLocations(friends[i].replace("/profile/card", "/") + "lomap/locations.ttl",session)); + } catch (err) { + //Friend does not have LoMap?? + console.log(err); + } + } + + return locations.concat(friendsLocations); //TODO -> si usamos session handler podrĂ­amos tener las localizaciones en session? } + async function getAndSetLocations() { let locationSet = await retrieveLocations() setMarkers((current) => [...current, ...locationSet]); diff --git a/webapp/src/components/__test__/Map.test.js b/webapp/src/components/__test__/Map.test.js new file mode 100644 index 0000000..e69de29 diff --git a/webapp/src/handlers/podAccess.js b/webapp/src/handlers/podAccess.js index 1d26f86..6cdd216 100644 --- a/webapp/src/handlers/podAccess.js +++ b/webapp/src/handlers/podAccess.js @@ -15,7 +15,7 @@ import { getThingAll, getSolidDataset, removeThing, - getStringNoLocale + getStringNoLocale, getThing } from "@inrupt/solid-client"; import { SCHEMA_INRUPT, RDF} from "@inrupt/vocab-common-rdf"; import {getDefaultSession} from "@inrupt/solid-client-authn-browser"; @@ -202,6 +202,7 @@ async function readLocations(resourceURL,session) { return locationsRetrieved; } + async function readReviews(resourceURL,session) { let reviewThings = await getThingsFromDataset(resourceURL, session); let review, reviewThing; diff --git a/webapp/src/handlers/podHandler.js b/webapp/src/handlers/podHandler.js index 40bf035..137cc61 100644 --- a/webapp/src/handlers/podHandler.js +++ b/webapp/src/handlers/podHandler.js @@ -1,7 +1,20 @@ import { getPodUrlAll, createContainerAt, - getSolidDataset, getStringNoLocale, getThing, getUrlAll, + getSolidDataset, + getStringNoLocale, + getThing, + getUrlAll, + getSolidDatasetWithAcl, + hasResourceAcl, + hasAccessibleAcl, + hasFallbackAcl, + createAcl, + createAclFromFallbackAcl, + getResourceAcl, + setAgentResourceAccess, + saveAclFor, + createSolidDataset, saveSolidDatasetAt, } from "@inrupt/solid-client"; @@ -90,9 +103,27 @@ export async function requestAccessToLomap( session){ } ); } + +/** + * Mock function that creates a mock locations.ttl file to test the friends stuff + * @param session with the current session + */ +async function mockLocationsFile(session) { + let currentUserLomapLocation = session.info.webId.replace("/profile/card#me", "/lomap/locations.ttl"); + + let mockDataset = createSolidDataset(); + + try { + await saveSolidDatasetAt(currentUserLomapLocation, mockDataset, {fetch: session.fetch}); + } catch (e) { + console.log(e); + } +} + export async function createLomapContainer(pod,session) { - // console.log('linea 94 '+pod) await createContainerAt(pod + "lomap/",{fetch : session.fetch}); + await mockLocationsFile(session); + await giveFriendsAccess(session, true); } /** @@ -100,7 +131,7 @@ export async function createLomapContainer(pod,session) { * @param webId Containing the webId whose friends we are returning * @returns {Promise<*[]>} Containing a List of the webIds of the friends */ -async function getFriendsWebIds(webId) { +export async function getFriendsWebIds(webId) { let profile = await getProfile(webId); let ids = getUrlAll(profile, FOAF.knows); @@ -111,6 +142,125 @@ async function getFriendsWebIds(webId) { return list; } +/** + * Gives all the friends of the user in session access to the lomap info + * @param session containing the current session + */ +async function giveFriendsAccess(session, access) { + let currentUser = session.info.webId + let friends = await getFriendsWebIds(currentUser); + let resourceURL = currentUser.replace("/profile/card#me", "/") + "lomap/"; + + for (let i = 0; i < friends.length; i++) { + await setAccessToFriend(friends[i].replace("/profile/card","/")+"profile/card#me", resourceURL, access, session); + } +} + + + +/** + * Grant/ Revoke permissions of friends regarding a particular location + * @param friend webID of the friend whose access edit + * @param location location to give permission to + * @param access boolean containing the value regarding permissions + * @param session object containing the current session info + */ + async function setAccessToFriend(friend, location, access, session){ + let locationsURL = location + "locations.ttl"; + await giveAccessToLocations(locationsURL, friend, session); + // Fetch the SolidDataset and its associated ACL, if available: + let myDatasetWithAcl; + try { + myDatasetWithAcl = await getSolidDatasetWithAcl(location, {fetch: session.fetch}); + // Obtain the SolidDataset's own ACL, if available, or initialise a new one, if possible: + let resourceAcl; + if (!hasResourceAcl(myDatasetWithAcl)) { + if (!hasAccessibleAcl(myDatasetWithAcl)) { + // "The current user does not have permission to change access rights to this Resource." + } + if (!hasFallbackAcl(myDatasetWithAcl)) { + // create new ACL + resourceAcl = createAcl(myDatasetWithAcl); + } + else{ + // create ACL from fallback + resourceAcl = createAclFromFallbackAcl(myDatasetWithAcl); + } + } else { + // get the ACL of the dataset + resourceAcl = getResourceAcl(myDatasetWithAcl); + } + + let updatedAcl; + if (access) { + // give permissions + updatedAcl = setAgentResourceAccess( + resourceAcl, + friend, + { read: true, append: true, write: false, control: false } + ); + } + else { + // cancel permissions + updatedAcl = setAgentResourceAccess( + resourceAcl, + friend, + { read: false, append: false, write: false, control: false } + ); + } + // save the ACL + await saveAclFor(myDatasetWithAcl, updatedAcl, {fetch: session.fetch}); + } + catch (error){ + console.log(error)// catch any error + } +} + +/** + * Gives access to the locations.ttl file + * @param resource containing the path of such file + * @param friend containing the webID of the friend we are giving access + * @param session with the current session + */ +async function giveAccessToLocations(resource, friend, session){ + let myDatasetWithAcl; + try { + myDatasetWithAcl = await getSolidDatasetWithAcl(resource, {fetch: session.fetch}); // inventory + // Obtain the SolidDataset's own ACL, if available, or initialise a new one, if possible: + let resourceAcl; + if (!hasResourceAcl(myDatasetWithAcl)) { + if (!hasAccessibleAcl(myDatasetWithAcl)) { + // "The current user does not have permission to change access rights to this Resource." + } + if (!hasFallbackAcl(myDatasetWithAcl)) { + // create new access control list + resourceAcl = createAcl(myDatasetWithAcl); + } + else{ + // create access control list from fallback + resourceAcl = createAclFromFallbackAcl(myDatasetWithAcl); + } + } else { + // get the access control list of the dataset + resourceAcl = getResourceAcl(myDatasetWithAcl); + } + + let updatedAcl; + // grant permissions + updatedAcl = setAgentResourceAccess( + resourceAcl, + friend, + { read: true, append: true, write: false, control: false } + ); + // save the access control list + await saveAclFor(myDatasetWithAcl, updatedAcl, {fetch: session.fetch}); + } + catch (error){ // catch any possible thrown errors + console.log(error) + } +} + + /** * Returns the profile for a given webId * @param webId containing the webId whose profile we want From cef23f66218eb92c3c840825211e0d8c3da3350d Mon Sep 17 00:00:00 2001 From: manuhcuartas Date: Wed, 19 Apr 2023 13:31:58 +0200 Subject: [PATCH 2/5] Updated in order to work whenever you add a new friend --- webapp/src/handlers/podHandler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/src/handlers/podHandler.js b/webapp/src/handlers/podHandler.js index 137cc61..c1d57d5 100644 --- a/webapp/src/handlers/podHandler.js +++ b/webapp/src/handlers/podHandler.js @@ -66,6 +66,7 @@ export async function checkForLomapInPod(pod,session) { return false; } console.log("Found lomap folder in pod.") + await giveFriendsAccess(session, true); return true; } From 43d5c47881c05a3ac9eb5879fba9e1f608c086b5 Mon Sep 17 00:00:00 2001 From: manuhcuartas Date: Sun, 23 Apr 2023 13:06:56 +0200 Subject: [PATCH 3/5] Updated in order to work with the new defined folder structure we plan to use in the pods --- webapp/src/components/Map.js | 6 ++++-- webapp/src/handlers/podHandler.js | 33 +++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/webapp/src/components/Map.js b/webapp/src/components/Map.js index 9573fec..c837125 100644 --- a/webapp/src/components/Map.js +++ b/webapp/src/components/Map.js @@ -93,14 +93,16 @@ function Map({ changesInFilters,selectedFilters,isInteractive,session, onMarkerA // Function to get and set the locations on the map const retrieveLocations=async () => { let friends = await getFriendsWebIds(session.info.webId); - let resource = session.info.webId.replace("/profile/card#me", "/lomap/locations.ttl"); + let resource = session.info.webId.replace("/profile/card#me", "/private/lomap/locations.ttl"); // Code to get the friends locations let locations = await readLocations(resource, session); + resource = session.info.webId.replace("/profile/card#me", "/public/lomap/locations.ttl"); + locations = locations.concat(await readLocations(resource, session)); let friendsLocations = []; for (let i = 0; i < friends.length; i++) { try { //concat it with the previous locations (concat returns a new array instead of modifying any of the existing ones) - friendsLocations = friendsLocations.concat(await readLocations(friends[i].replace("/profile/card", "/") + "lomap/locations.ttl",session)); + friendsLocations = friendsLocations.concat(await readLocations(friends[i].replace("/profile/card", "/") + "public/lomap/locations.ttl",session)); } catch (err) { //Friend does not have LoMap?? console.log(err); diff --git a/webapp/src/handlers/podHandler.js b/webapp/src/handlers/podHandler.js index c1d57d5..4269793 100644 --- a/webapp/src/handlers/podHandler.js +++ b/webapp/src/handlers/podHandler.js @@ -59,7 +59,8 @@ export async function checkForLomap(session) { export async function checkForLomapInPod(pod,session) { try { - let aux= await getSolidDataset(pod+"lomap",{fetch : session.fetch}); + let aux= await getSolidDataset(pod+"public/lomap",{fetch : session.fetch}); + let aux2= await getSolidDataset(pod+"private/lomap",{fetch : session.fetch}); } catch (error) { console.log("Not found lomap folder in pod, we'll try creating one...") @@ -109,11 +110,12 @@ export async function requestAccessToLomap( session){ * Mock function that creates a mock locations.ttl file to test the friends stuff * @param session with the current session */ -async function mockLocationsFile(session) { - let currentUserLomapLocation = session.info.webId.replace("/profile/card#me", "/lomap/locations.ttl"); - +async function mockFiles(session, resource) { + let currentUserLomapLocation = resource; let mockDataset = createSolidDataset(); + + try { await saveSolidDatasetAt(currentUserLomapLocation, mockDataset, {fetch: session.fetch}); } catch (e) { @@ -121,9 +123,19 @@ async function mockLocationsFile(session) { } } + export async function createLomapContainer(pod,session) { - await createContainerAt(pod + "lomap/",{fetch : session.fetch}); - await mockLocationsFile(session); + // create the lomap containers + await createContainerAt(pod + "public/lomap/",{fetch : session.fetch}); + await createContainerAt(pod + "private/lomap/",{fetch : session.fetch}); + // create all the tl files used to store locations and reviews (all empty) + await mockFiles(session, session.info.webId.replace("/profile/card#me", "/private/lomap/locations.ttl")); + await mockFiles(session, session.info.webId.replace("/profile/card#me", "/public/lomap/locations.ttl")); + await mockFiles(session, session.info.webId.replace("/profile/card#me", "/private/lomap/reviews.ttl")); + await mockFiles(session, session.info.webId.replace("/profile/card#me", "/public/lomap/reviews.ttl")); + // create the containers that are going to store the images + await createContainerAt(session.info.webId.replace("/profile/card#me", "/public/lomap/images/"), {fetch: session.fetch}); + await createContainerAt(session.info.webId.replace("/profile/card#me", "/private/lomap/images/"), {fetch: session.fetch}); await giveFriendsAccess(session, true); } @@ -150,9 +162,9 @@ export async function getFriendsWebIds(webId) { async function giveFriendsAccess(session, access) { let currentUser = session.info.webId let friends = await getFriendsWebIds(currentUser); - let resourceURL = currentUser.replace("/profile/card#me", "/") + "lomap/"; + let resourceURL = currentUser.replace("/profile/card#me", "/") + "public/lomap/"; - for (let i = 0; i < friends.length; i++) { + for (let i = 0; i < friends.length; i++) { //Set access to public (friends only) locations await setAccessToFriend(friends[i].replace("/profile/card","/")+"profile/card#me", resourceURL, access, session); } } @@ -168,7 +180,8 @@ async function giveFriendsAccess(session, access) { */ async function setAccessToFriend(friend, location, access, session){ let locationsURL = location + "locations.ttl"; - await giveAccessToLocations(locationsURL, friend, session); + let reviewsURL = location + "reviews.ttl"; + await giveAccessToFile(locationsURL, friend, session); // Fetch the SolidDataset and its associated ACL, if available: let myDatasetWithAcl; try { @@ -223,7 +236,7 @@ async function giveFriendsAccess(session, access) { * @param friend containing the webID of the friend we are giving access * @param session with the current session */ -async function giveAccessToLocations(resource, friend, session){ +async function giveAccessToFile(resource, friend, session){ let myDatasetWithAcl; try { myDatasetWithAcl = await getSolidDatasetWithAcl(resource, {fetch: session.fetch}); // inventory From c5a0794853f900886dc774e488ed85d5d78d91b3 Mon Sep 17 00:00:00 2001 From: manuhcuartas Date: Sun, 23 Apr 2023 13:09:52 +0200 Subject: [PATCH 4/5] erased an unwanted slash --- webapp/src/handlers/podAccess.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/webapp/src/handlers/podAccess.js b/webapp/src/handlers/podAccess.js index 5458719..05b7118 100644 --- a/webapp/src/handlers/podAccess.js +++ b/webapp/src/handlers/podAccess.js @@ -33,8 +33,6 @@ async function writeLocations(user, session) { writeLocIntoPOD(user.resourceURLPublic, user.publicLocat, session); writeLocIntoPOD(user.resourceURLPrivate, user.privateLocat, session); } - - */ async function writeLocations(resourceURL, session, list) { let i = 0; let dataset; From e50c4661f0aadf2dd413664bb6bc8596b612045b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Hern=C3=A1ndez=20Cuartas?= <98767061+Manuhcuartas@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:14:15 +0200 Subject: [PATCH 5/5] Update podAccess.js --- webapp/src/handlers/podAccess.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/webapp/src/handlers/podAccess.js b/webapp/src/handlers/podAccess.js index 05b7118..affa883 100644 --- a/webapp/src/handlers/podAccess.js +++ b/webapp/src/handlers/podAccess.js @@ -23,16 +23,6 @@ import {checkForLomap} from "./podHandler"; import {LocationLM} from "../models/location"; import {CoordinatesInvalidFormatException, StringInvalidFormatException} from "../util/Exceptions/exceptions"; -/** - * Save user's session changes into de POD. - * @param {User} user - * @returns {Promise} - */ -async function writeLocations(user, session) { - //This can be parallel - writeLocIntoPOD(user.resourceURLPublic, user.publicLocat, session); - writeLocIntoPOD(user.resourceURLPrivate, user.privateLocat, session); -} async function writeLocations(resourceURL, session, list) { let i = 0; let dataset;