Skip to content

Commit

Permalink
Merge pull request #323 from WelcometoMyGarden/feat/membership
Browse files Browse the repository at this point in the history
Adds memberships
  • Loading branch information
th0rgall authored Jun 15, 2023
2 parents b129c20 + 8153bf0 commit 9ce9f92
Show file tree
Hide file tree
Showing 104 changed files with 3,401 additions and 1,703 deletions.
31 changes: 31 additions & 0 deletions .github/actions/prepare-source/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Prepare WTMG source
description: Prepare the WTMG source code for building
inputs:
credentials_json:
description: 'GCP Service Account JSON Credentials'
required: true
runs:
using: composite
steps:
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Install Dependencies
# https://github.com/actions/setup-node/blob/main/docs/advanced-usage.md#caching-packages-data
# https://yarnpkg.com/cli/install
# --frozen-lockfile is deprecated
run: yarn install --immutable
shell: bash
- id: auth
uses: google-github-actions/auth@v1
with:
credentials_json: '${{ inputs.credentials_json }}'
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v1
with:
version: '>= 363.0.0'
project_id: 'wtmg-production'
- name: Use gcloud CLI
run: gsutil -m cp -r gs://wtmg-static/assets ${{ github.workspace }}/src/lib
shell: bash
8 changes: 3 additions & 5 deletions .github/workflows/firebase-hosting-merge-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ jobs:
VITE_STRIPE_PRICE_ID_SOLIDARITY: ${{secrets.STRIPE_PRICE_ID_SOLIDARITY}}
VITE_DISCOURSE_HOST: ${{vars.DISCOURSE_HOST}}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
- uses: actions/checkout@v3
- uses: ./.github/actions/prepare-source
with:
node-version: 16
- name: Install Dependencies
run: yarn
credentials_json: ${{secrets.GCP_CREDENTIALS}}
- name: Build project
run: yarn run build:prod
- uses: FirebaseExtended/action-hosting-deploy@v0
Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/firebase-hosting-merge-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ jobs:
VITE_STRIPE_PRICE_ID_SOLIDARITY: ${{secrets.STRIPE_PRICE_ID_SOLIDARITY}}
VITE_DISCOURSE_HOST: ${{vars.DISCOURSE_HOST}}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
- uses: actions/checkout@v3
- uses: ./.github/actions/prepare-source
with:
node-version: 16
- name: Install Dependencies
run: yarn
credentials_json: ${{secrets.GCP_CREDENTIALS}}
- name: Build project
run: yarn run build:staging
- uses: FirebaseExtended/action-hosting-deploy@v0
Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/firebase-hosting-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ jobs:
VITE_STRIPE_PRICE_ID_SOLIDARITY: ${{secrets.STRIPE_PRICE_ID_SOLIDARITY}}
VITE_DISCOURSE_HOST: ${{vars.DISCOURSE_HOST}}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
- uses: actions/checkout@v3
- uses: ./.github/actions/prepare-source
with:
node-version: 16
- name: Install Dependencies
run: yarn
credentials_json: ${{secrets.GCP_CREDENTIALS}}
- name: Build project
run: yarn run build:prod
- uses: FirebaseExtended/action-hosting-deploy@v0
Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/firebase-hosting-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ jobs:
VITE_STRIPE_PRICE_ID_SOLIDARITY: ${{secrets.STRIPE_PRICE_ID_SOLIDARITY}}
VITE_DISCOURSE_HOST: ${{vars.DISCOURSE_HOST}}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
- uses: actions/checkout@v3
- uses: ./.github/actions/prepare-source
with:
node-version: 16
- name: Install Dependencies
run: yarn
credentials_json: ${{secrets.GCP_CREDENTIALS}}
- name: Build project
run: yarn run build:staging
- uses: FirebaseExtended/action-hosting-deploy@v0
Expand Down
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Large source assets to be processed by svelte-img
# See the readme or docs/full-access.md for more info
src/lib/assets

# Logs
logs
*.log
Expand Down Expand Up @@ -36,8 +40,6 @@ firestore-coverage.html

.DS_Store



# Build & cache files

