Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add user seen artworks mutation #6443

Merged
merged 2 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions _schemaV2.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -8887,6 +8887,30 @@ type CreateUserSaleProfileSuccess {
userSaleProfile: UserSaleProfile
}

type CreateUserSeenArtworkFailure {
mutationError: GravityMutationError
}

input CreateUserSeenArtworkInput {
artworkId: String!
clientMutationId: String
}

type CreateUserSeenArtworkPayload {
clientMutationId: String

# On success: the created User Seen Artwork.
userSeenArtworkOrError: CreateUserSeenArtworkSuccessResponseOrError
}

type CreateUserSeenArtworkSuccess {
artworkId: String
}

union CreateUserSeenArtworkSuccessResponseOrError =
CreateUserSeenArtworkFailure
| CreateUserSeenArtworkSuccess

type CreateVerifiedRepresentativeFailure {
mutationError: GravityMutationError
}
Expand Down Expand Up @@ -14265,6 +14289,11 @@ type Mutation {
input: CreateUserSaleProfileMutationInput!
): CreateUserSaleProfileMutationPayload

# Marks an artwork as seen when a user swipes through Infinite Discovery.
createUserSeenArtwork(
input: CreateUserSeenArtworkInput!
): CreateUserSeenArtworkPayload

# Creates Verified Representative.
createVerifiedRepresentative(
input: CreateVerifiedRepresentativeInput!
Expand Down Expand Up @@ -17308,6 +17337,9 @@ type Query {

# Weights for the KNN and MLT query
osWeights: [Float] = [0.6, 0.4]

# Internal Redis tracking for the user seen artworks
useInternalTracking: Boolean = false
): ArtworkConnection

# A namespace external partners (provided by Galaxy)
Expand Down Expand Up @@ -22063,6 +22095,9 @@ type Viewer {

# Weights for the KNN and MLT query
osWeights: [Float] = [0.6, 0.4]

# Internal Redis tracking for the user seen artworks
useInternalTracking: Boolean = false
): ArtworkConnection

# A namespace external partners (provided by Galaxy)
Expand Down
5 changes: 5 additions & 0 deletions src/lib/loaders/loaders_with_authentication/gravity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ export default (accessToken, userID, opts) => {
{},
{ method: "POST" }
),
createUserSeenArtworkLoader: gravityLoader(
"artworks_discovery/artworks/seen",
{},
{ method: "POST" }
),
deliverSecondFactor: gravityLoader(
(id) => `me/second_factors/${id}/deliver`,
{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe("discoverArtworks", () => {
os_weights: [0.6, 0.4],
curated_picks_size: 2,
user_id: "user-id",
use_internal_tracking: false,
})

expect(result).toMatchInlineSnapshot(`
Expand Down Expand Up @@ -91,6 +92,7 @@ describe("discoverArtworks", () => {
os_weights: [0.5, 0.5],
curated_picks_size: 3,
user_id: "user-id",
use_internal_tracking: false,
})

expect(result).toMatchInlineSnapshot(`
Expand Down
98 changes: 98 additions & 0 deletions src/schema/v2/infiniteDiscovery/createUserSeenArtworkMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { mutationWithClientMutationId } from "graphql-relay"
import {
GraphQLNonNull,
GraphQLObjectType,
GraphQLString,
GraphQLUnionType,
} from "graphql"
import { ResolverContext } from "types/graphql"
import {
formatGravityError,
GravityMutationErrorType,
} from "lib/gravityErrorHandler"
import { snakeCase } from "lodash"

interface Input {
artworkId: string
}

const inputFields = {
artworkId: { type: new GraphQLNonNull(GraphQLString) },
}

interface GravityInput {
artwork_id: string
}

const SuccessType = new GraphQLObjectType<any, ResolverContext>({
name: "CreateUserSeenArtworkSuccess",
isTypeOf: (data) => data.artwork_id,
fields: {
artworkId: {
type: GraphQLString,
resolve: ({ artwork_id }) => artwork_id,
},
},
})

const FailureType = new GraphQLObjectType<any, ResolverContext>({
name: "CreateUserSeenArtworkFailure",
isTypeOf: (data) => data._type === "GravityMutationError",
fields: () => ({
mutationError: {
type: GravityMutationErrorType,
resolve: (err) => err,
},
}),
})

const ResponseOrErrorType = new GraphQLUnionType({
name: "CreateUserSeenArtworkSuccessResponseOrError",
types: [SuccessType, FailureType],
})

export const createUserSeenArtworkMutation = mutationWithClientMutationId<
Input,
any,
ResolverContext
>({
name: "CreateUserSeenArtwork",
description:
"Marks an artwork as seen when a user swipes through Infinite Discovery.",
inputFields,
outputFields: {
userSeenArtworkOrError: {
type: ResponseOrErrorType,
description: "On success: the created User Seen Artwork.",
resolve: (result) => result,
},
},
mutateAndGetPayload: async (args, { createUserSeenArtworkLoader }) => {
if (!createUserSeenArtworkLoader) {
throw new Error(
"You need to pass a X-Access-Token header to perform this action"
)
}

const createUserSeenArtworkLoaderPayload = Object.keys(args)
.filter((key) => key !== "id")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: not sure if I understand what it does. Could we just call createUserSeenArtworkLoader({ artwork_id: args.artworkId})?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It simply converts non-ID parameters to snake_case. Since it's used in other mutations, I thought it would be good to follow this utility for consistency

.reduce(
(acc, key) => ({ ...acc, [snakeCase(key)]: args[key] }),
{} as GravityInput
)

try {
return await createUserSeenArtworkLoader(
createUserSeenArtworkLoaderPayload
)
} catch (error) {
const formattedErr = formatGravityError(error)

if (formattedErr) {
return { ...formattedErr, _type: "GravityMutationError" }
} else {
throw new Error(error)
}
}
},
})
7 changes: 7 additions & 0 deletions src/schema/v2/infiniteDiscovery/discoverArtworks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
GraphQLInt,
GraphQLFloat,
GraphQLList,
GraphQLBoolean,
} from "graphql"
import { ResolverContext } from "types/graphql"
import { artworkConnection } from "../artwork"
Expand All @@ -18,6 +19,11 @@ export const DiscoverArtworks: GraphQLFieldConfig<void, ResolverContext> = {
type: new GraphQLList(GraphQLString),
description: "Exclude these artworks from the response",
},
useInternalTracking: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@egdbear sudden idea — let's instead of this param use an ENV var in line number 61? This way backend will be able to control behavior without frontend changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think that is necessary if we add this change to Eigen?

type: GraphQLBoolean,
description: "Internal Redis tracking for the user seen artworks",
defaultValue: false,
},
mltFields: {
type: new GraphQLList(GraphQLString),
description: "These fields are used for More Like This query",
Expand Down Expand Up @@ -52,6 +58,7 @@ export const DiscoverArtworks: GraphQLFieldConfig<void, ResolverContext> = {
os_weights: args.osWeights,
curated_picks_size: args.curatedPicksSize,
user_id: userID,
use_internal_tracking: args.useInternalTracking,
}

const gravityResponse = await artworksDiscoveryLoader(gravityArgs)
Expand Down
2 changes: 2 additions & 0 deletions src/schema/v2/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ import { deliverSecondFactorMutation } from "./me/secondFactors/mutations/delive
import { enableSecondFactorMutation } from "./me/secondFactors/mutations/enableSecondFactor"
import { createAndSendBackupSecondFactorMutation } from "./users/createAndSendBackupSecondFactorMutation"
import { createViewingRoomMutation } from "./viewingRooms/mutations/createViewingRoomMutation"
import { createUserSeenArtworkMutation } from "./infiniteDiscovery/createUserSeenArtworkMutation"
import { updateViewingRoomMutation } from "./viewingRooms/mutations/updateViewingRoomMutation"
import { deleteViewingRoomMutation } from "./viewingRooms/mutations/deleteViewingRoomMutation"
import { publishViewingRoomMutation } from "./viewingRooms/mutations/publishViewingRoomMutation"
Expand Down Expand Up @@ -477,6 +478,7 @@ export default new GraphQLSchema({
createPage: CreatePageMutation,
createPartnerOffer: createPartnerOfferMutation,
createUserAdminNote: createUserAdminNoteMutation,
createUserSeenArtwork: createUserSeenArtworkMutation,
createUserInterest: createUserInterestMutation,
createUserInterestForUser: createUserInterestForUser,
createUserInterests: createUserInterestsMutation,
Expand Down