Support tool: Remove layer from item

Heck yeah, let's clean these fuckers up!
This commit is contained in:
Emi Matchu 2020-08-20 21:40:05 -07:00
parent c94e94538e
commit 6821c2b734
3 changed files with 176 additions and 0 deletions

View file

@ -15,6 +15,7 @@ GRANT SELECT ON openneo_impress.zone_translations TO impress2020;
-- Public data tables: write -- Public data tables: write
GRANT UPDATE ON openneo_impress.items TO impress2020; GRANT UPDATE ON openneo_impress.items TO impress2020;
GRANT UPDATE ON openneo_impress.swf_assets TO impress2020; GRANT UPDATE ON openneo_impress.swf_assets TO impress2020;
GRANT DELETE ON openneo_impress.parents_swf_assets TO impress2020;
-- User data tables -- User data tables
GRANT SELECT ON openneo_impress.item_outfit_relationships TO impress2020; GRANT SELECT ON openneo_impress.item_outfit_relationships TO impress2020;

View file

@ -19,6 +19,7 @@ import {
Radio, Radio,
RadioGroup, RadioGroup,
Spinner, Spinner,
useDisclosure,
useToast, useToast,
} from "@chakra-ui/core"; } from "@chakra-ui/core";
import { ChevronRightIcon, ExternalLinkIcon } from "@chakra-ui/icons"; import { ChevronRightIcon, ExternalLinkIcon } from "@chakra-ui/icons";
@ -209,10 +210,18 @@ function ItemLayerSupportModal({
/> />
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<ItemLayerSupportModalRemoveButton
item={item}
itemLayer={itemLayer}
outfitState={outfitState}
onRemoveSuccess={onClose}
/>
<Box flex="1 0 0" />
{mutationError && ( {mutationError && (
<Box <Box
color="red.400" color="red.400"
fontSize="sm" fontSize="sm"
marginLeft="8"
marginRight="2" marginRight="2"
textAlign="right" textAlign="right"
> >
@ -223,6 +232,7 @@ function ItemLayerSupportModal({
isLoading={mutationLoading} isLoading={mutationLoading}
colorScheme="green" colorScheme="green"
onClick={mutate} onClick={mutate}
flex="0 0 auto"
> >
Save changes Save changes
</Button> </Button>
@ -344,4 +354,133 @@ function ItemLayerSupportPetCompatibilityFields({
); );
} }
function ItemLayerSupportModalRemoveButton({
item,
itemLayer,
outfitState,
onRemoveSuccess,
}) {
const { isOpen, onOpen, onClose } = useDisclosure();
const toast = useToast();
const supportSecret = useSupportSecret();
const [mutate, { loading, error }] = useMutation(
gql`
mutation ItemLayerSupportRemoveButton(
$layerId: ID!
$itemId: ID!
$outfitSpeciesId: ID!
$outfitColorId: ID!
$supportSecret: String!
) {
removeLayerFromItem(
layerId: $layerId
itemId: $itemId
supportSecret: $supportSecret
) {
# This mutation returns the affected layer, and the affected item.
# Fetch the updated appearance for the current outfit, which should
# no longer include this layer. This means you should be able to see
# your changes immediately!
item {
id
appearanceOn(speciesId: $outfitSpeciesId, colorId: $outfitColorId) {
...ItemAppearanceForOutfitPreview
}
}
# The layer's item should be null now, fetch to confirm and update!
layer {
id
item {
id
}
}
}
}
${itemAppearanceFragment}
`,
{
variables: {
layerId: itemLayer.id,
itemId: item.id,
outfitSpeciesId: outfitState.speciesId,
outfitColorId: outfitState.colorId,
supportSecret,
},
onCompleted: () => {
onClose();
onRemoveSuccess();
toast({
status: "success",
title: `Removed layer ${itemLayer.id} from ${item.name}`,
});
},
}
);
return (
<>
<Button colorScheme="red" flex="0 0 auto" onClick={onOpen}>
Remove
</Button>
<Modal isOpen={isOpen} onClose={onClose} size="xl" isCentered>
<ModalOverlay>
<ModalContent>
<ModalCloseButton />
<ModalHeader>
Remove Layer {itemLayer.id} ({itemLayer.zone.label}) from{" "}
{item.name}?
</ModalHeader>
<ModalBody>
<Box as="p" marginBottom="4">
This will permanently-ish remove Layer {itemLayer.id} (
{itemLayer.zone.label}) from this item.
</Box>
<Box as="p" marginBottom="4">
If you remove a correct layer by mistake, re-modeling should fix
it, or Matchu can restore it if you write down the layer ID
before proceeding!
</Box>
<Box as="p" marginBottom="4">
Are you sure you want to remove Layer {itemLayer.id} from this
item?
</Box>
</ModalBody>
<ModalFooter>
<Button flex="0 0 auto" onClick={onClose}>
Close
</Button>
<Box flex="1 0 0" />
{error && (
<Box
color="red.400"
fontSize="sm"
marginLeft="8"
marginRight="2"
textAlign="right"
>
{error.message}
</Box>
)}
<Button
colorScheme="red"
flex="0 0 auto"
onClick={() =>
mutate().catch((e) => {
/* Discard errors here; we'll show them in the UI! */
})
}
isLoading={loading}
>
Yes, remove permanently
</Button>
</ModalFooter>
</ModalContent>
</ModalOverlay>
</Modal>
</>
);
}
export default ItemLayerSupportModal; export default ItemLayerSupportModal;

View file

@ -210,6 +210,11 @@ const typeDefs = gql`
petOnNeopetsDotCom(petName: String!): Outfit petOnNeopetsDotCom(petName: String!): Outfit
} }
type RemoveLayerFromItemMutationResult {
layer: AppearanceLayer!
item: Item!
}
type Mutation { type Mutation {
setManualSpecialColor( setManualSpecialColor(
itemId: ID! itemId: ID!
@ -228,6 +233,12 @@ const typeDefs = gql`
bodyId: ID! bodyId: ID!
supportSecret: String! supportSecret: String!
): AppearanceLayer! ): AppearanceLayer!
removeLayerFromItem(
layerId: ID!
itemId: ID!
supportSecret: String!
): RemoveLayerFromItemMutationResult!
} }
`; `;
@ -672,6 +683,31 @@ const resolvers = {
return { id: layerId }; return { id: layerId };
}, },
removeLayerFromItem: async (
_,
{ layerId, itemId, supportSecret },
{ db }
) => {
if (supportSecret !== process.env["SUPPORT_SECRET"]) {
throw new Error(`Support secret is incorrect. Try setting up again?`);
}
const [result] = await db.execute(
`DELETE FROM parents_swf_assets ` +
`WHERE swf_asset_id = ? AND parent_type = "Item" AND parent_id = ? ` +
`LIMIT 1`,
[layerId, itemId]
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
);
}
return { layer: { id: layerId }, item: { id: itemId } };
},
}, },
}; };