From a9ea341a7b7f86f15cbee003ba89cc2c1869a28d Mon Sep 17 00:00:00 2001 From: keyan Date: Fri, 21 May 2021 19:09:11 -0500 Subject: [PATCH] create reserved usernames --- api/resolvers/user.js | 19 +- api/typeDefs/user.js | 4 + components/form.js | 4 +- components/user-header.js | 21 +- pages/lnd.js | 22 - .../20210427152429_init/migration.sql | 2 +- .../migration.sql | 625 ++++++++++++++++++ prisma/schema.prisma | 2 +- 8 files changed, 671 insertions(+), 28 deletions(-) delete mode 100644 pages/lnd.js create mode 100644 prisma/migrations/20210521234940_reserved_names/migration.sql diff --git a/api/resolvers/user.js b/api/resolvers/user.js index 4cab97a4..3386b5f6 100644 --- a/api/resolvers/user.js +++ b/api/resolvers/user.js @@ -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 } }) diff --git a/api/typeDefs/user.js b/api/typeDefs/user.js index 6ec10b5d..df8379b0 100644 --- a/api/typeDefs/user.js +++ b/api/typeDefs/user.js @@ -8,6 +8,10 @@ export default gql` nameAvailable(name: String!): Boolean! } + extend type Mutation { + setName(name: String!): Boolean + } + type User { id: ID! name: String diff --git a/components/form.js b/components/form.js index 67a120ce..74c513bf 100644 --- a/components/form.js +++ b/components/form.js @@ -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 ({ onSubmit && onSubmit(...args).catch(e => setError(e.message || e))} > diff --git a/components/user-header.js b/components/user-header.js index 083adb1d..5a501062 100644 --- a/components/user-header.js +++ b/components/user-header.js @@ -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 = () =>

[{user.stacked} stacked, {user.sats} sats]

@@ -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}` + }} > @ diff --git a/pages/lnd.js b/pages/lnd.js deleted file mode 100644 index c1f9fb50..00000000 --- a/pages/lnd.js +++ /dev/null @@ -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 ( - - - {data && data.accounts.map(account => -
account
- )} -
- ) -} diff --git a/prisma/migrations/20210427152429_init/migration.sql b/prisma/migrations/20210427152429_init/migration.sql index 46a5b807..73cdcddc 100644 --- a/prisma/migrations/20210427152429_init/migration.sql +++ b/prisma/migrations/20210427152429_init/migration.sql @@ -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), diff --git a/prisma/migrations/20210521234940_reserved_names/migration.sql b/prisma/migrations/20210521234940_reserved_names/migration.sql new file mode 100644 index 00000000..c3731050 --- /dev/null +++ b/prisma/migrations/20210521234940_reserved_names/migration.sql @@ -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'); \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c544c80d..96fffb28 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -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")