-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
167 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,93 @@ | ||
"use client" | ||
import { useQuery, gql, useMutation } from '@apollo/client' | ||
import { useState } from 'react' | ||
import {useState} from 'react' | ||
import { useQuery, useMutation, gql } from '@apollo/client' | ||
|
||
import Provider from '../../components/Provider' | ||
import Loading from '../../components/Loading' | ||
import Error from '../../components/Error' | ||
import Amount from '../../components/Amount' | ||
import {myDate, myTime} from '../../utils' | ||
import {myDate} from '../../utils' | ||
import Table from '../../components/Table' | ||
import Thead from '../../components/Thead' | ||
import Th from '../../components/Th' | ||
import Tr from '../../components/Tr' | ||
import Td from '../../components/Td' | ||
import Button from '../../components/Button' | ||
|
||
export default function UsersPage({}) { | ||
return <Provider> | ||
<Users /> | ||
</Provider> | ||
} | ||
|
||
const GET_USERS = gql` | ||
query GetUsers { | ||
users { | ||
const GET_USER_TRANSACTIONS = gql` | ||
query GetUserTransactions { | ||
userTransactions { | ||
creditCents | ||
timestamp | ||
count | ||
_id | ||
admin | ||
} | ||
}` | ||
|
||
function Users() { | ||
const {loading, error, data} = useQuery(GET_USERS) | ||
const {loading, error, data} = useQuery(GET_USER_TRANSACTIONS) | ||
const [edit, setEdit] = useState(false) | ||
if (loading) return <Loading /> | ||
if (error) return <Error error={error}/> | ||
return <> | ||
{edit | ||
? <a className="ml-auto" href="#" onClick={() => setEdit(false)}> | ||
termina modifiche | ||
</a> | ||
:<a className="ml-auto" href="#" onClick={() => setEdit(true)}> | ||
modifica | ||
</a> | ||
} | ||
<Table> | ||
<Thead> | ||
<tr> | ||
<Th className="text-left">email</Th> | ||
<Th className="text-right">#</Th> | ||
<Th className="text-right">€</Th> | ||
<Th className="text-left">data</Th> | ||
<Th className="text-left">admin</Th> | ||
</tr> | ||
</Thead> | ||
<tbody> | ||
{data.users.map((user: any, i: number) => | ||
{data.userTransactions.map((user: any, i: number) => | ||
<Tr key={i}> | ||
<Td>{user.email}</Td> | ||
<Td className="text-right">{user.count||""}</Td> | ||
<Td className="text-right"><Amount cents={user.creditCents}/></Td> | ||
<Td className="text-left">{myDate(user.timestamp)}</Td> | ||
<Td className="text-left"> | ||
{!edit && user.admin?"✅":""} | ||
{edit && user._id && <UpdateAdminButton user={user} />} | ||
</Td> | ||
</Tr> | ||
)} | ||
</tbody> | ||
</Table> | ||
</> | ||
} | ||
} | ||
|
||
const UPDATE_USER = gql` | ||
mutation UpdateUser($_id: String!, $data: UpdateUserInput) { | ||
updateUser(_id: $_id, data: $data) | ||
}` | ||
|
||
function UpdateAdminButton({user}:{user: {_id: string, admin: Boolean}}) { | ||
const [updateUser, {data, loading, error}] = useMutation(UPDATE_USER, { | ||
refetchQueries: ["GetUserTransactions"] | ||
}) | ||
return user.admin | ||
? <Button onClick={() => updateUser({variables: {_id: user._id, data: {admin: false}}})}> | ||
remove admin | ||
</Button> | ||
:<Button onClick={() => updateUser({variables: {_id: user._id, data: {admin: true}}})}> | ||
make admin | ||
</Button> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { User, Context } from './types' | ||
import config from '../config' | ||
import { isPermittedEmail } from '../utils' | ||
|
||
/** | ||
* @param context | ||
* @returns user object if authenticated | ||
* @throws error if not authenticated | ||
*/ | ||
export function requireAuthenticatedUser(context: Context) { | ||
const user = context?.user | ||
if (!user) throw new Error("not logged in") | ||
return user | ||
} | ||
|
||
/** | ||
* @param context | ||
* @returns user object if authenticated and email is permitted by configuration | ||
* @throws error if not authenticated or email is not permitted | ||
*/ | ||
export function requirePermittedUser(context: Context) { | ||
const user = requireAuthenticatedUser(context) | ||
if (!isPermittedEmail(user?.email)) throw new Error("email not permitted") | ||
return user | ||
} | ||
|
||
/** | ||
* @param context | ||
* @returns user object if authenticated and email is in the list of admins | ||
* @throws error if not authenticated or email is not in the list of admins | ||
*/ | ||
export function requireAdminUser(context: Context): User { | ||
const authorization = context.req.headers.get('authorization') | ||
if (authorization && !Array.isArray(authorization) && config.ADMIN_SECRET_TOKENS.split(',').includes(authorization)) { | ||
return { email: 'admin', name: 'request with authorization token', picture: '', id: 'unknown_admin', admin: true } | ||
} | ||
|
||
const user = requireAuthenticatedUser(context) | ||
if (!user.admin) throw new Error("not admin") | ||
return user | ||
} | ||
|
||
export function requireCardAuthentication(context: Context): User { | ||
const authorization = context.req.headers.get('authorization') | ||
if (authorization && !Array.isArray(authorization) && config.CARD_SECRET_TOKENS.split(',').includes(authorization)) { | ||
return { email: 'card', name: 'request with authorization token', picture: '', id: 'unknown_card', admin: false } | ||
} | ||
throw new Error("not card user") | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import type { NextRequest } from "next/server" | ||
|
||
export type User = { | ||
email: string | ||
name: string | ||
picture: string | ||
id: string | ||
admin: boolean | ||
} | ||
|
||
export type Context = { | ||
req: NextRequest | ||
res: Response|undefined | ||
user?: User | ||
} | ||
|