Upload a file on a solid pot and connecting to my pod

Hello,

I’m trying since few weeks to upload a file on my pod.
But i dont really understand how it works. First of all, when i try to connect on my pod i have this error :

error invalid_request
error_description Mismatching redirect uri

here is the code i use to upload file on my pod :

 async function uploadFile(event) {
    event.preventDefault();
    const fileInput = document.getElementById("fileInput");
    const file = fileInput.files[0];
    const url = `${session.info.webId}/public/${file.name}`;
    try {
        const fileResponse = await overwriteFile("https://******.solidcommunity.net/public/", file, { contentType: "text/plain" ,  fetch: session.fetch});
        document.getElementById(
            "labelUploadStatus"
        ).innerHTML = `File uploaded successfully at <a href="${url}" target="_blank">${url}</a>`;
        document.getElementById("labelUploadStatus").setAttribute("role", "alert");
    } catch (error) {
        console.log(`Error uploading file: ${error}`);
        document.getElementById(
            "labelUploadStatus"
        ).innerHTML = `Error uploading file: ${error}`;
        document.getElementById("labelUploadStatus").setAttribute("role", "alert");
    }
}

I’m a bit confused and stuck, someone know how i can upload a file on my pod ? And how can i acces my pod without having this issue ?

Hey there

The error seems related to the login process. Could you share the code for this? In particular, as the redirect url seems to cause troubles, what is the redirect url and the url of your application?

In general, following tutorial should cover the login process, so you could try to start with this and then modify it to your needs: Authenticate (Browser) — Inrupt JavaScript Client Libraries

