diff --git a/p2p/10.IPFS_or_HTTP/README.md b/p2p/10.IPFS_or_HTTP/README.md
new file mode 100644
index 00000000..4d8fc92a
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/README.md
@@ -0,0 +1,190 @@
+# 10. Learn the differences between HTTP and IPFS
+
+## π« Table of contents
+
+* [Step 0 - Setup](README.md#π§-step-0---setup)
+* [Step 1 - HTTP](README.md#step-1---http)
+ * [Discover the basics](README.md#βοΈ-10-discover-the-basics)
+ * [Storage](README.md#πΎ-11-storage)
+* [Step 2 - IPFS](README.md#step-2---ipfs)
+ * [Improve the storage](README.md#πΈοΈ-20-improve-the-storage)
+ * [Retrieve](README.md#π₯-22-retrieve)
+* [Going further](README.md#π-going-further)
+
+In this Workshop, you will learn :
+
+βοΈ The basics of HTTP
+
+βοΈ The basics of IPFS, and why in some cases it is better than HTTP
+
+βοΈ How to change a centralized storage into a distributed one via IPFS with Infura !
+
+## π§ Step 0 - Setup
+
+Please follow each instruction on the [SETUP.md](SETUP.md) file.
+
+## Step 1 - HTTP
+
+### βοΈ 1.0 Discover the basics
+
+Wanna launch the back-end? It's very simple, just run the container you pulled in the setup:
+
+```
+docker run -p 8080:8080 sacharbon/workshop-ipfs
+```
+
+you should have this log :
+
+```bash
+[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
+
+[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
+ - using env: export GIN_MODE=release
+ - using code: gin.SetMode(gin.ReleaseMode)
+
+[GIN-debug] GET /images --> main.getImages (4 handlers)
+[GIN-debug] GET /images/:id --> main.getImageByID (4 handlers)
+[GIN-debug] POST /upload --> main.uploadImage (4 handlers)
+[GIN-debug] GET /uploads/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)
+[GIN-debug] HEAD /uploads/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)
+[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
+Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
+[GIN-debug] Listening and serving HTTP on 0.0.0.0:8080
+```
+
+As you can see, there is different route for the back-end of our website. You can open your favorite browser like Firefox or Chrome (or Opera,
+no discrimination here) and go to this URL: [http://0.0.0.0:8080/images](http://0.0.0.0:8080/images).
+
+You should see an empty array !!
+
+If you want to shut down the server, use `Ctrl` + `C` and then run `docker stop ${id}`.
+
+Now it's time to wake the front-end up.
+
+Go to [the source of the front-end](./openocean/frontend/) and type `bun i` to download the dependencies. Then, type `bun dev` to launch the front-side of our web-app.
+
+Now visit this URL: [localhost:5173](localhost:5173). You should see a pretty UI made by two genius.
+
+### πΎ 1.1 Storage
+
+Go to [Unsplash](https://unsplash.com/photos/a-woman-sitting-at-a-table-using-a-cell-phone-nplkFSNschY) website and download the image.
+By the way, you can look for any other image you prefer on this website, it is free and open source. For the example, we are going to stick with this image.
+Go back to [http://localhost:5173/](http://localhost:5173), scroll down and click on the button on the `up right`.
+Fill the form correctly and validates it.
+
+Now, look at your terminal, you should see those strange logs appear:
+
+```bash
+[GIN] 2024/12/02 - 19:10:29 | 200 | 85.347Β΅s | 172.17.0.1 | GET "/images"
+[GIN] 2024/12/02 - 19:10:29 | 200 | 140.871Β΅s | 172.17.0.1 | GET "/images"
+[GIN] 2024/12/02 - 19:10:37 | 200 | 2.93712ms | 172.17.0.1 | POST "/upload"
+[GIN] 2024/12/02 - 19:10:37 | 200 | 30.521Β΅s | 172.17.0.1 | GET "/images/08245a6c-0843-4f68-bb41-c1dea72369c7"
+[GIN] 2024/12/02 - 19:10:37 | 200 | 15.784Β΅s | 172.17.0.1 | GET "/images/08245a6c-0843-4f68-bb41-c1dea72369c7"
+[GIN] 2024/12/02 - 19:10:37 | 200 | 5.895332ms | 172.17.0.1 | GET "/uploads/65fb793f-a8b5-4c88-9fbc-6432d40961ba.png"
+
+```
+
+Let me explain:
+The first part of the message is obviously the date-time. The second one is two numbers. The `200` is the most interesting : it is a status, preview code. `200` means that the server is OK to give us that page from the `/images` route, and it has been delivered correctly.
+Then, the time it took to respond to the request. Afterward, the address which requested. And finally, the method, `GET`, because we want to just get the page ; we are asking the server to give us the `/images` route which is the home page.
+
+![](http_request_flowchart.png)
+*Scheme of a HTTP request*
+
+>π‘ What does `POST` means ?
+
+`POST` is another **HTTP method** than `GET`. When you fill the form earlier, it was **you** that was giving the server
+some information :that is the main difference between `POST` and `GET`.
+
+> π‘ Learn more about HTTP methods [here](https://fr.wikipedia.org/wiki/Hypertext_Transfer_Protocol).
+
+Then, go to look at our `uploads` folder : you have the file you just downloaded in here !
+>π‘ This is how HTTP works. When retrieving data, HTTP focuses on **location**.
+
+## Step 2 - IPFS
+
+> π‘ HTTP is cool but has its limits : if the server is down, you won't be able to retrieve the data stored. Furthermore, your government can easily block access to certain servers by their IPs that host particular website for censure purposes.
+Let's see how IPFS answers this issues.
+
+At its core, IPFS is a [distributed system](https://en.wikipedia.org/wiki/Distributed_computing) for storing and accessing files, websites, applications, and data.
+Instead of referring to data (photos, articles, videos) by **location**, or which server they are stored on, IPFS refers
+to everything by that dataβs [hash](https://docs.ipfs.io/concepts/hashing/#hashes-are-important), meaning the **content itself.**
+
+The idea is that if you want to access a particular page from your browser, IPFS will ask the entire network, βdoes anyone
+have the data that corresponds to this hash?β A node on IPFS that contains the corresponding hash will return the data, allowing you to access it from anywhere (and potentially even offline).
+
+If this is not enough clear for you, I strongly advise you to refer to this [video (Simply Explained IPFS)](https://www.youtube.com/watch?v=5Uj6uR3fp-U).
+
+### πΈοΈ 2.0 Improve the storage
+
+Here is what we are going to do : We are going to upload our files directly on IPFS and not locally anymore.
+Instead of having the file locally, let's pin it with [Pinata](https://pinata.cloud/). Which is a pinning service.
+
+1. Go to `frontend/src/hooks/` and create a new hook `usePinFileToIPFS.ts` as a manner of `usePostImage.ts` It should call the [list file Pinata API route](https://docs.pinata.cloud/api-reference/endpoint/list-files).
+> π‘ Don't forget to create an [Pinata API & Gateway key](https://app.pinata.cloud/developers/api-keys) and write it down into your a `.env`. You can create one by typing in your terminal in `frontend/` folder:
+
+ ```
+cp .env.dist .env
+```
+
+2. Go to `frontend/src/pages/Upload.tsx` and modify the code of the upload view to communicate with your new hook in order to upload the file there.
+3. Go https://app.pinata.cloud/pinmanager and make sure the hash of the song appears.
+
+
+Some Trouble with IPFS API ?
+ Here is some links that could help you:
+
+ What is an API ?
+
+
+ Infura IPFS API
+
+
+ ipfs-Api python package
+
+
+
+### π₯ 2.2 Retrieve
+
+Last step : if anyone wants to see from our website some images, we need to get it from IPFS.
+Since you did the previous step, this one would seem easy : in your `src/page`
+ on the `index.tsx`, do the same thing as previously but instead of adding a file, call the get method to retrieve your image.
+
+## π Going further
+
+A very cool feature with IPFS is that if someone is having an IPFS node running on its machine and download your image then you deleted it, you will be able to retrieve it from its node !
+
+* Learn [how](https://docs.ipfs.io/how-to/command-line-quick-start) you can deploy and configure your own IPFS node.
+* Want to store a lot of data on IPFS but being the only one that can access it? Look at [OrbitDB](https://orbitdb.org/).
+
+## Authors
+
+| [Sacha Dujardin ](https://github.com/Sacharbon) |
+| :---: |
+
+
+Organization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+> π Don't hesitate to follow us on our different networks, and put a star π on `PoC's` repositories.
diff --git a/p2p/10.IPFS_or_HTTP/SETUP.md b/p2p/10.IPFS_or_HTTP/SETUP.md
new file mode 100644
index 00000000..d776181b
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/SETUP.md
@@ -0,0 +1,10 @@
+# Setup π§
+
+In order to launch our image platform, you have to download Docker and Bun.
+
+* [Docker](https://docs.docker.com/get-started/get-docker/)
+ Once docker is downloaded, pull this docker repo `sacharbon/workshop-ipfs`
+
+* [Bun](https://bun.sh/)
+
+[Go back to the exercise](README.md#step-1---http)
diff --git a/p2p/old/3.IPFS_or_HTTP/http_request_flowchart.png b/p2p/10.IPFS_or_HTTP/http_request_flowchart.png
similarity index 100%
rename from p2p/old/3.IPFS_or_HTTP/http_request_flowchart.png
rename to p2p/10.IPFS_or_HTTP/http_request_flowchart.png
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/.env.dist b/p2p/10.IPFS_or_HTTP/openocean/frontend/.env.dist
new file mode 100644
index 00000000..3f3c2a64
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/.env.dist
@@ -0,0 +1,2 @@
+VITE_PINATA_API_KEY=
+VITE_PINATA_GATEWAY=
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/.eslintrc.cjs b/p2p/10.IPFS_or_HTTP/openocean/frontend/.eslintrc.cjs
new file mode 100644
index 00000000..d6c95379
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/.eslintrc.cjs
@@ -0,0 +1,18 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parser: '@typescript-eslint/parser',
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/.gitignore b/p2p/10.IPFS_or_HTTP/openocean/frontend/.gitignore
new file mode 100644
index 00000000..50c8dda2
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+.env
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/bun.lockb b/p2p/10.IPFS_or_HTTP/openocean/frontend/bun.lockb
new file mode 100755
index 00000000..de7b05c3
Binary files /dev/null and b/p2p/10.IPFS_or_HTTP/openocean/frontend/bun.lockb differ
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/index.html b/p2p/10.IPFS_or_HTTP/openocean/frontend/index.html
new file mode 100644
index 00000000..6101660e
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ OpenOcean
+
+
+
+
+
+
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/package.json b/p2p/10.IPFS_or_HTTP/openocean/frontend/package.json
new file mode 100644
index 00000000..869faad7
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@chakra-ui/react": "^2.8.2",
+ "@emotion/react": "^11.11.4",
+ "@emotion/styled": "^11.11.5",
+ "@tanstack/react-query": "^5.51.11",
+ "axios": "^1.7.2",
+ "env-var": "^7.5.0",
+ "framer-motion": "^11.2.11",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.52.0",
+ "react-icons": "^5.2.1",
+ "react-router-dom": "^6.23.1",
+ "vite-plugin-node-polyfills": "^0.22.0",
+ "zustand": "^4.5.2"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.66",
+ "@types/react-dom": "^18.2.22",
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
+ "@typescript-eslint/parser": "^7.2.0",
+ "@vitejs/plugin-react": "^4.2.1",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "eslint-plugin-react-refresh": "^0.4.6",
+ "typescript": "^5.2.2",
+ "vite": "^5.2.0"
+ }
+}
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/public/_redirects b/p2p/10.IPFS_or_HTTP/openocean/frontend/public/_redirects
new file mode 100644
index 00000000..78f7f206
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/public/_redirects
@@ -0,0 +1 @@
+/* /index.html 200
\ No newline at end of file
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/public/openocean.png b/p2p/10.IPFS_or_HTTP/openocean/frontend/public/openocean.png
new file mode 100644
index 00000000..db253a00
Binary files /dev/null and b/p2p/10.IPFS_or_HTTP/openocean/frontend/public/openocean.png differ
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/public/vite.svg b/p2p/10.IPFS_or_HTTP/openocean/frontend/public/vite.svg
new file mode 100644
index 00000000..e7b8dfb1
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/App.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/App.tsx
new file mode 100644
index 00000000..d38365e4
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/App.tsx
@@ -0,0 +1,55 @@
+import Header from "./organisms/Header";
+import { BrowserRouter, Outlet, Route, Routes } from "react-router-dom";
+import theme, { colors } from "./theme";
+import { ChakraProvider, VStack } from "@chakra-ui/react";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import Home from "./pages";
+import { FC } from "react";
+import ImageDetailsPage from "./pages/images/:id";
+import ImagePage from "./pages/images";
+import UploadPage from "./pages/Upload";
+
+const Layout: FC = () => (
+
+
+
+
+
+
+);
+
+const queryClient = new QueryClient;
+
+const App: FC = () => {
+ return (
+
+
+
+
+ }>
+ } />
+ } />
+
+ } />
+ } />
+
+
+
+
+
+
+ );
+};
+
+export default App;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/assets/react.svg b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/assets/react.svg
new file mode 100644
index 00000000..6c87de9b
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/HeaderContainer.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/HeaderContainer.tsx
new file mode 100644
index 00000000..655d43cf
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/HeaderContainer.tsx
@@ -0,0 +1,19 @@
+import { HStack } from "@chakra-ui/react";
+import { FC, PropsWithChildren } from "react";
+
+const HeaderContainer: FC = ({ children }) => (
+
+ {children}
+
+);
+
+export default HeaderContainer;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/IMGCard.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/IMGCard.tsx
new file mode 100644
index 00000000..923b24f1
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/IMGCard.tsx
@@ -0,0 +1,34 @@
+import { AspectRatio, Box } from "@chakra-ui/react";
+import { FC } from "react";
+import { urlFromFileName } from "../utils";
+
+interface ImageCardProps {
+ url?: string;
+ ratio?: number;
+}
+const IMGCard: FC = ({ url, ratio = 16 / 9 }) => (
+
+
+
+);
+
+export default IMGCard;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/Logo.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/Logo.tsx
new file mode 100644
index 00000000..6ce3e9a5
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/atoms/Logo.tsx
@@ -0,0 +1,14 @@
+import { Icon, Text, VStack } from "@chakra-ui/react";
+import { FC } from "react";
+import { BsEasel } from "react-icons/bs";
+
+const Logo: FC = () => (
+
+
+
+ OpenOcean
+
+
+);
+
+export default Logo;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/constants.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/constants.ts
new file mode 100644
index 00000000..6aa56907
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/constants.ts
@@ -0,0 +1,13 @@
+import { from } from "env-var";
+
+const vars = {
+ VITE_PINATA_API_KEY: import.meta.env.VITE_PINATA_API_KEY,
+ VITE_PINATA_GATEWAY: import.meta.env.VITE_PINATA_GATEWAY,
+};
+
+const env = from(vars, {});
+
+export const constants = {
+ pinataAPIKey: env.get("VITE_PINATA_API_KEY").asString(),
+ pinataGateway: env.get("VITE_PINATA_GATEWAY").asString(),
+};
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/useGetImageByID.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/useGetImageByID.ts
new file mode 100644
index 00000000..2de8c108
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/useGetImageByID.ts
@@ -0,0 +1,11 @@
+import { useMutation } from "@tanstack/react-query";
+import axios from "axios";
+
+const useGetImageByID = () =>
+ useMutation({
+ mutationFn: (id: string | undefined) => {
+ return axios.get(`http://localhost:8080/images/${id}`);
+ },
+ });
+
+export default useGetImageByID;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/useGetImages.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/useGetImages.ts
new file mode 100644
index 00000000..31058195
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/useGetImages.ts
@@ -0,0 +1,11 @@
+import { useMutation } from "@tanstack/react-query";
+import axios from "axios";
+
+const useGetImages = () =>
+ useMutation({
+ mutationFn: () => {
+ return axios.get("http://localhost:8080/images");
+ },
+ });
+
+export default useGetImages;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/usePostImage.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/usePostImage.ts
new file mode 100644
index 00000000..c1aa8b4b
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/hooks/usePostImage.ts
@@ -0,0 +1,15 @@
+import { useMutation } from "@tanstack/react-query";
+import axios from "axios";
+
+const usePostImage = () =>
+ useMutation({
+ mutationFn: (params: { image: File, name: string }) => {
+ const formData = new FormData();
+ formData.append("image", params.image);
+ formData.append("name", params.name);
+ console.log(formData);
+ return axios.post("http://localhost:8080/upload", formData);
+ },
+ });
+
+export default usePostImage;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/index.css b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/index.css
new file mode 100644
index 00000000..54aa67d4
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/index.css
@@ -0,0 +1,8 @@
+html {
+ background-color: rgb(41, 41, 41);
+}
+
+::-webkit-scrollbar {
+ width: 0px;
+ background: transparent; /* make scrollbar transparent */
+}
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/main.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/main.tsx
new file mode 100644
index 00000000..966f17a4
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/main.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App.tsx";
+import "./index.css";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+
+);
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/HomeButton.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/HomeButton.tsx
new file mode 100644
index 00000000..aa10c916
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/HomeButton.tsx
@@ -0,0 +1,16 @@
+import { FC } from "react";
+import Logo from "../atoms/Logo";
+import { Box } from "@chakra-ui/react";
+import { useNavigate } from "react-router-dom";
+
+const HomeButton: FC = () => {
+ const navigate = useNavigate();
+
+ return (
+ navigate("/")}>
+
+
+ );
+};
+
+export default HomeButton;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/IMGCardWithDetails.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/IMGCardWithDetails.tsx
new file mode 100644
index 00000000..61af1ab2
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/IMGCardWithDetails.tsx
@@ -0,0 +1,61 @@
+import { Box, Card, Icon, Text, Tooltip } from "@chakra-ui/react";
+import { FC } from "react";
+import IMGCard from "../atoms/IMGCard";
+import { FaQuestion } from "react-icons/fa";
+
+interface IMGCardWithDetailsProps {
+ name: string;
+ description: string;
+ img?: string;
+ onClick: () => void;
+}
+const IMGCardWithDetails: FC = ({
+ name,
+ description,
+ img,
+ onClick,
+}) => (
+
+
+ {description}
+
+
+ }
+ >
+
+
+ {!img && (
+
+ )}
+
+
+ {name}
+
+
+
+
+);
+
+export default IMGCardWithDetails;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/NavButton.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/NavButton.tsx
new file mode 100644
index 00000000..5fc68c30
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/NavButton.tsx
@@ -0,0 +1,27 @@
+import { Button, Icon } from "@chakra-ui/react";
+import { FC } from "react";
+import { IconType } from "react-icons";
+import { useLocation, useNavigate } from "react-router-dom";
+
+interface NavButtonProps {
+ path: string;
+ icon: IconType;
+ label: string;
+}
+const NavButton: FC = ({ path, icon, label }) => {
+ const navigate = useNavigate();
+ const location = useLocation();
+
+ return (
+ navigate(path)} flexDir="column" variant="primary">
+
+ {label}
+
+ );
+};
+
+export default NavButton;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/SectionTitle.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/SectionTitle.tsx
new file mode 100644
index 00000000..d2d8610e
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/SectionTitle.tsx
@@ -0,0 +1,24 @@
+import { Button, HStack, Text } from "@chakra-ui/react";
+import { FC } from "react";
+
+interface SectionTitleProps {
+ title: string;
+ subtitle?: string;
+ onClick: () => void;
+}
+const SectionTitle: FC = ({
+ onClick,
+ title,
+ subtitle = "View all",
+}) => (
+
+
+ {title}
+
+
+ {subtitle}
+
+
+);
+
+export default SectionTitle;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/SingleUploadImage.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/SingleUploadImage.tsx
new file mode 100644
index 00000000..e60a580b
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/molecules/SingleUploadImage.tsx
@@ -0,0 +1,76 @@
+import {
+ Center,
+ chakra,
+ VStack,
+ ScaleFade,
+ Text,
+ Icon,
+ Image,
+ ChakraProps,
+ CenterProps,
+} from "@chakra-ui/react";
+import { FC, useState } from "react";
+import { MdAdd } from "react-icons/md";
+
+interface SingleUploadImageProps {
+ size?: ChakraProps["boxSize"];
+ rounded?: ChakraProps["rounded"];
+ onUpdateFile: (file: File) => void;
+}
+const SingleUploadImage: FC = ({
+ onUpdateFile,
+ ...props
+}) => {
+ const [uploadedFile, setUploadedFile] = useState(null);
+
+ const handleFileChange = (event: { target: { files: FileList | null } }) => {
+ const file = event.target.files?.[0];
+ if (!file) return;
+ setUploadedFile(file);
+ onUpdateFile(file);
+ };
+
+ return (
+
+ {uploadedFile ? (
+
+
+
+ ) : (
+
+
+
+ Upload
+
+
+ )}
+
+
+
+ );
+};
+
+export default SingleUploadImage;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/organisms/AvailableImages.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/organisms/AvailableImages.tsx
new file mode 100644
index 00000000..1a758f08
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/organisms/AvailableImages.tsx
@@ -0,0 +1,40 @@
+import { HStack, Box } from "@chakra-ui/react";
+import { motion } from "framer-motion";
+import { FC } from "react";
+import IMGCard from "../atoms/IMGCard";
+import { useNavigate } from "react-router-dom";
+
+const AvailableImages: FC = ({ images }) => {
+ const navigate = useNavigate();
+
+ return (
+
+
+ {images.map((image: any) => (
+ navigate(`/images/${image.id}`)}
+ w={`${33}vw`}
+ px="24px"
+ flexShrink={0}
+ >
+
+
+ ))}
+
+
+ );
+};
+
+export default AvailableImages;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/organisms/Header.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/organisms/Header.tsx
new file mode 100644
index 00000000..54818640
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/organisms/Header.tsx
@@ -0,0 +1,17 @@
+import { FC } from "react";
+import { HStack } from "@chakra-ui/react";
+import HomeButton from "../molecules/HomeButton";
+import NavButton from "../molecules/NavButton";
+import HeaderContainer from "../atoms/HeaderContainer";
+import { RiImageAddFill } from "react-icons/ri";
+
+const Header: FC = () => (
+
+
+
+
+
+
+);
+
+export default Header;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/Upload.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/Upload.tsx
new file mode 100644
index 00000000..2b27afe5
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/Upload.tsx
@@ -0,0 +1,148 @@
+import {
+ FormControl,
+ Button,
+ FormErrorMessage,
+ FormLabel,
+ Icon,
+ Input,
+ Stack,
+ Text,
+ VStack,
+ chakra,
+ useToast,
+} from "@chakra-ui/react";
+import { FC } from "react";
+import SingleUploadImage from "../molecules/SingleUploadImage";
+import { colors } from "../theme";
+import { useForm } from "react-hook-form";
+import { RiImageAddFill } from "react-icons/ri";
+import usePostImage from "../hooks/usePostImage";
+import { useNavigate } from "react-router-dom";
+
+interface MintForm {
+ name: string;
+ description: string;
+ file: File;
+ collection: string;
+ price: number;
+}
+
+const UploadPage: FC = () => {
+ const {
+ handleSubmit,
+ register,
+ setValue,
+ clearErrors,
+ setError,
+ formState: { errors },
+ } = useForm();
+
+ const toast = useToast();
+
+ const navigate = useNavigate();
+
+ const { mutate: postImage, isPending: isPendingPostImage } =
+ usePostImage();
+
+ const onSubmit = handleSubmit((data) => {
+ if (!data.file) {
+ setError("file", { message: "This field is required" });
+ return;
+ }
+ postImage({ image: data.file, name: data.name }, {
+ onSuccess: (res) => {
+ toast({
+ colorScheme: "purple",
+ title: "Image uploaded",
+ description: "Your image has been uploaded successfully!",
+ status: "success",
+ duration: 5000,
+ isClosable: true,
+ });
+ navigate(`/images/${res.data.id}`)
+ },
+ onError: (err) => {
+ console.log(err)
+ toast({
+ colorScheme: "red",
+ title: "Error",
+ description: "There was an error uploading the image to IPFS",
+ status: "error",
+ duration: 5000,
+ isClosable: true,
+ });
+ },
+ });
+ });
+
+ return (
+
+
+ Upload new picture
+
+
+
+ {
+ setValue("file", file);
+ clearErrors("file");
+ }}
+ />
+ {errors.file && (
+ An image is required
+ )}
+
+
+
+
+
+ Name
+
+ {errors.name && (
+ This field is required
+ )}
+
+
+
+ Upload
+
+
+
+
+
+
+ );
+};
+
+export default UploadPage;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/images/:id.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/images/:id.tsx
new file mode 100644
index 00000000..8e47588e
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/images/:id.tsx
@@ -0,0 +1,51 @@
+import {
+ Box,
+ HStack,
+ Text,
+ VStack,
+} from "@chakra-ui/react";
+import { FC, useState, useEffect } from "react";
+import IMGCard from "../../atoms/IMGCard";
+import { useParams } from "react-router-dom";
+import useGetImageByID from "../../hooks/useGetImageByID";
+
+const ImageDetailsPage: FC = () => {
+ const { id } = useParams();
+ const [img, setImg] = useState([]);
+
+ const { mutate: getImageByID } = useGetImageByID();
+
+ useEffect(() => {
+ getImageByID(id, {
+ onSuccess: (data) => {
+ setImg(data.data);
+ console.log(data.data)
+ },
+ onError: (error) => {
+ console.error("Erreur :", error);
+ },
+ });
+ }, [getImageByID]);
+
+ if (!img) return null;
+
+ return (
+
+
+
+
+ #{img.id}
+
+ {img.name}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ImageDetailsPage;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/images/index.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/images/index.tsx
new file mode 100644
index 00000000..bde36098
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/images/index.tsx
@@ -0,0 +1,62 @@
+import {
+ Card,
+ Divider,
+ SimpleGrid,
+ Text,
+ VStack,
+} from "@chakra-ui/react";
+import { FC, useState, useEffect } from "react";
+import IMGCard from "../../atoms/IMGCard";
+import { useNavigate } from "react-router-dom";
+import useGetImages from "../../hooks/useGetImages";
+
+const ImageCard: FC<{ img: any }> = ({ img }) => {
+ const navigate = useNavigate();
+ return (
+ navigate(`/images/${img.id}`)}
+ cursor="pointer"
+ role="group"
+ gap="12px"
+ p="12px"
+ >
+
+ {img.metadata?.name}
+
+
+
+
+ );
+};
+
+const ImagePage: FC = () => {
+ const [images, setImages] = useState([]);
+
+ const { mutate: getImages } = useGetImages();
+
+ useEffect(() => {
+ getImages(undefined, {
+ onSuccess: (data) => {
+ setImages(data.data);
+ },
+ onError: (error) => {
+ console.error("Erreur :", error);
+ },
+ });
+ }, [getImages]);
+
+ return (
+
+
+ All images
+
+
+ {images.map((img) => (
+
+ ))}
+
+
+ );
+};
+
+export default ImagePage;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/index.tsx b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/index.tsx
new file mode 100644
index 00000000..7264fcae
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/pages/index.tsx
@@ -0,0 +1,39 @@
+import { FC } from "react";
+import { VStack } from "@chakra-ui/react";
+import SectionTitle from "../molecules/SectionTitle";
+import { useNavigate } from "react-router-dom";
+import AvailableImages from "../organisms/AvailableImages";
+import useGetImages from "../hooks/useGetImages";
+import { useEffect, useState } from "react";
+
+const Home: FC = () => {
+ const navigate = useNavigate();
+ const [images, setImages] = useState([]);
+
+ const { mutate: getImages } = useGetImages();
+
+ useEffect(() => {
+ getImages(undefined, {
+ onSuccess: (data) => {
+ setImages(data.data);
+ },
+ onError: (error) => {
+ console.error("Erreur :", error);
+ },
+ });
+ }, [getImages]);
+
+
+ return (
+ <>
+ {images && (
+ < VStack align="start" w="100%" h="100%" spacing="24px">
+ navigate("/images")} />
+
+
+ )}
+ >
+ );
+};
+
+export default Home;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/theme.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/theme.ts
new file mode 100644
index 00000000..ba351736
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/theme.ts
@@ -0,0 +1,113 @@
+import { defineStyleConfig, extendTheme } from "@chakra-ui/react";
+
+export const colors = {
+ gray: {
+ 50: "#f7fafc",
+ 100: "#edf2f7",
+ 200: "#e2e8f0",
+ 300: "#cbd5e0",
+ 400: "#a0aec0",
+ 500: "#718096",
+ 600: "#4a5568",
+ 700: "#2d3748",
+ 800: "#1a202c",
+ 900: "#171923",
+ },
+};
+
+const Button = defineStyleConfig({
+ baseStyle: {
+ fontWeight: "bold",
+ borderRadius: "base",
+ },
+ variants: {
+ primary: {
+ p: "0px",
+ fontFamily: "heading",
+ color: "gray.400",
+ _hover: {
+ color: "gray.50",
+ },
+ transitionDuration: "0.5s",
+ },
+ secondary: {
+ p: "0px",
+ fontFamily: "heading",
+ background: "purple.600",
+ boxShadow: "lg",
+ color: "gray.300",
+ _hover: {
+ border: `1px solid ${colors.gray[300]}`,
+ color: "gray.200",
+ background: "purple.400",
+ },
+ border: `1px solid ${colors.gray[900]}`,
+ transitionDuration: "0.5s",
+ },
+ tertiary: {
+ p: "0px",
+ fontFamily: "heading",
+ background: "gray.800",
+ boxShadow: "lg",
+ color: "gray.200",
+ _hover: {
+ border: `1px solid ${colors.gray[500]}`,
+ color: "gray.100",
+ background: "gray.700",
+ },
+ border: `1px solid ${colors.gray[700]}`,
+ transitionDuration: "0.5s",
+ },
+ },
+ defaultProps: {
+ size: "md",
+ variant: "primary",
+ },
+});
+
+const Card = {
+ parts: ["container"],
+ baseStyle: {
+ container: {
+ border: `1px solid ${colors.gray[700]}`,
+ boxShadow: "lg",
+ bg: "gray.800",
+ },
+ },
+};
+
+const theme = extendTheme({
+ colors,
+ fonts: {
+ heading: "Poppins, sans-serif",
+ body: "Whyte, sans-serif",
+ },
+ components: {
+ Table: {
+ variants: {
+ simple: {
+ th: {
+ borderColor: "gray.700",
+ },
+ td: {
+ borderColor: "gray.800",
+ },
+ },
+ },
+ },
+ Text: {
+ baseStyle: {
+ color: "gray.50",
+ },
+ },
+ Heading: {
+ baseStyle: {
+ color: "gray.50",
+ },
+ },
+ Button,
+ Card,
+ },
+});
+
+export default theme;
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/utils/index.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/utils/index.ts
new file mode 100644
index 00000000..b5774093
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/utils/index.ts
@@ -0,0 +1,30 @@
+import { constants } from "../constants";
+
+export const displayUgnot = (ugnot: number) => {
+ return ugnot >= 1000
+ ? `${Math.floor(ugnot / 1000).toLocaleString("fr-FR")} GNOT`
+ : `${ugnot.toLocaleString("fr-FR")} ugnot`;
+};
+
+export const displayGnot = (gnot: number) => {
+ return `${gnot.toLocaleString("fr-FR", {
+ style: "currency",
+ currency: "USD",
+ })} GNOT`;
+};
+
+export const parseDataJson = (data: string): T => {
+ const content = data.slice(2, -'" string)'.length).replaceAll("\\", "");
+ return JSON.parse(content);
+};
+
+export const urlFromIpfsHash = (hash: string) =>
+ hash.includes("https://")
+ ? hash
+ : `https://${constants.pinataGateway}/ipfs/${hash}`;
+
+export const urlFromFileName = (filename: string): string => {
+ const url = `http://localhost:8080/uploads/${filename}`;
+ console.log(url);
+ return url;
+}
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/src/vite-env.d.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/vite-env.d.ts
new file mode 100644
index 00000000..11f02fe2
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/tsconfig.json b/p2p/10.IPFS_or_HTTP/openocean/frontend/tsconfig.json
new file mode 100644
index 00000000..d4aba321
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "useDefineForClassFields": true,
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/tsconfig.node.json b/p2p/10.IPFS_or_HTTP/openocean/frontend/tsconfig.node.json
new file mode 100644
index 00000000..97ede7ee
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/p2p/10.IPFS_or_HTTP/openocean/frontend/vite.config.ts b/p2p/10.IPFS_or_HTTP/openocean/frontend/vite.config.ts
new file mode 100644
index 00000000..634dc411
--- /dev/null
+++ b/p2p/10.IPFS_or_HTTP/openocean/frontend/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+import { nodePolyfills } from "vite-plugin-node-polyfills";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react(), nodePolyfills()],
+});
diff --git a/p2p/old/3.IPFS_or_HTTP/README.md b/p2p/old/3.IPFS_or_HTTP/README.md
deleted file mode 100644
index 5aea7da3..00000000
--- a/p2p/old/3.IPFS_or_HTTP/README.md
+++ /dev/null
@@ -1,212 +0,0 @@
-# 3. Learn the differences between HTTP and IPFS !
-
-## π« Table of contents
-* [Step 0 - Setup](README.md#π§-step-0---setup)
-* [Step 1 - HTTP](README.md#step-1---http)
- * [Discover the basics](README.md#βοΈ-10-discover-the-basics)
- * [Storage](README.md#πΎ-11-storage)
-* [Step 2 - IPFS](README.md#step-2---ipfs)
- * [Improve the storage](README.md#πΈοΈ-20-improve-the-storage)
- * [Retrieve](README.md#π₯-22-retrieve)
-* [Going further](README.md#π-going-further)
-
-
-In this Workshop, you will learn :
-
-βοΈ Run a web application with `docker-compose`
-
-βοΈ The basics of HTTP
-
-βοΈ The basics of IPFS, and why in some cases it is better than HTTP
-
-βοΈ How to change a centralized storage into a distributed one via IPFS with Infura !
-
-## π§ Step 0 - Setup
-Please follow each instruction on the [SETUP.md](SETUP.md) file.
-
-## Step 1 - HTTP
-### βοΈ 1.0 Discover the basics
-Wanna launch the platform? Alright, make sure you are on the [sources](./sources.zip) directory where the `Dockerfile` and
-`docker-compose.yml` are.
-
-Build the multi service container :
-```bash
-sudo docker-compose build
-```
-You have to only use this command once. After several steps, you should have this output:
-```bash
-Successfully built a998a543950c
-Successfully tagged music-share_web:latest
-```
-> π‘ The number `a998a543950c` is the id of your container, it's ok if yours is different.
-
-Then, each time you want to launch your website, run :
-```bash
-docker-compose up
-```
-you should have this log :
-```bash
-Starting music-share_db_1 ... done
-Starting music-share_web_1 ... done
-Attaching to music-share_db_1, music-share_web_1
-db_1 |
-db_1 | PostgreSQL Database directory appears to contain a database; Skipping initialization
-db_1 |
-db_1 | 2021-08-02 20:48:37.281 UTC [1] LOG: starting PostgreSQL 13.2 (Debian 13.2-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
-db_1 | 2021-08-02 20:48:37.281 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
-db_1 | 2021-08-02 20:48:37.281 UTC [1] LOG: listening on IPv6 address "::", port 5432
-db_1 | 2021-08-02 20:48:37.283 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
-db_1 | 2021-08-02 20:48:37.286 UTC [25] LOG: database system was shut down at 2021-08-02 20:48:32 UTC
-db_1 | 2021-08-02 20:48:37.289 UTC [1] LOG: database system is ready to accept connections
-web_1 | No changes detected
-web_1 | Operations to perform:
-web_1 | Apply all migrations: admin, auth, contenttypes, musicshare, sessions
-web_1 | Running migrations:
-web_1 | No migrations to apply.
-web_1 | Watching for file changes with StatReloader
-web_1 | Performing system checks...
-web_1 |
-web_1 | System check identified no issues (0 silenced).
-web_1 | August 02, 2021 - 20:48:39
-web_1 | Django version 3.1.6, using settings 'music_share_project.settings'
-web_1 | Starting development server at http://0.0.0.0:8000/
-web_1 | Quit the server with CONTROL-C.
-
-```
-As you can see, `db_1` is our database which seems okay and ready to accept new connections,
-and `web_1` is the backend of our website. You can open your favorite browser like Firefox or Chrome (or Opera,
-no discrimination here) and go to this url: [http://0.0.0.0:8000/](http://0.0.0.0:8000/).
-
-You should see our beautiful website !!
-
-If you want to shut down the server, use `Ctrl` + `C` and then run `docker-compose down -v`.
-
-### πΎ 1.1 Storage
-
-Go to the [freearchivemusic](https://freemusicarchive.org/music/Scott_Holmes/rock-background-music/country-road-drive)
-website and download the song.
-By the way, you can look for any other genres of music you prefer on this website, it is free and open source. For the example, we are going to
-stick with this song.
-Go back to [http://0.0.0.0:8000/](http://0.0.0.0:8000/), scroll down and click on the button `upload a song`.
-Fill the form correctly and validates it.
-
-You can find the code of the form in `musichare/forms.py`, and the associate model object in
-`musicshare/models.py`.
-
-Now, look at your terminal, you should see those strange logs appear:
-```bash
-web_1 | [06/Aug/2021 11:02:33] "GET / HTTP/1.1" 200 4650
-web_1 | [06/Aug/2021 11:02:37] "GET /upload/ HTTP/1.1" 200 4640
-web_1 | [06/Aug/2021 11:02:57] "POST /upload/ HTTP/1.1" 302 0
-web_1 | [06/Aug/2021 11:02:57] "GET /success/ HTTP/1.1" 200 4360
-web_1 | [06/Aug/2021 11:02:59] "POST / HTTP/1.1" 200 5120
-web_1 | [06/Aug/2021 11:02:59] "GET /media/static/Scott_Holmes_Music_-_Country_Road_Drive.mp3 HTTP/1.1" 200 8983053
-```
-Let me explain:
-The first part of the message is obviously the datetime. The second one is the method, `GET`, because we want to just
-get the page ; we are asking the server to give us the `/` route which is the home page.
-Then, the `HTTP` protocol and finally two numbers. The `200` is the most interesting : it is a status, preview code. `200` means
-that the server is ok to give us that page from the `/` route, and it has been delivered correctly.
-
-![](http_request_flowchart.png)
-*Scheme of a HTTP request*
-
->π‘ What does `POST` means ?
-
-`POST` is another **HTTP method** than `GET`. When you fill the form earlier, it was **you** that was giving the server
-some information :that is the main difference between `POST` and `GET`.
-
-> π‘ Learn more about HTTP methods [here](https://www.restapitutorial.com/lessons/httpmethods.html).
-
-Now, look at our `media/static` folder : you have the mp3 file you just downloaded in here !
->π‘ This is how HTTP works. When retrieving data, HTTP focuses on **location**. Have you noticed the url ?
-First, it is `0.0.0.0` which is your local IP; then `:8000` to signify the port. Finally, the routes or file you want to
-get, joined by a `/`. That format does not ring a bell to you ? It is like a path !
-
-## Step 2 - IPFS
-
-> π‘ HTTP is cool but has its limits : if the server is down, you won't be able to retrieve the data stored. Furthermore,
-your government can easily block access to certain servers by their IPs that host particular website for censure purposes.
-Let's see how IPFS answers this issues.
-
-At its core, IPFS is a [distributed system](https://blog.stackpath.com/distributed-system/) for storing and accessing files, websites, applications, and data.
-Instead of referring to data (photos, articles, videos) by **location**, or which server they are stored on, IPFS refers
-to everything by that dataβs [hash](https://docs.ipfs.io/concepts/hashing/#hashes-are-important), meaning the **content itself.**
-
-The idea is that if you want to access a particular page from your browser, IPFS will ask the entire network, βdoes anyone
-have the data that corresponds to this hash?β A node on IPFS that contains the corresponding hash will return the data, allowing you to access it from anywhere (and potentially even offline).
-
-If this is not enough clear for you, I strongly advise you to refer to this [video (Simply Explained IPFS)](https://www.youtube.com/watch?v=5Uj6uR3fp-U).
-
-### πΈοΈ 2.0 Improve the storage
-
-Here is what we are going to do : We are going to upload our files directly on IPFS and not locally anymore.
-Instead of having the file locally, let's have its corresponding hash in our database.
-
-1. Go to `musicshare/models.py` and add a CharField for the hash.
-2. Go to `musicshare/views.py` and modify the code of the upload view to communicate with IPFS API in order to upload the file there.
- Please use port `5001` for the connection.
-3. Open `musicshare/templates/musicshare/index.html` to line `179`
- and make sure the hash of the song appears.
-
-
-Some Trouble with IPFS API ?
- Here is some links that could help you:
-
- What is an API ?
-
-
- Infura IPFS API
-
-
- ipfs-Api python package
-
-
-
-To apply your migrations, shut down the server and relaunch it.
-
-Test another time to upload your music, copy past the hash of the newly added song and go to `https://ipfs.infura.io:5001/api/v0/cat?arg={your_hash_here}`.
-You should see your song play, even if the server has been shut down !
-
-### π₯ 2.2 Retrieve
-Last step : if anyone wants to download from our website some mp3 songs, we need to get it from IPFS.
-Since you did the previous step, this one would seem easy : in your `musicshare/views.py`
- on the `download` view, do the same thing as previously but instead of adding a file, call the `cat` (or `get`) method.
-
-## π Going further
-A very cool feature with IPFS is that if someone is having an IPFS node running on its machine and download your mp3 audio
-then you deleted it, you will be able to retrieve it from its node !
-
-* Learn [how](https://docs.ipfs.io/how-to/command-line-quick-start) you can deploy and configure your own IPFS node.
-* Want to store a lot of data on IPFS but being the only one that can access it? Look at [OrbitDB](https://orbitdb.org/).
-
-## Authors
-
-| [Adina Cazalens ](https://github.com/NaadiQmmr) |
-| :---: |
-
-Organization
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-> π Don't hesitate to follow us on our different networks, and put a star π on `PoC's` repositories.
diff --git a/p2p/old/3.IPFS_or_HTTP/SETUP.md b/p2p/old/3.IPFS_or_HTTP/SETUP.md
deleted file mode 100644
index 3a31e09a..00000000
--- a/p2p/old/3.IPFS_or_HTTP/SETUP.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Setup π§
-
-In order to launch our music platform, you have to download Docker and the `source.zip`
-which contains the code of our web application.
-* [Docker](https://github.com/PoCInnovation/Workshops/blob/master/software/04.Docker/SETUP.md)
-* Download the [source.zip](https://github.com/PoCInnovation/Workshops/raw/p2p/digital_ipfs/p2p/3.IPFS_or_HTTP/sources.zip), move it to your working directory `mv ~/Downloads/sources.zip ; cd ` and unzip it `unzip ./sources.zip`.
-
-
-[Go back to the exercise](README.md#step-1---http)
diff --git a/p2p/old/3.IPFS_or_HTTP/sources.zip b/p2p/old/3.IPFS_or_HTTP/sources.zip
deleted file mode 100644
index a268e4d7..00000000
Binary files a/p2p/old/3.IPFS_or_HTTP/sources.zip and /dev/null differ