Support tools can set appearance glitched state!

this is also very good! :3
This commit is contained in:
Emi Matchu 2020-08-31 00:48:54 -07:00
parent 2929c3373e
commit 1c8eba4698
2 changed files with 170 additions and 7 deletions

View file

@ -213,7 +213,7 @@ function PosePickerSupportNavigator({
function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) { function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
const { supportSecret } = useSupport(); const { supportSecret } = useSupport();
const [mutate, { loading, error, data }] = useMutation( const [mutatePose, poseMutation] = useMutation(
gql` gql`
mutation PosePickerSupportSetPetAppearancePose( mutation PosePickerSupportSetPetAppearancePose(
$appearanceId: ID! $appearanceId: ID!
@ -248,6 +248,41 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
} }
); );
const [mutateIsGlitched, isGlitchedMutation] = useMutation(
gql`
mutation PosePickerSupportSetPetAppearanceIsGlitched(
$appearanceId: ID!
$isGlitched: Boolean!
$supportSecret: String!
) {
setPetAppearanceIsGlitched(
appearanceId: $appearanceId
isGlitched: $isGlitched
supportSecret: $supportSecret
) {
id
isGlitched
}
}
`,
{
refetchQueries: [
{
query: gql`
query PosePickerSupportRefetchCanonicalAppearances(
$speciesId: ID!
$colorId: ID!
) {
...CanonicalPetAppearances
}
${canonicalPetAppearancesFragment}
`,
variables: { speciesId, colorId },
},
],
}
);
return ( return (
<Box> <Box>
<Box display="flex" flexDirection="row" alignItems="center"> <Box display="flex" flexDirection="row" alignItems="center">
@ -255,10 +290,16 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
size="sm" size="sm"
value={petAppearance.pose} value={petAppearance.pose}
flex="0 1 200px" flex="0 1 200px"
icon={loading ? <Spinner /> : data ? <CheckCircleIcon /> : undefined} icon={
poseMutation.loading ? (
<Spinner />
) : poseMutation.data ? (
<CheckCircleIcon />
) : undefined
}
onChange={(e) => { onChange={(e) => {
const pose = e.target.value; const pose = e.target.value;
mutate({ mutatePose({
variables: { variables: {
appearanceId: petAppearance.id, appearanceId: petAppearance.id,
pose, pose,
@ -276,7 +317,7 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
/* Discard errors here; we'll show them in the UI! */ /* Discard errors here; we'll show them in the UI! */
}); });
}} }}
isInvalid={error != null} isInvalid={poseMutation.error != null}
> >
{Object.entries(POSE_NAMES).map(([pose, name]) => ( {Object.entries(POSE_NAMES).map(([pose, name]) => (
<option key={pose} value={pose}> <option key={pose} value={pose}>
@ -289,14 +330,45 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
marginLeft="2" marginLeft="2"
flex="0 1 150px" flex="0 1 150px"
value={petAppearance.isGlitched} value={petAppearance.isGlitched}
cursor="not-allowed" icon={
isReadOnly isGlitchedMutation.loading ? (
<Spinner />
) : isGlitchedMutation.data ? (
<CheckCircleIcon />
) : undefined
}
onChange={(e) => {
const isGlitched = e.target.value === "true";
mutateIsGlitched({
variables: {
appearanceId: petAppearance.id,
isGlitched,
supportSecret,
},
optimisticResponse: {
__typename: "Mutation",
setPetAppearanceIsGlitched: {
__typename: "PetAppearance",
id: petAppearance.id,
isGlitched,
},
},
}).catch((e) => {
/* Discard errors here; we'll show them in the UI! */
});
}}
isInvalid={isGlitchedMutation.error != null}
> >
<option value="false">Valid</option> <option value="false">Valid</option>
<option value="true">Glitched</option> <option value="true">Glitched</option>
</Select> </Select>
</Box> </Box>
{error && <Box color="red.400">{error.message}</Box>} {poseMutation.error && (
<Box color="red.400">{poseMutation.error.message}</Box>
)}
{isGlitchedMutation.error && (
<Box color="red.400">{isGlitchedMutation.error.message}</Box>
)}
</Box> </Box>
); );
} }

View file

@ -267,6 +267,12 @@ const typeDefs = gql`
pose: Pose! pose: Pose!
supportSecret: String! supportSecret: String!
): PetAppearance! ): PetAppearance!
setPetAppearanceIsGlitched(
appearanceId: ID!
isGlitched: Boolean!
supportSecret: String!
): PetAppearance!
} }
`; `;
@ -1027,6 +1033,91 @@ const resolvers = {
return { id: appearanceId }; return { id: appearanceId };
}, },
setPetAppearanceIsGlitched: async (
_,
{ appearanceId, isGlitched, supportSecret },
{
colorTranslationLoader,
speciesTranslationLoader,
petStateLoader,
petTypeLoader,
db,
}
) => {
if (supportSecret !== process.env["SUPPORT_SECRET"]) {
throw new Error(`Support secret is incorrect. Try setting up again?`);
}
const oldPetState = await petStateLoader.load(appearanceId);
const [
result,
] = await db.execute(
`UPDATE pet_states SET glitched = ? WHERE id = ? LIMIT 1`,
[isGlitched, appearanceId]
);
if (result.affectedRows !== 1) {
throw new Error(
`Expected to affect 1 layer, but affected ${result.affectedRows}`
);
}
// we changed it, so clear it from cache
petStateLoader.clear(appearanceId);
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
try {
const petType = await petTypeLoader.load(oldPetState.petTypeId);
const [colorTranslation, speciesTranslation] = await Promise.all([
colorTranslationLoader.load(petType.colorId),
speciesTranslationLoader.load(petType.speciesId),
]);
const colorName = capitalize(colorTranslation.name);
const speciesName = capitalize(speciesTranslation.name);
const pose = getPoseFromPetState(oldPetState);
const oldGlitchinessState =
String(oldPetState.glitched) === "1" ? "Glitched" : "Valid";
const newGlitchinessState = isGlitched ? "Glitched" : "Valid";
await logToDiscord({
embeds: [
{
title: `🛠 ${colorName} ${speciesName}`,
thumbnail: {
url: `http://pets.neopets.com/cp/${
petType.basicImageHash || petType.imageHash
}/1/6.png`,
height: 150,
width: 150,
},
fields: [
{
name: `Appearance ${appearanceId}`,
value: `${oldGlitchinessState} → **${newGlitchinessState}**`,
},
{
name: "As a reminder…",
value: "…the thumbnail might not match!",
},
],
timestamp: new Date().toISOString(),
url: `https://impress-2020.openneo.net/outfits/new?species=${petType.speciesId}&color=${petType.colorId}&pose=${pose}&state=${appearanceId}`,
},
],
});
} catch (e) {
console.error("Error sending Discord support log", e);
}
} else {
console.warn("No Discord support webhook provided, skipping");
}
return { id: appearanceId };
},
}, },
}; };