create reserved usernames

This commit is contained in:
keyan 2021-05-21 19:09:11 -05:00
parent 4f627e2a5c
commit a9ea341a7b
8 changed files with 671 additions and 28 deletions

View File

@ -1,4 +1,4 @@
import { AuthenticationError } from 'apollo-server-errors'
import { AuthenticationError, UserInputError } from 'apollo-server-errors'
export default {
Query: {
@ -18,6 +18,23 @@ export default {
}
},
Mutation: {
setName: async (parent, { name }, { me, models }) => {
if (!me) {
throw new AuthenticationError('you must be logged in')
}
try {
await models.user.update({ where: { name: me.name }, data: { name } })
} catch (error) {
if (error.code === 'P2002') {
throw new UserInputError('name taken')
}
throw error
}
}
},
User: {
nitems: async (user, args, { models }) => {
return await models.item.count({ where: { userId: user.id, parentId: null } })

View File

@ -8,6 +8,10 @@ export default gql`
nameAvailable(name: String!): Boolean!
}
extend type Mutation {
setName(name: String!): Boolean
}
type User {
id: ID!
name: String

View File

@ -84,7 +84,7 @@ export function Input ({ label, prepend, append, hint, showValid, noBottomMargin
}
export function Form ({
initial, schema, onSubmit, children, initialError, ...props
initial, schema, onSubmit, children, initialError, validateOnBlur, ...props
}) {
const [error, setError] = useState(initialError)
@ -92,7 +92,7 @@ export function Form ({
<Formik
initialValues={initial}
validationSchema={schema}
validateOnBlur={false}
validateOnBlur={validateOnBlur}
onSubmit={async (...args) =>
onSubmit && onSubmit(...args).catch(e => setError(e.message || e))}
>

View File

@ -7,7 +7,7 @@ import { useState } from 'react'
import { Form, Input, SubmitButton } from './form'
import InputGroup from 'react-bootstrap/InputGroup'
import * as Yup from 'yup'
import { gql, useApolloClient, useQuery } from '@apollo/client'
import { gql, useApolloClient, useMutation } from '@apollo/client'
const NAME_QUERY =
gql`
@ -16,11 +16,19 @@ gql`
}
`
const NAME_MUTATION =
gql`
mutation setName($name: String!) {
setName(name: $name)
}
`
export default function UserHeader ({ user }) {
const [editting, setEditting] = useState(false)
const [session] = useSession()
const router = useRouter()
const client = useApolloClient()
const [setName] = useMutation(NAME_MUTATION)
const Satistics = () => <h1 className='ml-2'><small className='text-success'>[{user.stacked} stacked, {user.sats} sats]</small></h1>
@ -50,6 +58,17 @@ export default function UserHeader ({ user }) {
initial={{
name: user.name
}}
onSubmit={async ({ name }) => {
if (name === user.name) {
setEditting(false)
return
}
const { error } = await setName({ variables: { name } })
if (error) {
throw new Error({ message: error.toString() })
}
window.location = `/${name}`
}}
>
<Input
prepend=<InputGroup.Text>@</InputGroup.Text>

View File

@ -1,22 +0,0 @@
import { gql, useMutation, useQuery } from '@apollo/client'
import { Button } from 'react-bootstrap'
import Layout from '../components/layout'
export default function Index () {
const [createAccount] = useMutation(gql`
mutation {
createAccount
}`)
const { data } = useQuery(gql`
{
accounts
}`)
return (
<Layout>
<Button onClick={createAccount}>create account</Button>
{data && data.accounts.map(account =>
<div key={account}>account</div>
)}
</Layout>
)
}

View File

@ -2,7 +2,7 @@
CREATE TABLE "users" (
"id" SERIAL NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" TEXT,
"email" TEXT,
"email_verified" TIMESTAMP(3),

View File

@ -0,0 +1,625 @@
/*
Warnings:
- Made the column `name` on table `users` required. This step will fail if there are existing NULL values in that column.
*/
-- AlterTable
ALTER TABLE "users" ALTER COLUMN "name" SET NOT NULL;
INSERT INTO "users" ("name") VALUES
('0'),
('about'),
('access'),
('account'),
('accounts'),
('activate'),
('activities'),
('activity'),
('ad'),
('add'),
('address'),
('adm'),
('admin'),
('administration'),
('administrator'),
('ads'),
('adult'),
('advertising'),
('affiliate'),
('affiliates'),
('ajax'),
('all'),
('alpha'),
('analysis'),
('analytics'),
('android'),
('anon'),
('anonymous'),
('api'),
('app'),
('apps'),
('archive'),
('archives'),
('article'),
('asct'),
('asset'),
('atom'),
('auth'),
('authentication'),
('avatar'),
('backup'),
('balancer-manager'),
('banner'),
('banners'),
('beta'),
('billing'),
('bin'),
('bitcoin'),
('blog'),
('blogs'),
('board'),
('book'),
('bookmark'),
('bot'),
('bots'),
('bug'),
('business'),
('cache'),
('cadastro'),
('calendar'),
('call'),
('campaign'),
('cancel'),
('captcha'),
('career'),
('careers'),
('cart'),
('categories'),
('category'),
('cgi'),
('cgi-bin'),
('changelog'),
('chat'),
('check'),
('checking'),
('checkout'),
('client'),
('cliente'),
('clients'),
('code'),
('codereview'),
('comercial'),
('comment'),
('comments'),
('communities'),
('community'),
('company'),
('compare'),
('compras'),
('config'),
('configuration'),
('connect'),
('contact'),
('contact-us'),
('contact_us'),
('contactus'),
('contest'),
('contribute'),
('corp'),
('create'),
('css'),
('dashboard'),
('data'),
('db'),
('default'),
('delete'),
('demo'),
('design'),
('designer'),
('destroy'),
('dev'),
('devel'),
('developer'),
('developers'),
('diagram'),
('diary'),
('dict'),
('dictionary'),
('die'),
('dir'),
('direct_messages'),
('directory'),
('dist'),
('doc'),
('docs'),
('documentation'),
('domain'),
('download'),
('downloads'),
('ecommerce'),
('edit'),
('editor'),
('edu'),
('education'),
('email'),
('employment'),
('empty'),
('end'),
('enterprise'),
('entries'),
('entry'),
('error'),
('errors'),
('eval'),
('event'),
('exit'),
('explore'),
('facebook'),
('faq'),
('favorite'),
('favorites'),
('feature'),
('features'),
('feed'),
('feedback'),
('feeds'),
('file'),
('files'),
('first'),
('flash'),
('fleet'),
('fleets'),
('flog'),
('follow'),
('followers'),
('following'),
('forgot'),
('form'),
('forum'),
('forums'),
('founder'),
('free'),
('friend'),
('friends'),
('ftp'),
('gadget'),
('gadgets'),
('game'),
('games'),
('get'),
('ghost'),
('gift'),
('gifts'),
('gist'),
('github'),
('graph'),
('group'),
('groups'),
('guest'),
('guests'),
('help'),
('home'),
('homepage'),
('host'),
('hosting'),
('hostmaster'),
('hostname'),
('howto'),
('hpg'),
('html'),
('http'),
('httpd'),
('https'),
('i'),
('iamges'),
('icon'),
('icons'),
('id'),
('idea'),
('ideas'),
('image'),
('images'),
('imap'),
('img'),
('index'),
('indice'),
('info'),
('information'),
('inquiry'),
('instagram'),
('intranet'),
('invitations'),
('invite'),
('invoice'),
('invoices'),
('ipad'),
('iphone'),
('irc'),
('is'),
('issue'),
('issues'),
('it'),
('item'),
('items'),
('java'),
('javascript'),
('job'),
('jobs'),
('join'),
('js'),
('json'),
('jump'),
('knowledgebase'),
('language'),
('languages'),
('last'),
('ldap-status'),
('legal'),
('license'),
('link'),
('links'),
('linux'),
('lightning'),
('list'),
('lists'),
('log'),
('log-in'),
('log-out'),
('log_in'),
('log_out'),
('login'),
('logout'),
('logs'),
('m'),
('mac'),
('mail'),
('mail1'),
('mail2'),
('mail3'),
('mail4'),
('mail5'),
('mailer'),
('mailing'),
('maintenance'),
('manager'),
('manual'),
('map'),
('maps'),
('marketing'),
('master'),
('me'),
('media'),
('member'),
('members'),
('message'),
('messages'),
('messenger'),
('microblog'),
('microblogs'),
('mine'),
('mis'),
('mob'),
('mobile'),
('movie'),
('movies'),
('mp3'),
('msg'),
('msn'),
('music'),
('musicas'),
('mx'),
('my'),
('mysql'),
('name'),
('named'),
('nan'),
('nakamoto'),
('navi'),
('navigation'),
('net'),
('network'),
('new'),
('news'),
('newsletter'),
('nick'),
('nickname'),
('notes'),
('noticias'),
('notification'),
('notifications'),
('notify'),
('ns'),
('ns1'),
('ns10'),
('ns2'),
('ns3'),
('ns4'),
('ns5'),
('ns6'),
('ns7'),
('ns8'),
('ns9'),
('null'),
('oauth'),
('oauth_clients'),
('offer'),
('offers'),
('official'),
('old'),
('online'),
('openid'),
('operator'),
('order'),
('orders'),
('organization'),
('organizations'),
('overview'),
('owner'),
('owners'),
('page'),
('pager'),
('pages'),
('panel'),
('password'),
('payment'),
('perl'),
('phone'),
('photo'),
('photoalbum'),
('photos'),
('php'),
('phpmyadmin'),
('phppgadmin'),
('phpredisadmin'),
('pic'),
('pics'),
('ping'),
('plan'),
('plans'),
('plugin'),
('plugins'),
('policy'),
('pop'),
('pop3'),
('popular'),
('portal'),
('post'),
('postfix'),
('postmaster'),
('posts'),
('pr'),
('premium'),
('press'),
('price'),
('pricing'),
('privacy'),
('privacy-policy'),
('privacy_policy'),
('privacypolicy'),
('private'),
('product'),
('products'),
('profile'),
('project'),
('projects'),
('promo'),
('pub'),
('public'),
('purpose'),
('put'),
('python'),
('query'),
('random'),
('ranking'),
('read'),
('readme'),
('recent'),
('recruit'),
('recruitment'),
('register'),
('registration'),
('release'),
('remove'),
('replies'),
('report'),
('reports'),
('repositories'),
('repository'),
('req'),
('request'),
('requests'),
('reset'),
('roc'),
('root'),
('rss'),
('ruby'),
('rule'),
('sag'),
('sale'),
('sales'),
('sample'),
('samples'),
('sat'),
('sats'),
('satoshi'),
('satoshinakamoto'),
('satoshi_nakamoto'),
('save'),
('school'),
('script'),
('scripts'),
('search'),
('secure'),
('security'),
('self'),
('send'),
('server'),
('server-info'),
('server-status'),
('service'),
('services'),
('session'),
('sessions'),
('setting'),
('settings'),
('setup'),
('share'),
('shop'),
('show'),
('sign-in'),
('sign-up'),
('sign_in'),
('sign_up'),
('signin'),
('signout'),
('signup'),
('site'),
('sitemap'),
('sites'),
('smartphone'),
('smtp'),
('soporte'),
('source'),
('spec'),
('special'),
('sql'),
('src'),
('ssh'),
('ssl'),
('ssladmin'),
('ssladministrator'),
('sslwebmaster'),
('staff'),
('stage'),
('staging'),
('start'),
('stat'),
('state'),
('static'),
('stats'),
('status'),
('store'),
('stores'),
('stories'),
('style'),
('styleguide'),
('stylesheet'),
('stylesheets'),
('subdomain'),
('subscribe'),
('subscriptions'),
('suporte'),
('support'),
('svn'),
('swf'),
('sys'),
('sysadmin'),
('sysadministrator'),
('system'),
('tablet'),
('tablets'),
('tag'),
('talk'),
('task'),
('tasks'),
('team'),
('teams'),
('tech'),
('telnet'),
('term'),
('terms'),
('terms-of-service'),
('terms_of_service'),
('termsofservice'),
('test'),
('test1'),
('test2'),
('test3'),
('teste'),
('testing'),
('tests'),
('theme'),
('themes'),
('thread'),
('threads'),
('tmp'),
('todo'),
('tool'),
('tools'),
('top'),
('topic'),
('topics'),
('tos'),
('tour'),
('translations'),
('trends'),
('tutorial'),
('tux'),
('tv'),
('twitter'),
('undef'),
('unfollow'),
('unsubscribe'),
('update'),
('upload'),
('uploads'),
('url'),
('usage'),
('user'),
('username'),
('users'),
('usuario'),
('vendas'),
('ver'),
('version'),
('video'),
('videos'),
('visitor'),
('wallet'),
('watch'),
('weather'),
('web'),
('webhook'),
('webhooks'),
('webmail'),
('webmaster'),
('website'),
('websites'),
('welcome'),
('widget'),
('widgets'),
('withdrawl'),
('withdrawls'),
('wiki'),
('win'),
('windows'),
('word'),
('work'),
('works'),
('workshop'),
('ww'),
('wws'),
('www'),
('www1'),
('www2'),
('www3'),
('www4'),
('www5'),
('www6'),
('www7'),
('wwws'),
('wwww'),
('xfn'),
('xml'),
('xmpp'),
('xpg'),
('xxx'),
('yaml'),
('year'),
('yml'),
('you'),
('yourdomain'),
('yourname'),
('yoursite'),
('yourusername');

View File

@ -13,7 +13,7 @@ generator client {
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
updatedAt DateTime @default(now()) @updatedAt @map(name: "updated_at")
name String @unique
email String? @unique
emailVerified DateTime? @map(name: "email_verified")