Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/photo_gallery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: photo_gallery

on:
push:
branches:
- master
pull_request:
paths:
- rust/photo_gallery/**
- .github/workflows/photo_gallery.yml

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
rust-photo_gallery:
runs-on: ubuntu-24.04
container: ghcr.io/dfinity/icp-dev-env-rust:1.0.0
env:
ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Deploy and test
working-directory: rust/photo_gallery
run: |
icp network start -d
icp deploy
make test
20 changes: 0 additions & 20 deletions rust/photo_gallery/.devcontainer/devcontainer.json

This file was deleted.

6 changes: 1 addition & 5 deletions rust/photo_gallery/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@
.DS_Store
**/.DS_Store

# dfx temporary files
.dfx/

# generated files
**/declarations/
frontend/src/bindings/

# rust
target/

# frontend code
node_modules/
dist/
.svelte-kit/

# environment variables
.env
113 changes: 0 additions & 113 deletions rust/photo_gallery/BUILD.md

This file was deleted.

3 changes: 1 addition & 2 deletions rust/photo_gallery/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions rust/photo_gallery/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.PHONY: test

test:
@echo "=== Test 1: list_images returns empty list initially ==="
@result=$$(icp canister call --query backend list_images '()') && \
echo "$$result" && \
echo "$$result" | grep -q 'vec {}' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 2: upload_image stores an image and returns an ID ==="
@result=$$(icp canister call backend upload_image '("test.png", "image/png", blob "\89\50\4e\47")') && \
echo "$$result" && \
echo "$$result" | grep -qE '^\(([0-9]+) : nat64\)$$' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 3: list_images includes the uploaded image ==="
@result=$$(icp canister call --query backend list_images '()') && \
echo "$$result" && \
echo "$$result" | grep -q 'test.png' && \
echo "$$result" | grep -q 'image/png' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 4: upload a second image and list_images returns both ==="
@icp canister call backend upload_image '("photo.jpg", "image/jpeg", blob "\ff\d8\ff")' > /dev/null
@result=$$(icp canister call --query backend list_images '()') && \
echo "$$result" && \
echo "$$result" | grep -q 'test.png' && \
echo "$$result" | grep -q 'photo.jpg' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 5: http_request serves uploaded image by ID ==="
@result=$$(icp canister call --query backend http_request '(record { method = "GET"; url = "/image/1"; headers = vec {}; body = blob "" })') && \
echo "$$result" && \
echo "$$result" | grep -q '200' && \
echo "PASS" || (echo "FAIL" && exit 1)

@echo "=== Test 6: http_request returns 404 for missing image ==="
@result=$$(icp canister call --query backend http_request '(record { method = "GET"; url = "/image/9999"; headers = vec {}; body = blob "" })') && \
echo "$$result" && \
echo "$$result" | grep -q '404' && \
echo "PASS" || (echo "FAIL" && exit 1)
56 changes: 36 additions & 20 deletions rust/photo_gallery/README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,57 @@
# Photo gallery
# Photo Gallery

A decentralized photo gallery application built on the Internet Computer blockchain. Users can upload, view, and manage their photos in a decentralized environment.
A decentralized photo gallery application built on the Internet Computer. Users can upload and view photos stored directly on-chain, served via the HTTP gateway with browser-cacheable responses.

**WARNING:** This is meant primarily as a demo to show how the response verification library and HTTP gateways can be used to serve images with cache headers. It is not making use of authentication or certification. Use it at your own risk.
**Note:** This example is primarily a demo showing how the [response verification library](https://docs.internetcomputer.org/references/http-gateway-protocol-spec) and HTTP gateways can serve images with long-lived `Cache-Control` headers. It does not implement authentication or per-user access control. Use it at your own risk.

## Deploying from ICP Ninja
## Overview

[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/editor?g=https://github.com/dfinity/examples/rust/photo_gallery)
The backend canister stores images in memory and exposes three methods:

## Build and deploy from the command-line
- `upload_image(name, content_type, data)` — stores an image blob and returns its numeric ID.
- `list_images()` — returns metadata (ID, name, content type) for all stored images.
- `http_request(request)` — serves images at `/image/<id>` via the HTTP gateway, including skip-certification headers and `Cache-Control: public, max-age=31536000, immutable` so browsers cache images after the first fetch.

### 1. [Download and install the IC SDK.](https://internetcomputer.org/docs/building-apps/getting-started/install)
The frontend is a React + Vite application that uploads images and renders the gallery by constructing HTTP gateway URLs for each image ID, allowing the browser to fetch and cache image data directly.

### 2. Download your project from ICP Ninja using the 'Download files' button on the upper left corner, or [clone the GitHub examples repository.](https://github.com/dfinity/examples/)
## Build and deploy from the command line

### 3. Navigate into the project's directory.
### Prerequisites

### 4. Deploy the project to your local environment:
- [Node.js](https://nodejs.org/en/download/)
- icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm`

```
dfx start --background --clean && dfx deploy
```
### Install

```bash
git clone https://github.com/dfinity/examples
cd examples/rust/photo_gallery
```

#### 5. Generate Candid interfaces after making changes to the backend:
### Deploy and test

```
npm run generate
```bash
icp network start -d
icp deploy
make test
icp network stop
```

#### 6. Deploy frontend development server (if needed):
To run the Vite dev server with hot reload during frontend development:

```bash
npm run dev
```
npm start

## Updating the Candid interface

If you modify the backend's public API, rebuild the canister and regenerate the `.did` file:

```bash
icp build backend
candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.did
```

## Security considerations and best practices

If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices.

If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices.
7 changes: 2 additions & 5 deletions rust/photo_gallery/backend/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
[package]
name = "pictures-site-backend"
name = "backend"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate-type = ["cdylib"]
path = "lib.rs"

[dependencies]
candid = "0.10"
ic-cdk = "0.17"
ic-cdk-timers = "0.11" # Feel free to remove this dependency if you don't need timers
ic-cdk = "0.20"
serde = { version = "1.0", features = ["derive"] }
ic-http-certification = "3.0.3"
regex = "1.11.1"
17 changes: 0 additions & 17 deletions rust/photo_gallery/dfx.json

This file was deleted.

17 changes: 5 additions & 12 deletions rust/photo_gallery/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
{
"name": "pictures-site-frontend",
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"setup": "npm i && dfx canister create backend && dfx generate backend && dfx deploy",
"start": "vite --port 3000",
"prebuild": "npm i --include=dev && dfx generate",
"prebuild": "npm i --include=dev",
"build": "tsc && vite build",
"format": "prettier --write \"src/**/*.{json,js,jsx,ts,tsx,css,scss}\""
"dev": "vite"
},
"dependencies": {
"@icp-sdk/core": "~5.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^20.4.2",
"@icp-sdk/bindgen": "~0.2.2",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@vitejs/plugin-react": "^4.0.1",
"dotenv": "^16.3.1",
"prettier": "^3.0.0",
"sass": "^1.63.6",
"typescript": "^5.1.3",
"vite": "^6.3.5",
"vite-plugin-environment": "^1.1.3"
"vite": "^6.3.5"
}
}
Loading
Loading