diff --git a/components/messages.js b/components/messages.js index f0af08f7..bfb173e8 100644 --- a/components/messages.js +++ b/components/messages.js @@ -14,7 +14,7 @@ export const labels = defineMessages({ password: { id: 'label.password', defaultMessage: 'Password' }, role: { id: 'label.role', defaultMessage: 'Role' }, user: { id: 'label.user', defaultMessage: 'User' }, - admin: { id: 'label.administrator', defaultMessage: 'Administrator' }, + admin: { id: 'label.admin', defaultMessage: 'Administrator' }, confirm: { id: 'label.confirm', defaultMessage: 'Confirm' }, details: { id: 'label.details', defaultMessage: 'Details' }, websites: { id: 'label.websites', defaultMessage: 'Websites' }, diff --git a/components/pages/settings/teams/WebsiteAddTeamForm.js b/components/pages/settings/teams/TeamAddWebsiteForm.js similarity index 96% rename from components/pages/settings/teams/WebsiteAddTeamForm.js rename to components/pages/settings/teams/TeamAddWebsiteForm.js index 64ce782b..457a9adb 100644 --- a/components/pages/settings/teams/WebsiteAddTeamForm.js +++ b/components/pages/settings/teams/TeamAddWebsiteForm.js @@ -4,7 +4,7 @@ import { Button, Dropdown, Form, FormButtons, FormRow, Item, SubmitButton } from import WebsiteTags from './WebsiteTags'; import useMessages from 'hooks/useMessages'; -export default function WebsiteAddTeamForm({ teamId, onSave, onClose }) { +export default function TeamAddWebsiteForm({ teamId, onSave, onClose }) { const { formatMessage, labels } = useMessages(); const { get, post, useQuery, useMutation } = useApi(); const { mutate, error } = useMutation(data => post(`/teams/${teamId}/websites`, data)); diff --git a/components/pages/settings/teams/TeamLeaveForm.js b/components/pages/settings/teams/TeamLeaveForm.js index e33d0b25..2497f28a 100644 --- a/components/pages/settings/teams/TeamLeaveForm.js +++ b/components/pages/settings/teams/TeamLeaveForm.js @@ -2,18 +2,21 @@ import { Button, Form, FormButtons, SubmitButton } from 'react-basics'; import useApi from 'hooks/useApi'; import useMessages from 'hooks/useMessages'; -export default function TeamLeaveForm({ teamUserId, teamName, onSave, onClose }) { +export default function TeamLeaveForm({ teamId, userId, teamName, onSave, onClose }) { const { formatMessage, labels, messages, FormattedMessage } = useMessages(); const { del, useMutation } = useApi(); - const { mutate, error, isLoading } = useMutation(data => del(`/teamUsers/${teamUserId}`, data)); + const { mutate, error, isLoading } = useMutation(() => del(`/team/${teamId}/users/${userId}`)); - const handleSubmit = async data => { - mutate(data, { - onSuccess: async () => { - onSave(); - onClose(); + const handleSubmit = async () => { + mutate( + {}, + { + onSuccess: async () => { + onSave(); + onClose(); + }, }, - }); + ); }; return ( diff --git a/components/pages/settings/teams/TeamMemberRemoveButton.js b/components/pages/settings/teams/TeamMemberRemoveButton.js index 84b728a6..85e5db53 100644 --- a/components/pages/settings/teams/TeamMemberRemoveButton.js +++ b/components/pages/settings/teams/TeamMemberRemoveButton.js @@ -2,14 +2,14 @@ import useApi from 'hooks/useApi'; import useMessages from 'hooks/useMessages'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; -export default function TeamMemberRemoveButton({ teamUserId, disabled, onSave }) { +export default function TeamMemberRemoveButton({ teamId, userId, disabled, onSave }) { const { formatMessage, labels } = useMessages(); const { del, useMutation } = useApi(); - const { mutate, isLoading } = useMutation(() => del(`/teamUsers/${teamUserId}`)); + const { mutate, isLoading } = useMutation(() => del(`/team/${teamId}/users/${userId}`)); const handleRemoveTeamMember = () => { mutate( - { teamUserId }, + {}, { onSuccess: () => { onSave(); diff --git a/components/pages/settings/teams/TeamMembersTable.js b/components/pages/settings/teams/TeamMembersTable.js index b4909369..b13e57cd 100644 --- a/components/pages/settings/teams/TeamMembersTable.js +++ b/components/pages/settings/teams/TeamMembersTable.js @@ -43,7 +43,8 @@ export default function TeamMembersTable({ data = [], onSave, readOnly }) { action: !readOnly && ( diff --git a/components/pages/settings/teams/TeamWebsiteRemoveButton.js b/components/pages/settings/teams/TeamWebsiteRemoveButton.js index cc38f892..1887d80a 100644 --- a/components/pages/settings/teams/TeamWebsiteRemoveButton.js +++ b/components/pages/settings/teams/TeamWebsiteRemoveButton.js @@ -2,14 +2,14 @@ import useApi from 'hooks/useApi'; import useMessages from 'hooks/useMessages'; import { Icon, Icons, LoadingButton, Text } from 'react-basics'; -export default function TeamWebsiteRemoveButton({ teamWebsiteId, onSave }) { +export default function TeamWebsiteRemoveButton({ teamId, websiteId, onSave }) { const { formatMessage, labels } = useMessages(); const { del, useMutation } = useApi(); - const { mutate, isLoading } = useMutation(() => del(`/teamWebsites/${teamWebsiteId}`)); + const { mutate, isLoading } = useMutation(() => del(`/teams/${teamId}/websites/${websiteId}`)); const handleRemoveTeamMember = () => { mutate( - { teamWebsiteId }, + {}, { onSuccess: () => { onSave(); diff --git a/components/pages/settings/teams/TeamWebsites.js b/components/pages/settings/teams/TeamWebsites.js index b4e31034..a1bcdee8 100644 --- a/components/pages/settings/teams/TeamWebsites.js +++ b/components/pages/settings/teams/TeamWebsites.js @@ -11,7 +11,7 @@ import { } from 'react-basics'; import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import TeamWebsitesTable from 'components/pages/settings/teams/TeamWebsitesTable'; -import WebsiteAddTeamForm from 'components/pages/settings/teams/WebsiteAddTeamForm'; +import TeamAddWebsiteForm from 'components/pages/settings/teams/TeamAddWebsiteForm'; import useApi from 'hooks/useApi'; import useMessages from 'hooks/useMessages'; @@ -42,7 +42,7 @@ export default function TeamWebsites({ teamId }) { {formatMessage(labels.addWebsite)} - {close => } + {close => } ); diff --git a/components/pages/settings/teams/TeamWebsitesTable.js b/components/pages/settings/teams/TeamWebsitesTable.js index a2190abc..2d8a2a2d 100644 --- a/components/pages/settings/teams/TeamWebsitesTable.js +++ b/components/pages/settings/teams/TeamWebsitesTable.js @@ -38,7 +38,7 @@ export default function TeamWebsitesTable({ data = [], onSave }) { {(row, keys, rowIndex) => { - const { id: teamWebsiteId } = row; + const { teamId } = row; const { id: websiteId, name, domain, userId } = row.website; const { teamUser } = row.team; const owner = teamUser[0]; @@ -59,7 +59,8 @@ export default function TeamWebsitesTable({ data = [], onSave }) { {canRemove && ( )} diff --git a/components/pages/settings/teams/TeamsTable.js b/components/pages/settings/teams/TeamsTable.js index 4b27bdfe..1319c6d4 100644 --- a/components/pages/settings/teams/TeamsTable.js +++ b/components/pages/settings/teams/TeamsTable.js @@ -92,7 +92,8 @@ export default function TeamsTable({ data = [], onDelete }) { {close => ( , res: NextApiResponse) => { + await useAuth(req, res); + + if (req.method === 'DELETE') { + const { id: teamId, userId } = req.query; + + if (!(await canDeleteTeamUser(req.auth, teamId, userId))) { + return unauthorized(res, 'You must be the owner of this team.'); + } + + await deleteTeamUser(teamId, userId); + + return ok(res); + } + + return methodNotAllowed(res); +}; diff --git a/pages/api/teams/[id]/users.ts b/pages/api/teams/[id]/users/index.ts similarity index 73% rename from pages/api/teams/[id]/users.ts rename to pages/api/teams/[id]/users/index.ts index 9ed41e12..af01d0ce 100644 --- a/pages/api/teams/[id]/users.ts +++ b/pages/api/teams/[id]/users/index.ts @@ -1,9 +1,9 @@ -import { NextApiRequestQueryBody } from 'lib/types'; -import { canDeleteTeamUser, canUpdateTeam, canViewTeam } from 'lib/auth'; +import { canUpdateTeam, canViewTeam } from 'lib/auth'; import { useAuth } from 'lib/middleware'; +import { NextApiRequestQueryBody } from 'lib/types'; import { NextApiResponse } from 'next'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { createTeamUser, deleteTeamUser, getUser, getTeamUsers } from 'queries'; +import { createTeamUser, getTeamUsers, getUser } from 'queries'; export interface TeamUserRequestQuery { id: string; @@ -12,7 +12,6 @@ export interface TeamUserRequestQuery { export interface TeamUserRequestBody { email: string; roleId: string; - userId?: string; } export default async ( @@ -52,17 +51,5 @@ export default async ( return ok(res, updated); } - if (req.method === 'DELETE') { - const { userId } = req.body; - - if (await canDeleteTeamUser(req.auth, teamId, userId)) { - return unauthorized(res, 'You must be the owner of this team.'); - } - - await deleteTeamUser(teamId, userId); - - return ok(res); - } - return methodNotAllowed(res); }; diff --git a/pages/api/teamWebsites/[id].ts b/pages/api/teams/[id]/websites/[websiteId].ts similarity index 64% rename from pages/api/teamWebsites/[id].ts rename to pages/api/teams/[id]/websites/[websiteId].ts index 96222e08..5c0835d9 100644 --- a/pages/api/teamWebsites/[id].ts +++ b/pages/api/teams/[id]/websites/[websiteId].ts @@ -5,24 +5,25 @@ import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { deleteTeamWebsite } from 'queries/admin/teamWebsite'; -export interface TeamWebsiteRequestQuery { +export interface TeamWebsitesRequestQuery { id: string; + websiteId: string; } export default async ( - req: NextApiRequestQueryBody, + req: NextApiRequestQueryBody, res: NextApiResponse, ) => { await useAuth(req, res); - const { id: teamWebsiteId } = req.query; + const { id: teamId, websiteId } = req.query; if (req.method === 'DELETE') { - if (!(await canDeleteTeamWebsite(req.auth, teamWebsiteId))) { + if (!(await canDeleteTeamWebsite(req.auth, teamId, websiteId))) { return unauthorized(res); } - const websites = await deleteTeamWebsite(teamWebsiteId); + const websites = await deleteTeamWebsite(teamId, websiteId); return ok(res, websites); } diff --git a/pages/api/teams/[id]/websites.ts b/pages/api/teams/[id]/websites/index.ts similarity index 100% rename from pages/api/teams/[id]/websites.ts rename to pages/api/teams/[id]/websites/index.ts diff --git a/queries/admin/teamWebsite.ts b/queries/admin/teamWebsite.ts index 5592a2ac..0aedc3c7 100644 --- a/queries/admin/teamWebsite.ts +++ b/queries/admin/teamWebsite.ts @@ -1,16 +1,20 @@ -import { TeamWebsite, Prisma, Website, Team, User, TeamUser } from '@prisma/client'; +import { Prisma, Team, TeamUser, TeamWebsite, Website } from '@prisma/client'; import { ROLES } from 'lib/constants'; import { uuid } from 'lib/crypto'; import prisma from 'lib/prisma'; -export async function getTeamWebsite(teamWebsiteId: string): Promise< +export async function getTeamWebsite( + teamId: string, + websiteId: string, +): Promise< TeamWebsite & { website: Website; } > { return prisma.client.teamWebsite.findFirst({ where: { - id: teamWebsiteId, + teamId, + websiteId, }, include: { website: true, @@ -110,10 +114,14 @@ export async function createTeamWebsites(teamId: string, websiteIds: string[]) { }); } -export async function deleteTeamWebsite(teamWebsiteId: string): Promise { - return prisma.client.teamWebsite.delete({ +export async function deleteTeamWebsite( + teamId: string, + websiteId: string, +): Promise { + return prisma.client.teamWebsite.deleteMany({ where: { - id: teamWebsiteId, + teamId, + websiteId, }, }); }