The error indeed indicates something is wrong with auth, so I’d fix that first, but then after that, you’re also calling overwriteFile with a Container path (https://******.solidcommunity.net/public/), so you’re trying to overwrite that Container, which I think Pods reject. Instead, you’ll probably want to use saveFileInContainer.

1 Like

there is no code for that, it’s when i want to go on my pod, when i’m connected. I just click on the link finishing by “#card” and i dont understand why but it give me this error. When i’m in private nav it does work

So i changed and used the function you gave me.

When i click on the link where my file is supposed to be i’ve this :
image

The upload seems to work, but the name of the file isn’t the good one and the type of file too. I upload RDF file and got a TXT is that normal ?

image

Here is my full javaScript code :


import {
    getSolidDataset,
    getThing,
    setThing,
    getStringNoLocale,
    setStringNoLocale,
    saveSolidDatasetAt, 
    overwriteFile,
    getSourceUrl,
    saveFileInContainer
} from "@inrupt/solid-client";
import { Session } from "@inrupt/solid-client-authn-browser";
import { VCARD } from "@inrupt/vocab-common-rdf";

// If your Pod is *not* on `solidcommunity.net`, change this to your identity provider.
const SOLID_IDENTITY_PROVIDER = "https://solidcommunity.net";
document.getElementById(
    "solid_identity_provider"
).innerHTML = `[<a target="_blank" href="${SOLID_IDENTITY_PROVIDER}">${SOLID_IDENTITY_PROVIDER}</a>]`;

const NOT_ENTERED_WEBID =
    "...not logged in yet - but enter any WebID to read from its profile...";

const session = new Session();

const buttonLogin = document.getElementById("btnLogin");
const writeForm = document.getElementById("writeForm");
const readForm = document.getElementById("readForm");
const uploadForm = document.getElementById("uploadForm");

// 1a. Start Login Process. Call session.login() function.
async function login() {
    if (!session.info.isLoggedIn) {
        await session.login({
            oidcIssuer: SOLID_IDENTITY_PROVIDER,
            clientName: "Inrupt tutorial client app",
            redirectUrl: window.location.href
        });
    }
}

// 1b. Login Redirect. Call session.handleIncomingRedirect() function.
// When redirected after login, finish the process by retrieving session information.
async function handleRedirectAfterLogin() {
    await session.handleIncomingRedirect(window.location.href);
    if (session.info.isLoggedIn) {
        // Update the page with the status.
        document.getElementById(
            "labelStatus"
        ).innerHTML = `Your session is logged in with the WebID [<a target="_blank" href="${session.info.webId}">${session.info.webId}</a>].`;
        document.getElementById("labelStatus").setAttribute("role", "alert");
        document.getElementById("webID").value = session.info.webId;
    }
}

// The example has the login redirect back to the index.html.
// This calls the function to process login information.
// If the function is called when not part of the login redirect, the function is a no-op.
handleRedirectAfterLogin();

// 2. Write to profile
async function writeProfile() {
    const name = document.getElementById("input_name").value;

    if (!session.info.isLoggedIn) {
        // You must be authenticated to write.
        document.getElementById(
            "labelWriteStatus"
        ).textContent = `...you can't write [${name}] until you first login!`;
        document.getElementById("labelWriteStatus").setAttribute("role", "alert");
        return;
    }
    const webID = session.info.webId;
    // The WebID can contain a hash fragment (e.g. `#me`) to refer to profile data
    // in the profile dataset. If we strip the hash, we get the URL of the full
    // dataset.
    const profileDocumentUrl = new URL(webID);
    profileDocumentUrl.hash = "";

    // To write to a profile, you must be authenticated. That is the role of the fetch
    // parameter in the following call.
    let myProfileDataset = await getSolidDataset(profileDocumentUrl.href, {
        fetch: session.fetch
    });

    // The profile data is a "Thing" in the profile dataset.
    let profile = getThing(myProfileDataset, webID);

    // Using the name provided in text field, update the name in your profile.
    // VCARD.fn object is a convenience object that includes the identifier string "http://www.w3.org/2006/vcard/ns#fn".
    // As an alternative, you can pass in the "http://www.w3.org/2006/vcard/ns#fn" string instead of VCARD.fn.
    profile = setStringNoLocale(profile, VCARD.fn, name);

    // Write back the profile to the dataset.
    myProfileDataset = setThing(myProfileDataset, profile);

    // Write back the dataset to your Pod.
    await saveSolidDatasetAt(profileDocumentUrl.href, myProfileDataset, {
        fetch: session.fetch
    });

    // Update the page with the retrieved values.
    document.getElementById(
        "labelWriteStatus"
    ).textContent = `Wrote [${name}] as name successfully!`;
    document.getElementById("labelWriteStatus").setAttribute("role", "alert");
    document.getElementById(
        "labelFN"
    ).textContent = `...click the 'Read Profile' button to to see what the name might be now...?!`;
}

// 3. Read profile
async function readProfile() {
    const webID = document.getElementById("webID").value;

    if (webID === NOT_ENTERED_WEBID) {
        document.getElementById(
            "labelFN"
        ).textContent = `Login first, or enter a WebID (any WebID!) to read from its profile`;
        return false;
    }

    try {
        new URL(webID);
    } catch (_) {
        document.getElementById(
            "labelFN"
        ).textContent = `Provided WebID [${webID}] is not a valid URL - please try again`;
        return false;
    }

    const profileDocumentUrl = new URL(webID);
    profileDocumentUrl.hash = "";

   
    // Profile is public data; i.e., you do not need to be logged in to read the data.
    // For illustrative purposes, shows both an authenticated and non-authenticated reads.

    let myDataset;
    try {
        if (session.info.isLoggedIn) {
            myDataset = await getSolidDataset(profileDocumentUrl.href, { fetch: session.fetch });
        } else {
            myDataset = await getSolidDataset(profileDocumentUrl.href);
        }
    } catch (error) {
        document.getElementById(
            "labelFN"
        ).textContent = `Entered value [${webID}] does not appear to be a WebID. Error: [${error}]`;
        return false;
    }

    const profile = getThing(myDataset, webID);

    const formattedName = getStringNoLocale(profile, VCARD.fn);

    // Update the page with the retrieved values.
    document.getElementById("labelFN").textContent = `[${formattedName}]`;
}

 // 4. Upload file
 async function uploadFile(event) {
    event.preventDefault();
    const fileInput = document.getElementById("fileInput");
    const file = fileInput.files[0];
    const url = `https://luciesorreau.solidcommunity.net/public/${file.name}`;
    try {
        const fileResponse = await saveFileInContainer("https://luciesorreau.solidcommunity.net/public/", file, { contentType: "text/plain" ,  fetch: session.fetch});
        document.getElementById(
            "labelUploadStatus"
        ).innerHTML = `File uploaded successfully at <a href="${url}" target="_blank">${url}</a>`;
        document.getElementById("labelUploadStatus").setAttribute("role", "alert");
    } catch (error) {
        console.log(`Error uploading file: ${error}`);
        document.getElementById(
            "labelUploadStatus"
        ).innerHTML = `Error uploading file: ${error}`;
        document.getElementById("labelUploadStatus").setAttribute("role", "alert");
    }
}


buttonLogin.onclick = function () {
    login();
};

writeForm.addEventListener("submit", (event) => {
    event.preventDefault();
    writeProfile();
});

readForm.addEventListener("submit", (event) => {
    event.preventDefault();
    readProfile();
});

uploadForm.addEventListener("submit", (event) => {
    event.preventDefault();
    uploadFile(event);
});

Yes, currently you do not specify the file name and the content type should be text/turtle (text/plain is for txt). You can add the name suggestion (And it’s really only a suggestion, no guarantee that it gets this name) with the slug option and change the content type option to contentType: 'text/turtle'.

If you want to make sure it gets this name you’ll need to use the overwriteFile method as initially, but add the name to the url (https://.../public/file.ttl).

1 Like

When you say that i have to use the overwriteFile method you mean after having upload the file with the saveFileInContainer? Or replace ?

Use either of them, overwriteFile or saveFileInContainer. The overwriteFile with the url where the file should be created, the saveFileInContainer with the container url.

1 Like

Thanks for your answer.

The idea of this project is first of all download the data you can have on sites like google, discord etc and then upload them to a pod and then develop :

  • a graphical interface to deposit the files and to export the resulting data.
  • a set of reels to read data from several departments and transform them into a common format.
  • a data query and search service.

Do you have any advice or links that might help me develop this? Because to be honest I find that solid technology is quite difficult to take in hand…