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
GRANT UPDATE ON openneo_impress.items TO impress2020;
GRANT UPDATE ON openneo_impress.swf_assets TO impress2020;
GRANT DELETE ON openneo_impress.parents_swf_assets TO impress2020;
-- User data tables
GRANT SELECT ON openneo_impress.item_outfit_relationships TO impress2020;

View file

@ -19,6 +19,7 @@ import {
Radio,
RadioGroup,
Spinner,
useDisclosure,
useToast,
} from "@chakra-ui/core";
import { ChevronRightIcon, ExternalLinkIcon } from "@chakra-ui/icons";
@ -209,10 +210,18 @@ function ItemLayerSupportModal({
/>
</ModalBody>
<ModalFooter>
<ItemLayerSupportModalRemoveButton
item={item}
itemLayer={itemLayer}
outfitState={outfitState}
onRemoveSuccess={onClose}
/>
<Box flex="1 0 0" />
{mutationError && (
<Box
color="red.400"
fontSize="sm"
marginLeft="8"
marginRight="2"
textAlign="right"
>
@ -223,6 +232,7 @@ function ItemLayerSupportModal({
isLoading={mutationLoading}
colorScheme="green"
onClick={mutate}
flex="0 0 auto"
>
Save changes
</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;

View file

@ -210,6 +210,11 @@ const typeDefs = gql`
petOnNeopetsDotCom(petName: String!): Outfit
}
type RemoveLayerFromItemMutationResult {
layer: AppearanceLayer!
item: Item!
}
type Mutation {
setManualSpecialColor(
itemId: ID!
@ -228,6 +233,12 @@ const typeDefs = gql`
bodyId: ID!
supportSecret: String!
): AppearanceLayer!
removeLayerFromItem(
layerId: ID!
itemId: ID!
supportSecret: String!
): RemoveLayerFromItemMutationResult!
}
`;
@ -672,6 +683,31 @@ const resolvers = {
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 } };
},
},
};