dist
Expand Down
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"label": "Local Development",
"dependsOn": [
"copy-demo-env",
"npm: firebase:demo",
"npm: firebase:demo-seed",
"npm: dev"
],
"group": {
Expand Down Expand Up @@ -89,4 +89,4 @@
"detail": "firebase --project demo-test emulators:exec api/seeders/simple.js"
}
]
}
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ Some features are reserved for [Superfans](https://welcometomygarden.org/about-s

### What can you NOT immediately do?

- Some static images will be missing. We started dynamically generating responsive images on build-time for some newer components, rather than using one-size static images hosted in a bucket. The source images for this process should be put in `src/lib/assets`, but are not checked into the Git repo. You can download this [Google Drive](https://drive.google.com/drive/folders/1OcaKJa9VoykflvKNv6nH13O0Ho_PcApF?usp=sharing) and manually drop the contents in the mentioned local folder. See the [additional notes](./docs/full-access.md) if you have full access to WTMG's systems to learn about syncing this folder.
- Preview the email HTML, and test contact property syncing functionality - except if you create your own SendGrid account. It's a quick procedure to set up your own free account for testing.
- Work on subscription features - except if you go through the hassle of setting up your own test company on Stripe!
- Log into the Discourse community reserved for superfans - except if you set up your own Discourse server for testing, see [additional Discourse notes](./docs/discourse.md)
- Log into the Discourse community reserved for Superfans - except if you set up your own Discourse server for testing, see [additional Discourse notes](./docs/discourse.md)

If you have received access to our staging or production Firebase environment, see how to log in your Firebase account & access real API services with [these additional notes](./docs/full-access.md).

Expand Down
2 changes: 1 addition & 1 deletion api/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ admin-credentials.json
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!.yarn/versions
79 changes: 59 additions & 20 deletions api/seeders/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ const db = admin.firestore(app);
const auth = admin.auth(app);

/**
* @param {import('firebase-admin/auth').CreateRequest} authProps
* @param {import('../../src/lib/api/functions').CreateUserRequest & {superfan?: true}} callableProps
* @param {import('firebase-admin/auth').CreateRequest} authProps - passed to auth.createUser
* @param {import('../../src/lib/api/functions').CreateUserRequest & {superfan?: true}} callableProps - replicating what is passed to the createUser callable
*/
const createNewUser = async (authProps, callableProps) => {
const user = await auth.createUser({
Expand Down Expand Up @@ -55,6 +55,14 @@ const createNewUser = async (authProps, callableProps) => {
return user;
};

/**
* @param {string} uid
* @param {import('../../src/lib/types/Garden').Garden} data
*/
const createGarden = async (uid, data) => {
await db.collection('campsites').doc(uid).set(data);
};

/**
* Based on src/lib/api/chat.ts -> create
* @param {string} uid1
Expand Down Expand Up @@ -122,19 +130,57 @@ const sendMessage = async (currentUserId, chatId, message, useLastMessageSeen =
};

const seed = async () => {
// Seed two users
const user1 = await createNewUser(
{ email: '[email protected]' },
{ firstName: 'Bob', lastName: 'Dylan', countryCode: 'US' }
);

const user2 = await createNewUser(
{ email: '[email protected]' },
{ firstName: 'Urbain', lastName: 'Servranckx', countryCode: 'BE', superfan: true }
);
// Create users
const [user1, user2, user3] = await Promise.all([
// First user: non-superfan, has a garden
createNewUser(
{ email: '[email protected]' },
{ firstName: 'Bob', lastName: 'Dylan', countryCode: 'US' }
).then(async (user1Inner) => {
await createGarden(user1Inner.uid, {
description: 'Hello, this is a test camping spot. You are welcome to stay!',
location: {
latitude: 50.952798579681854,
longitude: 4.763172541851901
},
facilities: {
capacity: 2,
toilets: true,
shower: false,
electricity: true,
water: false,
drinkableWater: true,
bonfire: true,
tent: true
},
photo: null,
listed: true
});
return user1Inner;
}),
// Second user: superfan, no garden
createNewUser(
{ email: '[email protected]' },
{ firstName: 'Urbain', lastName: 'Servranckx', countryCode: 'BE', superfan: true }
),
// Third user: no superfan, no garden, has past chats
createNewUser(
{
email: '[email protected]'
},
{ firstName: 'Maria Louise', lastName: 'from Austria', countryCode: 'AT' }
),
// Fourth user: a non-superfan user without garden and without messages sent yet
createNewUser(
{
email: '[email protected]'
},
{ firstName: 'Laura', lastName: 'Verheyden', countryCode: 'BE' }
)
]);

// Send chats
// TODO messages are sent without gardens being created, this is not realistic
// TODO messages are sent to user 2 without that account having a garden, this is not realistic
// initiated by 1 to 2
const chatId = await createChat(user1.uid, user2.uid, 'Hey, can I stay in your garden?', false);
for (let i = 0; i < 10; i += 1) {
Expand All @@ -143,13 +189,6 @@ const seed = async () => {
await sendMessage((even ? user2 : user1).uid, chatId, faker.lorem.sentences(), false);
}

const user3 = await createNewUser(
{
email: '[email protected]'
},
{ firstName: 'Maria Louise', lastName: 'from Austria', countryCode: 'AT' }
);

// from 3 to 1
await createChat(user3.uid, user1.uid, 'I have a question');
};
Expand Down
31 changes: 31 additions & 0 deletions docs/full-access.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,40 @@ For the backend, your `.runtimeconfig.json` will need:

## Static image assets

**Google Cloud bucket assets**

Some of our static assets live in a simple Google Cloud bucket.

In the bucket file management API, it's possible to drag & drop in a second version of a file onto an existing one (e.g. with a rescaled resolution), and specify to "replace" it in the dialog that appears. However:

- this will not actually create a second version in the bucket's object versioning history, for that the API probably needs to be used.
- the authenticated URL will update quickly, but the public URL (which we use for the static site) will be plagued **by inexplicable old cached versions that randomly appear** for some time (1 day?), see [this StackOverflow comment too](https://stackoverflow.com/a/37671993/4973029), regardless of cache headers. Probably due to intermediary caches.

**Dynamically generated responsive SvelteKit assets**

For some newer components, we started dynamically generating responsive images on build-time, rather than using one-size static images hosted in a bucket, using [svelte-img](https://github.com/zerodevx/svelte-img).

The source images for this process should be put in `src/lib/assets`, but are not checked into the Git repo.

We keep them in a Google Cloud bucket (and maybe in [Google Drive](https://drive.google.com/drive/folders/1OcaKJa9VoykflvKNv6nH13O0Ho_PcApF?usp=sharing)).

It's possible to sync your local version with the Google Drive, in both ways, with several tools. Here are some guidelines for [rclone](https://rclone.org/drive/):

Uploading local files:

```
rclone copy --exclude="**.DS_Store" src/lib/assets gcloud:wtmg-static/assets
```

```
rclone copy --exclude="**.DS_Store" src/lib/assets slowby-gdrive:Development/assets
```

`bisync` can be used to both download and upload.

This assumes:

- `gcloud` is configured as a Google Cloud Storage remote. Check with the team to copy configuration.
- `slowby-gdrive` is configured as a Google Drive remote, and that "Development" is a shortcut to the Development folder in our team drive. Check with the team to receive a client ID & secret you can use for the configuration.

In the future, we should maybe consider blowing up our repository size to 10s to 100s of megabytes anyway, to get the benefits of version control for source images, and to not have to deal with an external storage system like now. See [this discussion](https://softwareengineering.stackexchange.com/questions/80962/should-images-be-stored-in-a-git-repository).
5 changes: 4 additions & 1 deletion firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,12 @@ service cloud.firestore {
allow write: if false;
}

// Allow reading superfan stats on our public pages
// Allow reading superfan & campsite stats on our public pages
match /stats/superfans {
allow read: if true;
}
match /stats/campsites {
allow read: if true;
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@types/smoothscroll-polyfill": "^0.3.1",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"@zerodevx/svelte-img": "^1.2.10",
"dotenv": "^16.0.3",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.3.0",
Expand Down
7 changes: 7 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ declare interface Window {
*/
plausible: Plausible;
}

// https://github.com/zerodevx/svelte-img#install
// Squelch warnings of image imports from your assets dir
declare module '$lib/assets/*' {
const meta: Object[];
export default meta;
}
5 changes: 5 additions & 0 deletions src/lib/api/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ export const getSuperfanCount = async () => {
return (await getDoc(doc(db(), STATS, 'superfans') as DocumentReference<CountStat>)).data()
?.count;
};

export const getGardenCount = async () => {
return (await getDoc(doc(db(), STATS, 'campsites') as DocumentReference<CountStat>)).data()
?.count;
};
2 changes: 1 addition & 1 deletion src/lib/components/Footer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
},
{
title: $_('footer.links.superfans'),
link: routes.ABOUT_SUPERFAN
link: routes.ABOUT_MEMBERSHIP
},
{
title: $_('footer.links.donate'),
Expand Down
18 changes: 11 additions & 7 deletions src/lib/components/Garden/FacilitiesFilter.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
</div>
<div class="gardenFilterCapacityModifier">
<p>{$_('garden.filter.min')}</p>
<button on:click={capacityMinReduce}>-</button>
<button on:click={capacityMinReduce}><span>&minus;</span></button>
<input
type="number"
class="capacity-input"
Expand All @@ -109,7 +109,7 @@
max="20"
bind:value={filter.capacity.min}
/>
<button on:click={capacityMinIncrease}>+</button>
<button on:click={capacityMinIncrease}><span>&plus;</span></button>
</div>
</div>
</div>
Expand Down Expand Up @@ -181,21 +181,25 @@
}
.gardenFilterCapacityModifier > button {
margin: 2px 1rem 0 1rem;
margin: 1px 1rem 0 1rem;
padding: 0;
border: 1.5px solid var(--color-green);
border-radius: 50%;
background-color: var(--color-white);
cursor: pointer;
height: 2rem;
width: 2rem;
width: 2.1rem;
height: 2.1rem;
display: flex;
justify-content: center;
align-items: center;
}
.gardenFilterCapacityModifier > button span {
/* padding-top: 1.5px; */
font-family: 'Courier', monospace;
font-weight: bold;
}
.gardenFilterCapacityModifier > button:hover {
background-color: var(--color-green);
color: var(--color-white);
Expand Down
Loading

0 comments on commit 9ce9f92

Please sign in to comment.