Allow clients to create manalinks

This commit is contained in:
Austin Chen 2022-05-04 11:44:24 -04:00
parent 2b37c2dd14
commit 12aceef4ca
6 changed files with 91 additions and 5 deletions

View File

@ -1,6 +1,6 @@
export type Manalink = { export type Manalink = {
// The link to send: https://manifold.markets/send/{slug} // The link to send: https://manifold.markets/send/{slug}
// Also functions as the unique identifier for the link. // Also functions as the unique id for the link.
slug: string slug: string
// Note: we assume both fromId and toId are of SourceType 'USER' // Note: we assume both fromId and toId are of SourceType 'USER'
@ -11,10 +11,10 @@ export type Manalink = {
token: 'M$' // TODO: could send eg YES shares too?? token: 'M$' // TODO: could send eg YES shares too??
createdTime: number createdTime: number
// If not set, the link is valid forever // If set to Infinity, the link is valid forever
expiresTime?: number expiresTime: number
// If not set, the link can be used infinitely // If set to Infinity, the link can be used infinitely
maxUses?: number maxUses: number
// Successful redemptions of the link // Successful redemptions of the link
successes: Claim[] successes: Claim[]

View File

@ -85,5 +85,10 @@ service cloud.firestore {
match /txns/{txnId} { match /txns/{txnId} {
allow read; allow read;
} }
match /manalinks/{slug} {
allow read;
allow create, update: if request.auth.uid == request.resource.data.fromId;
}
} }
} }

View File

@ -0,0 +1,40 @@
import { setDoc } from 'firebase/firestore'
import { doc } from 'firebase/firestore'
import { Manalink } from '../../../common/manalink'
import { db } from './init'
import { customAlphabet } from 'nanoid'
export async function createManalink(data: {
fromId: string
amount: number
expiresTime: number
maxUses: number
}) {
const { fromId, amount, expiresTime, maxUses } = data
// At 100 IDs per hour, using this alphabet and 8 chars, there's a 1% chance of collision in 2 years
// See https://zelark.github.io/nano-id-cc/
const nanoid = customAlphabet(
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
8
)
const slug = nanoid()
if (amount <= 0 || isNaN(amount) || !isFinite(amount))
return { status: 'error', message: 'Invalid amount' }
const manalink: Manalink = {
slug,
fromId,
amount,
token: 'M$',
createdTime: Date.now(),
expiresTime,
maxUses,
successes: [],
failures: [],
}
const ref = doc(db, 'manalinks', slug)
await setDoc(ref, manalink)
}

View File

@ -29,6 +29,7 @@
"gridjs": "5.0.2", "gridjs": "5.0.2",
"gridjs-react": "5.0.2", "gridjs-react": "5.0.2",
"lodash": "4.17.21", "lodash": "4.17.21",
"nanoid": "^3.3.4",
"next": "12.1.2", "next": "12.1.2",
"react": "17.0.2", "react": "17.0.2",
"react-confetti": "^6.0.1", "react-confetti": "^6.0.1",

35
web/pages/send.tsx Normal file
View File

@ -0,0 +1,35 @@
import { Page } from '../components/page'
import { SEO } from '../components/SEO'
import { useUser } from '../hooks/use-user'
import { createManalink } from '../lib/firebase/manalinks'
export default function SendPage() {
const user = useUser()
return (
<Page>
<SEO
title="Send Mana"
description="Send mana to anyone via link!"
url="/send"
/>
<h1>Send Mana</h1>
{user && (
<button
className="btn"
onClick={async () => {
await createManalink({
fromId: user.id,
amount: 1234,
expiresTime: Date.now() + 1000 * 60 * 60 * 24 * 7,
maxUses: Infinity,
})
}}
>
Create a new Manalink
</button>
)}
</Page>
)
}

View File

@ -3793,6 +3793,11 @@ nanoid@^3.1.30:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557"
integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
natural-compare@^1.4.0: natural-compare@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"