[web] Complete integration of payments code (#1233)

Next step - deploy from here.
This commit is contained in:
Manav Rathi 2024-03-28 17:48:05 +05:30 committed by GitHub
commit e4ce144bd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 139 additions and 163 deletions

View file

@ -0,0 +1,43 @@
name: "Deploy (payments)"
on:
push:
# Run workflow on pushes to the deploy/payments
branches: [deploy/payments]
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: web
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: "yarn"
cache-dependency-path: "docs/yarn.lock"
- name: Install dependencies
run: yarn install
- name: Build payments
run: yarn build:payments
- name: Publish payments
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: deploy/payments
directory: web/apps/payments/out
wranglerVersion: "3"

View file

@ -78,6 +78,19 @@ jobs:
directory: web/apps/cast/out
wranglerVersion: "3"
- name: Build payments
run: yarn build:payments
- name: Publish payments
uses: cloudflare/pages-action@1
with:
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
projectName: ente
branch: n-payments
directory: web/apps/payments/out
wranglerVersion: "3"
- name: Build photos
run: yarn build:photos
env:

View file

@ -12,6 +12,7 @@ on:
- "accounts"
- "auth"
- "cast"
- "payments"
- "photos"
jobs:

View file

@ -17,6 +17,7 @@ services:
- custom-logs:/var/logs
- ./museum.yaml:/museum.yaml:ro
- ./scripts/compose/credentials.yaml:/credentials.yaml:ro
- ./data:/data:ro
networks:
- internal

View file

@ -3,28 +3,55 @@ Stripe's API for payments.
## Development
If you're running this to test out the payment flows end-to-end, please do a
`yarn build`, that will place the output within the `out` folder.
There are three pieces that need to be connected to have a working local setup:
Then use any tool to serve this over HTTP. For example, `python3 -m http.server
3001` will serve this directory over port `3001`.
- A client app
- This web app
- Museum
Aside that, these are the necessary configuration changes.
### Client app
### Local configuration
For the client, let us consider the Photos web app (similar configuration can be
done in the mobile client too).
Create an `.env` in this directory to point to the local museum instance, and to
define the necessary Stripe keys that can be fetched from [Stripe's developer
Add the following to `web/apps/photos/.env.local`:
```env
NEXT_PUBLIC_ENTE_ENDPOINT = http://localhost:8080
NEXT_PUBLIC_ENTE_PAYMENTS_ENDPOINT = http://localhost:3001
```
Then start it locally
```sh
yarn dev:photos
```
This tells it to connect to the museum and payments app running on localhost.
> For connecting from the mobile app, you'll need to run museum on a local IP
> instead localhost. If so, just replace "http://localhost:8080" with (say)
> "http://192.168.1.2:8080" wherever mentioned.
### Payments app
For this (payments) web app, configure it to connect to the local museum, and
use a set of (development) Stripe keys which can be found in [Stripe's developer
dashboard](https://dashboard.stripe.com).
Assuming that your local museum instance is running on `192.168.1.2:8080`, your
`.env` should look as follows.
Add the following to
`web/apps/payments/.env.local`
```
NEXT_PUBLIC_ENTE_ENDPOINT = http://192.168.1.2:8080
```env
NEXT_PUBLIC_ENTE_ENDPOINT = http://localhost:8080
NEXT_PUBLIC_STRIPE_US_PUBLISHABLE_KEY = stripe_publishable_key
```
Then start it locally
```sh
yarn dev:payments
```
### Museum
1. Install the [stripe-cli](https://docs.stripe.com/stripe-cli) and capture the
@ -33,18 +60,32 @@ NEXT_PUBLIC_STRIPE_US_PUBLISHABLE_KEY = stripe_publishable_key
2. Define this secret within your `musuem.yaml`
3. Update the `whitelisted-redirect-urls` so that it supports redirecting to
this locally running project.
the locally running payments app.
Assuming that your local payments app is running on `192.168.1.2:3001`, your
`museum.yaml` should look as follows.
Assuming that your local payments app is running on `localhost:3001`, your
`server/museum.yaml` should look as follows.
```yaml
stripe:
us:
key: stripe_dev_key
webhook-secret: stripe_dev_webhook_secret
whitelisted-redirect-urls: ["http://192.168.1.2:3001/frameRedirect"]
whitelisted-redirect-urls: ["http://localhost:3000/gallery", "http://192.168.1.2:3001/frameRedirect"]
path:
success: ?status=success&session_id={CHECKOUT_SESSION_ID}
cancel: ?status=fail&reason=canceled
```
Make sure you have test plans available for museum to use, by placing them in
(say) `server/data/billing/us-testing.json`.
Finally, start museum, for example:
```
docker compose up
```
Now if you try to purchase a plan from your locally running photos web client,
it should redirect to the locally running payments app, and from there to
Stripe. Once the test purchase completes it should redirect back to the local
web client.

View file

@ -1,96 +0,0 @@
-------------------------------
UBUNTU FONT LICENCE Version 1.0
-------------------------------
PREAMBLE
This licence allows the licensed fonts to be used, studied, modified and
redistributed freely. The fonts, including any derivative works, can be
bundled, embedded, and redistributed provided the terms of this licence
are met. The fonts and derivatives, however, cannot be released under
any other licence. The requirement for fonts to remain under this
licence does not require any document created using the fonts or their
derivatives to be published under this licence, as long as the primary
purpose of the document is not to be a vehicle for the distribution of
the fonts.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this licence and clearly marked as such. This may
include source files, build scripts and documentation.
"Original Version" refers to the collection of Font Software components
as received under this licence.
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to
a new environment.
"Copyright Holder(s)" refers to all individuals and companies who have a
copyright ownership of the Font Software.
"Substantially Changed" refers to Modified Versions which can be easily
identified as dissimilar to the Font Software by users of the Font
Software comparing the Original Version with the Modified Version.
To "Propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification and with or without charging
a redistribution fee), making available to the public, and in some
countries other activities as well.
PERMISSION & CONDITIONS
This licence does not grant any rights under trademark law and all such
rights are reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to propagate the Font Software, subject to
the below conditions:
1) Each copy of the Font Software must contain the above copyright
notice and this licence. These can be included either as stand-alone
text files, human-readable headers or in the appropriate machine-
readable metadata fields within text or binary files as long as those
fields can be easily viewed by the user.
2) The font name complies with the following:
(a) The Original Version must retain its name, unmodified.
(b) Modified Versions which are Substantially Changed must be renamed to
avoid use of the name of the Original Version or similar names entirely.
(c) Modified Versions which are not Substantially Changed must be
renamed to both (i) retain the name of the Original Version and (ii) add
additional naming elements to distinguish the Modified Version from the
Original Version. The name of such Modified Versions must be the name of
the Original Version, with "derivative X" where X represents the name of
the new work, appended to that name.
3) The name(s) of the Copyright Holder(s) and any contributor to the
Font Software shall not be used to promote, endorse or advertise any
Modified Version, except (i) as required by this licence, (ii) to
acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
their explicit written permission.
4) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this licence, and must not be distributed
under any other licence. The requirement for fonts to remain under this
licence does not affect any document created using the Font Software,
except any version of the Font Software extracted from a document
created using the Font Software may only be distributed under this
licence.
TERMINATION
This licence becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.

View file

@ -1,10 +1,10 @@
import * as React from "react";
import { Spinner } from "react-bootstrap";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export default function EnteSpinner(props: any) {
export const EnteSpinner: React.FC = () => {
return (
<Spinner {...props} animation="border" variant="success" role="status">
<Spinner animation="border" variant="success" role="status">
<span className="sr-only">Loading...</span>
</Spinner>
);
}
};

View file

@ -1,5 +1,5 @@
import { Container } from "components/Container";
import constants from "utils/strings/constants";
import constants from "utils/strings";
export default function Home() {
return <Container>{constants.NOT_FOUND}</Container>;

View file

@ -1,7 +1,7 @@
import "bootstrap/dist/css/bootstrap.min.css";
import type { AppProps } from "next/app";
import Head from "next/head";
import constants from "utils/strings/constants";
import constants from "utils/strings";
import "../styles/globals.css";
function MyApp({ Component, pageProps }: AppProps) {
@ -14,4 +14,5 @@ function MyApp({ Component, pageProps }: AppProps) {
</>
);
}
export default MyApp;

View file

@ -1,5 +1,5 @@
import { Container } from "components/Container";
import EnteSpinner from "components/EnteSpinner";
import { EnteSpinner } from "components/EnteSpinner";
import * as React from "react";
export default function DesktopRedirect() {
@ -12,7 +12,7 @@ export default function DesktopRedirect() {
return (
<Container>
<EnteSpinner animation="border" />
<EnteSpinner />
</Container>
);
}

View file

@ -1,13 +1,14 @@
import { Container } from "components/Container";
import EnteSpinner from "components/EnteSpinner";
import { EnteSpinner } from "components/EnteSpinner";
import * as React from "react";
import { parseAndHandleRequest } from "services/billingService";
import { CUSTOM_ERROR } from "utils/error";
import constants from "utils/strings/constants";
import constants from "utils/strings";
export default function Home() {
const [errorMessageView, setErrorMessageView] = React.useState(false);
const [loading, setLoading] = React.useState(false);
React.useEffect(() => {
async function main() {
try {
@ -34,7 +35,7 @@ export default function Home() {
{errorMessageView ? (
<div>{constants.SOMETHING_WENT_WRONG}</div>
) : (
loading && <EnteSpinner animation="border" />
loading && <EnteSpinner />
)}
</Container>
);

View file

@ -8,7 +8,7 @@
import { loadStripe } from "@stripe/stripe-js";
import { CUSTOM_ERROR } from "utils/error";
import { logError } from "utils/sentry";
import { logError } from "utils/log";
import HTTPService from "./HTTPService";
const getStripePublishableKey = (stripeAccount: StripeAccountCountry) => {

View file

@ -1,39 +1,16 @@
/* ubuntu-regular - latin */
@font-face {
font-family: "Ubuntu";
font-style: normal;
font-weight: 400;
src:
local(""),
url("/fonts/ubuntu-v15-latin-regular.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("/fonts/ubuntu-v15-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* ubuntu-700 - latin */
@font-face {
font-family: "Ubuntu";
font-style: normal;
font-weight: 700;
src:
local(""),
url("/fonts/ubuntu-v15-latin-700.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("/fonts/ubuntu-v15-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
html,
body {
padding: 0;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
font-family: system-ui, sans-serif;
height: 100%;
flex: 1;
display: flex;
flex-direction: column;
background-color: #191919 !important;
color: #aaa !important;
font-family: Ubuntu, Arial, sans-serif !important;
}
:is(h1, h2, h3, h4, h5, h6) {
color: #d7d7d7;
}
@ -43,11 +20,3 @@ body {
display: flex;
flex-direction: column;
}
.ente-container {
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
align-items: center;
}

View file

@ -1,3 +0,0 @@
export function runningInBrowser() {
return typeof window !== "undefined";
}

View file

@ -3,4 +3,5 @@ const englishConstants = {
SOMETHING_WENT_WRONG: "Oops, something went wrong.",
NOT_FOUND: "404 | This page could not be found.",
};
export default englishConstants;

View file

@ -486,7 +486,9 @@ export default function App(props: EnteAppProps) {
<EnteSpinner />
</Overlay>
)}
<Component setLoading={setLoading} {...pageProps} />
{isI18nReady && (
<Component setLoading={setLoading} {...pageProps} />
)}
</AppContext.Provider>
</ThemeProvider>
</CacheProvider>

View file

@ -36,10 +36,12 @@ deployments, and the action that triggers them:
| [auth.ente.io](https://auth.ente.io) | Production | Push to `deploy/auth` |
| [accounts.ente.io](https://accounts.ente.io) | Production | Push to `deploy/accounts` |
| [cast.ente.io](https://cast.ente.io) | Production | Push to `deploy/cast` |
| [payments.ente.io](https://payments.ente.io) | Production | Push to `deploy/payments` |
| [help.ente.io](https://help.ente.io) | Production | Push to `main` + changes in `docs/` |
| [accounts.ente.sh](https://accounts.ente.sh) | Preview | Nightly deploy of `main` |
| [auth.ente.sh](https://auth.ente.sh) | Preview | Nightly deploy of `main` |
| [cast.ente.sh](https://cast.ente.sh) | Preview | Nightly deploy of `main` |
| [payments.ente.sh](https://payments.ente.sh) | Preview | Nightly deploy of `main` |
| [photos.ente.sh](https://photos.ente.sh) | Preview | Nightly deploy of `main` |
| [preview.ente.sh](https://preview.ente.sh) | Preview | Manually triggered |
@ -52,8 +54,8 @@ Apart from this, there are also some other deployments:
`albums.ente.io`, it redirects to the `/shared-albums` page (Enhancement:
serve it as a separate app with a smaller bundle size).
- `payments.ente.io` and `family.ente.io` are currently in a separate
repositories (Enhancement: bring them in here).
- `family.ente.io` is currently in a separate repositories (Enhancement: bring
them in here).
### Preview deployments