diff --git a/README.md b/README.md
index 7291047..692c866 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@
Have you ever attended a wedding or a birthday party? If yes, you probably saw photo booth there. You get in, take a photo and paste it in the guest book - simple and fun. But what if we could bring this fun into the digital world? This is where **LensUp** comes to the rescue. **LensUp** is a web application that serves as a virtual gallery, allowing party guests to upload their photos from the event and also write down their wishes.
-- [Project status](#Project status)
-- [100 days roadmap](#100 days roadmap)
-- [How to run LensUp locally](#How to run LensUp locally)
-- [TODO list (100 days)](#TODO list (100 days))
+- [Project status](#project-status)
+- [100 days roadmap](#100-days-roadmap)
+- [How to run LensUp locally](#how-to-run-lensup-locally)
+- [TODO list (100 days)](#todo-list-(100-days))
# Project status
The video shows the project status as of `26.04.2024` and the core functionality of the application.
@@ -73,26 +73,85 @@ Description:
## How to run LensUp locally
-You can run the project locally on your machine using Docker. All services will be hosted on your WLAN network. Follow the steps below to run the application locally.
+You can run the project locally on your machine using Docker. Follow the steps below to run the application locally:
-1. Before we start you should generate `dev-certs` for LensUp on your machine. This operation is required to hosting ASP.NET Core images with Docker over HTTPS. So generate a certificate and configure the local machine:
+1. Before we start you should generate `dev-certs` for **LensUp** on your machine. This operation is required to hosting ASP.NET Core images with Docker over HTTPS. So generate a certificate using these commands:
```bash
dotnet dev-certs https -ep "%USERPROFILE%\.aspnet\https\lens-up.pfx" -p localCertPassword
dotnet dev-certs https --trust
```
- **Replace `%USERPROFILE%` with your computer name.** Example `"C:\Users\Kamil\.aspnet\https\lens-up.pfx"`
+ **Replace `%USERPROFILE%` with your computer name.** Example `"C:\Users\Dell Precision 7520\.aspnet\https\lens-up.pfx"`
- **This is necessary step, because docker-compose refers to that certificate**.
+ **For local development purposes, we will use the password `localCertPassword`. Do not change this, as the same password is used in the `docker-compose.yml` file.**
-2. Install `docker desktop` on your machine (skip if you already done it).
+ The above commands should generate a `lens-up.pfx` certificate, and should place it in the directory as shown in the screenshot below.
+
+ 
+
+ **This is necessary step, because docker-compose refers to that certificate!**
+
+2. Install `docker desktop` on your machine *(skip if you already done it)*.
3. Run your `docker desktop` application.
-4. To be continued.
+4. In the main project directory (`lens-up`), where the `docker-compose.yml` file is located, run the command `docker-compose build`. This will build 7 necessary LensUp images. After completing these steps, you should see new images in the Docker Desktop application.
+
+ 
+
+5. After the build command, run the `docker-compose up` to start the entire infrastructure. You should see in Docker Desktop that 7 containers related to LensUp have been started.
+
+ 
+
+6. Now the entire application is running on your machine. You can use the following addresses:
+
+ - Backend services:
+
+ - `LensUp.BackOfficeService.API` swagger - https://localhost:8085/swagger/index.html
+ - `LensUp.GalleryService.API` swagger - https://localhost:8083/swagger/index.html
+ - `LensUp.GalleryService.WebhookTriggerSimulator` - http://localhost:8086/
+ - `LensUp.PhotoCollectorService.API` swagger - https://localhost:8081/swagger/index.html
+
+ - UI applications:
+
+ - `LensUp.GalleryService.UI` - http://localhost:5001/
+
+ - `LensUp.PhotoCollectorService.UI` - http://localhost:5002/
+
+ *On LensUp.PhotoCollectorService.UI you will see error page, because you need to navigate to the view associated with a specific gallery, which you haven't created yet.*
+
+
+
+**How to create your first gallery and have fun with LensUp?**
+
+1. Go to `LensUp.BackOfficeService.API` - https://localhost:8085/swagger/index.html
+
+2. Use `Create` endpoint to create your gallery. The endpoint returns the gallery identifier after it is created **(1)**.
+
+ 
+
+3. Before using the gallery, we need to activate it. In that case use `Activate` endpoint and pass `galleryId` and `endDate` in request body. Remember the `endDate` is validated and must be greater than the current time. Otherwise, your gallery will be treated as expired. The endpoint returns the gallery `enterCode` after it is activated **(1)**.
+
+ 
+
+4. With your gallery `enterCode` you can open your gallery using `LensUp.GalleryService.UI` - http://localhost:5001/
+
+ Log in to your gallery using `enterCode`.
+
+ 
+
+5. Now you can scan gallery QR code and upload photos to it. The code redirects to a form for adding photos to the gallery. You can use browser tool to scan QR code or if it doesn't work you can just go to `http://localhost:5002/upload-photo/{enterCode}`.
+
+ 
+
+6. QR Code redirects you to add photo and wishes form. Now you can upload your data to gallery.
+
+ 
+7. After successfully completing the form, we should see success notification and the photo should appear in the gallery.
+ 
## TODO list (100 days)
diff --git a/backend-services/Directory.Packages.props b/backend-services/Directory.Packages.props
index 6df5888..96faae3 100644
--- a/backend-services/Directory.Packages.props
+++ b/backend-services/Directory.Packages.props
@@ -4,7 +4,6 @@
true
-
@@ -24,9 +23,5 @@
-
-
-
-
\ No newline at end of file
diff --git a/backend-services/back-office-service/src/LensUp.BackOfficeService.API/appsettings.Development.json b/backend-services/back-office-service/src/LensUp.BackOfficeService.API/appsettings.Development.json
index 8cb9e1f..1d5811c 100644
--- a/backend-services/back-office-service/src/LensUp.BackOfficeService.API/appsettings.Development.json
+++ b/backend-services/back-office-service/src/LensUp.BackOfficeService.API/appsettings.Development.json
@@ -10,6 +10,6 @@
"AzureStorage": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://host.docker.internal:10000/devstoreaccount1;QueueEndpoint=http://host.docker.internal:10001/devstoreaccount1;TableEndpoint=http://host.docker.internal:10002/devstoreaccount1;"
},
"ApplicationOptions": {
- "PhotoCollectorUIUrl": "http://localhost:5002"
+ "PhotoCollectorUIUrl": "http://localhost:5002/upload-photo"
}
}
diff --git a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/AppSettingsKeys.cs b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/AppSettingsKeys.cs
new file mode 100644
index 0000000..f0c6e8c
--- /dev/null
+++ b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/AppSettingsKeys.cs
@@ -0,0 +1,7 @@
+namespace LensUp.GalleryService.WebhookTriggerSimulator;
+
+internal static class AppSettingsKeys
+{
+ public const string AzureWebJobsAzureStorageConnectionString = "AzureWebJobsAzureStorageConnectionString";
+ public const string WebhookUrl = "WebhookUrl";
+}
diff --git a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/Dockerfile b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/Dockerfile
index 40921b8..7517c92 100644
--- a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/Dockerfile
+++ b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/Dockerfile
@@ -1,26 +1,26 @@
+FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0 AS base
+WORKDIR /home/site/wwwroot
+EXPOSE 8080
-FROM mcr.microsoft.com/dotnet/sdk:8.0 AS installer-env
-
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
COPY ["Directory.Build.props", "/"]
-COPY ["Directory.Packages.props", "/"]
COPY ["StyleCop.ruleset", "/"]
COPY ["photo-collector-service/src/LensUp.PhotoCollectorService.Contracts/LensUp.PhotoCollectorService.Contracts.csproj", "/photo-collector-service/src/LensUp.PhotoCollectorService.Contracts/"]
COPY ["common/src/LensUp.Common.Types/LensUp.Common.Types.csproj", "/common/src/LensUp.Common.Types/"]
COPY ["gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj", "/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/"]
-
-RUN dotnet restore "gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj"
-
-COPY . /src/func-app
-
-RUN cd /src/func-app && \
-mkdir -p /home/site/wwwroot && \
-dotnet publish gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj -c Release --output /home/site/wwwroot
-
-FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0
+RUN dotnet restore "/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj"
+COPY . .
+WORKDIR "/src/."
+RUN dotnet build "./gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+FROM build AS publish
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
+
+FROM base AS final
+WORKDIR /home/site/wwwroot
+COPY --from=publish /app/publish .
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
-
-EXPOSE 8080
-EXPOSE 8086
-
-COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"]
\ No newline at end of file
diff --git a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj
index d0711d4..51439a7 100644
--- a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj
+++ b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/LensUp.GalleryService.WebhookTriggerSimulator.csproj
@@ -7,14 +7,17 @@
enable
Linux
..\..
+ false
+ false
-
-
-
-
-
+
+
+
+
+
+
diff --git a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/WebhookTriggerSimulatorFunction.cs b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/WebhookTriggerSimulatorFunction.cs
index c232e6b..c5470e0 100644
--- a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/WebhookTriggerSimulatorFunction.cs
+++ b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/WebhookTriggerSimulatorFunction.cs
@@ -2,6 +2,7 @@
using LensUp.Common.Types.Constants;
using LensUp.PhotoCollectorService.Contracts.Events;
using Microsoft.Azure.Functions.Worker;
+using Microsoft.Extensions.Configuration;
using System.Text;
using System.Text.Json;
@@ -10,13 +11,13 @@ namespace LensUp.GalleryService.WebhookTriggerSimulator;
// Workaround - simulate webhook trigger
public sealed class WebhookTriggerSimulatorFunction
{
- private const string WebhookUrl = "http://localhost:8082/Webhook";
+ private readonly string WebhookUrl = Environment.GetEnvironmentVariable(AppSettingsKeys.WebhookUrl) ?? throw new ArgumentNullException(AppSettingsKeys.WebhookUrl);
public WebhookTriggerSimulatorFunction()
{
}
[Function(nameof(WebhookTriggerSimulatorFunction))]
- public async Task Run([QueueTrigger(QueueNames.PhotoQueue, Connection = "AzureStorageConnectionString")] QueueMessage message)
+ public async Task Run([QueueTrigger(QueueNames.PhotoQueue, Connection = AppSettingsKeys.AzureWebJobsAzureStorageConnectionString)] QueueMessage message)
{
if (message?.Body == null)
@@ -37,7 +38,7 @@ public async Task Run([QueueTrigger(QueueNames.PhotoQueue, Connection = "AzureSt
using var client = new HttpClient(clientHandler);
var content = new StringContent(JsonSerializer.Serialize(@event), Encoding.UTF8, "application/json");
- await client.PostAsync(WebhookUrl, content);
+ await client.PostAsync(this.WebhookUrl, content);
}
catch (Exception exception)
{
diff --git a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/host.json b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/host.json
index ee5cf5f..0126a38 100644
--- a/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/host.json
+++ b/backend-services/gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/host.json
@@ -1,12 +1,17 @@
{
- "version": "2.0",
- "logging": {
- "applicationInsights": {
- "samplingSettings": {
- "isEnabled": true,
- "excludedTypes": "Request"
- },
- "enableLiveMetricsFilters": true
- }
+ "version": "2.0",
+ "extensions": {
+ "queues": {
+ "maxPollingInterval": "00:00:02",
}
+ },
+ "logging": {
+ "applicationInsights": {
+ "samplingSettings": {
+ "isEnabled": true,
+ "excludedTypes": "Request"
+ },
+ "enableLiveMetricsFilters": true
+ }
+ }
}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 0e2791b..34b4f21 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -31,6 +31,22 @@ services:
depends_on:
- azurite
+ lensup.photocollectorservice.ui:
+ build:
+ context: ./ui-applications
+ dockerfile: Dockerfile
+ args:
+ SERVICE: photo-collector-ui
+ image: lensup.photocollectorservice.ui
+ container_name: lensup.photocollectorservice.ui
+ ports:
+ - "5002:5002"
+ environment:
+ - NODE_ENV=dev
+ command: npm run dev
+ depends_on:
+ - lensup.photocollectorservice.api
+
lensup.galleryservice.api:
environment:
- ASPNETCORE_ENVIRONMENT=Development
@@ -51,19 +67,37 @@ services:
depends_on:
- azurite
- # lensup.galleryservice.webhooktriggersimulator:
- # environment:
- # - AzureFunctionsJobHost__Http__Port=8086
- # container_name: lensup.galleryservice.webhooktriggersimulator
- # image: lensup.galleryservice.webhooktriggersimulator
- # build:
- # context: ./backend-services
- # dockerfile: gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/Dockerfile
- # ports:
- # - "8086:8080"
- # depends_on:
- # - azurite
- # - lensup.galleryservice.api
+ lensup.galleryservice.webhooktriggersimulator:
+ environment:
+ - AzureFunctionsJobHost__Http__Port=8086
+ - AzureWebJobsAzureStorageConnectionString=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://host.docker.internal:10001/devstoreaccount1;
+ - WebhookUrl=http://host.docker.internal:8082/Webhook
+ container_name: lensup.galleryservice.webhooktriggersimulator
+ image: lensup.galleryservice.webhooktriggersimulator
+ build:
+ context: ./backend-services
+ dockerfile: gallery-service/src/LensUp.GalleryService.WebhookTriggerSimulator/Dockerfile
+ ports:
+ - "8086:8080"
+ depends_on:
+ - azurite
+ - lensup.galleryservice.api
+
+ lensup.galleryservice.ui:
+ build:
+ context: ./ui-applications
+ dockerfile: Dockerfile
+ args:
+ SERVICE: gallery-ui
+ image: lensup.galleryservice.ui
+ container_name: lensup.galleryservice.ui
+ ports:
+ - "5001:5001"
+ environment:
+ - NODE_ENV=dev
+ command: npm run dev
+ depends_on:
+ - lensup.galleryservice.api
lensup.backofficeservice.api:
environment:
diff --git a/docs/lens-up-activate-endpoint.png b/docs/lens-up-activate-endpoint.png
new file mode 100644
index 0000000..750f618
Binary files /dev/null and b/docs/lens-up-activate-endpoint.png differ
diff --git a/docs/lens-up-cert.png b/docs/lens-up-cert.png
new file mode 100644
index 0000000..5888488
Binary files /dev/null and b/docs/lens-up-cert.png differ
diff --git a/docs/lens-up-containers.png b/docs/lens-up-containers.png
new file mode 100644
index 0000000..ba2590a
Binary files /dev/null and b/docs/lens-up-containers.png differ
diff --git a/docs/lens-up-create-endpoint.png b/docs/lens-up-create-endpoint.png
new file mode 100644
index 0000000..c94620e
Binary files /dev/null and b/docs/lens-up-create-endpoint.png differ
diff --git a/docs/lens-up-docker-images.png b/docs/lens-up-docker-images.png
new file mode 100644
index 0000000..fae9378
Binary files /dev/null and b/docs/lens-up-docker-images.png differ
diff --git a/docs/lens-up-gallery-qr-code.png b/docs/lens-up-gallery-qr-code.png
new file mode 100644
index 0000000..665eae2
Binary files /dev/null and b/docs/lens-up-gallery-qr-code.png differ
diff --git a/docs/lens-up-login-form.png b/docs/lens-up-login-form.png
new file mode 100644
index 0000000..4c4eec9
Binary files /dev/null and b/docs/lens-up-login-form.png differ
diff --git a/docs/lens-up-upload-flow.gif b/docs/lens-up-upload-flow.gif
new file mode 100644
index 0000000..b0ec0fc
Binary files /dev/null and b/docs/lens-up-upload-flow.gif differ
diff --git a/docs/lens-up-upload-photo-form.png b/docs/lens-up-upload-photo-form.png
new file mode 100644
index 0000000..37c571a
Binary files /dev/null and b/docs/lens-up-upload-photo-form.png differ
diff --git a/ui-applications/Dockerfile b/ui-applications/Dockerfile
new file mode 100644
index 0000000..f093676
--- /dev/null
+++ b/ui-applications/Dockerfile
@@ -0,0 +1,13 @@
+FROM node:alpine as builder
+ARG SERVICE
+WORKDIR /usr/src/app
+
+COPY --chown=node:node package*.json lerna.json tsconfig.json ./
+COPY --chown=node:node packages/shared-components ./packages/shared-components
+COPY --chown=node:node packages/${SERVICE} ./packages/${SERVICE}
+RUN npm install --loglevel notice --unsafe-perm
+
+ENV SERVICE_NAME=${SERVICE}
+
+EXPOSE 5000
+CMD ["npm", "--prefix", "services/${SERVICE}", "start"]
\ No newline at end of file
diff --git a/ui-applications/packages/back-office-ui/Dockerfile b/ui-applications/packages/back-office-ui/Dockerfile
deleted file mode 100644
index 5f7ff80..0000000
--- a/ui-applications/packages/back-office-ui/Dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM node:alpine as build
-
-WORKDIR /app
-
-COPY package*.json ./
-
-RUN npm install
-
-COPY . .
-
-EXPOSE 5000
-
-CMD ["npm", "run", "dev"]
\ No newline at end of file
diff --git a/ui-applications/packages/gallery-ui/Dockerfile b/ui-applications/packages/gallery-ui/Dockerfile
deleted file mode 100644
index 8f08ff2..0000000
--- a/ui-applications/packages/gallery-ui/Dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM node:alpine as build
-
-WORKDIR /app
-
-COPY package*.json ./
-
-RUN npm install
-
-COPY . .
-
-EXPOSE 5001
-
-CMD ["npm", "run", "dev"]
\ No newline at end of file
diff --git a/ui-applications/packages/gallery-ui/package.json b/ui-applications/packages/gallery-ui/package.json
index 4435945..a2a99ec 100644
--- a/ui-applications/packages/gallery-ui/package.json
+++ b/ui-applications/packages/gallery-ui/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"@lens-up/shared-components": "file:../shared-components",
+ "@microsoft/signalr": "^8.0.0",
"@reduxjs/toolkit": "^2.2.3",
"framer-motion": "^11.1.7",
"localforage": "^1.10.0",
diff --git a/ui-applications/packages/gallery-ui/src/pages/Home/components/QRCodeCard.tsx b/ui-applications/packages/gallery-ui/src/pages/Home/components/QRCodeCard.tsx
index 9504c52..e3dcea5 100644
--- a/ui-applications/packages/gallery-ui/src/pages/Home/components/QRCodeCard.tsx
+++ b/ui-applications/packages/gallery-ui/src/pages/Home/components/QRCodeCard.tsx
@@ -1,3 +1,5 @@
+import { memo } from "react"
+
interface IQRCodeCardProps {
qRCodeUrl: string
hasPhotos?: boolean
@@ -14,4 +16,4 @@ const QRCodeCard = ({ qRCodeUrl, hasPhotos }: IQRCodeCardProps) => {
)
}
-export default QRCodeCard
\ No newline at end of file
+export default memo(QRCodeCard)
\ No newline at end of file
diff --git a/ui-applications/packages/photo-collector-ui/Dockerfile b/ui-applications/packages/photo-collector-ui/Dockerfile
deleted file mode 100644
index cf9a8bb..0000000
--- a/ui-applications/packages/photo-collector-ui/Dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM node:alpine as build
-
-WORKDIR /app
-
-COPY package*.json ./
-
-RUN npm install
-
-COPY . .
-
-EXPOSE 5002
-
-CMD ["npm", "run", "dev"]
\ No newline at end of file
diff --git a/ui-applications/packages/shared-components/src/images/lens-up-logo.png b/ui-applications/packages/shared-components/src/images/lens-up-logo.png
index 5f95c58..4943998 100644
Binary files a/ui-applications/packages/shared-components/src/images/lens-up-logo.png and b/ui-applications/packages/shared-components/src/images/lens-up-logo.png differ