Skip to content

Commit

Permalink
feat: implement more PubKey Profiles features
Browse files Browse the repository at this point in the history
  • Loading branch information
beeman committed Jun 21, 2024
1 parent 74c5fc9 commit 91f295e
Show file tree
Hide file tree
Showing 56 changed files with 1,684 additions and 103 deletions.
21 changes: 19 additions & 2 deletions api-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,31 @@ type PagingMeta {
totalCount: Int
}

type PubkeyProfile {
authorities: [String!]!
avatarUrl: String!
bump: Int!
feePayer: String!
identities: [PubkeyProfileIdentity!]!
publicKey: String!
username: String!
}

type PubkeyProfileIdentity {
name: String!
provider: String!
providerId: String!
}

type Query {
adminFindManyIdentity(input: IdentityAdminFindManyInput!): [Identity!]
adminFindManyUser(input: UserAdminFindManyInput!): UserPaging!
adminFindOneUser(userId: String!): User
anonRequestIdentityChallenge(input: IdentityRequestChallengeInput!): IdentityChallenge
appConfig: AppConfig!
getUserProfile: JSON!
getUserProfileByUsername(username: String!): JSON!
getUserProfile: PubkeyProfile
getUserProfileByProvider(provider: IdentityProvider!, providerId: String!): PubkeyProfile
getUserProfileByUsername(username: String!): PubkeyProfile
getUserProfiles: JSON!
me: User
solanaGetBalance(account: String!): String
Expand Down
10 changes: 10 additions & 0 deletions apps/web/src/assets/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,23 @@ export class ApiIdentityDataAnonService {

if (identity?.owner && profile) {
if (profile.username !== identity?.owner?.username) {
throw new Error(`TODO: Fix: Profile and Identity Owner username do not match`)
console.log({
profileUsername: profile.username,
identityOwnerUsername: identity?.owner?.username,
})
this.logger.warn(`Re-syncing profile username: ${identity?.owner?.username} => ${profile.username}`)
await this.core.data.user.update({
where: { id: identity?.owner?.id },
data: {
username: profile.username,
// TODO: Fix: once we have a name property on the PubKeyProfile
name: profile.username,
avatarUrl: profile.avatarUrl,
},
})
}
avatarUrl = identity.owner.avatarUrl ?? undefined
username = identity.owner.username
avatarUrl = profile.avatarUrl
username = profile.username
}

// PubKey Profile is found, identity does not exist.
Expand Down
1 change: 1 addition & 0 deletions libs/api/profile/data-access/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './lib/entity/api-pubkey-profile.entity'
export * from './lib/api-profile.data-access.module'
export * from './lib/api-profile.service'
81 changes: 70 additions & 11 deletions libs/api/profile/data-access/src/lib/api-profile.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ export class ApiProfileService {
providerId: i.providerId,
}))

const diff = diffProfileIdentities(userIdentities, profileIdentities)
console.log('diff', diff)
const diffIdentities = diffProfileIdentities(userIdentities, profileIdentities)
console.log('diffIdentities', diffIdentities)

try {
const current = await this.getUserProfile(userId)
Expand All @@ -150,15 +150,26 @@ export class ApiProfileService {
async syncUserProfile(userId: string) {
const { user, profile } = await this.ensureUserProfile(userId)

console.log({ user, profile })
const userIdentities = user.identities.map((i) => ({ provider: i.provider.toString(), providerId: i.providerId }))

const profileIdentities = profile.identities.map((i) => ({
provider: i.provider.toString(),
providerId: i.providerId,
}))
const diffProfile = diffProfileDetails(
{ avatarUrl: 'a', username: user?.username },
{ avatarUrl: 'a', username: profile?.username },
)

if (Object.values(diffProfile).filter(Boolean).length) {
console.log('profile changes', diffProfile)
}

const diff = diffProfileIdentities(userIdentities, profileIdentities)
console.log('diff', diff)
const diffIdentities = diffProfileIdentities(
userIdentities,
profile.identities.map((i) => ({
provider: i.provider.toString(),
providerId: i.providerId,
})),
)
console.log('diffIdentities', diffIdentities)

try {
const current = await this.getUserProfile(userId)
Expand Down Expand Up @@ -221,7 +232,14 @@ export class ApiProfileService {
provider: IdentityProvider,
providerId: string,
): Promise<PubKeyProfile | null> {
return this.sdk.getProfileByProviderNullable({ provider: convertToPubKeyIdentityProvider(provider), providerId })
try {
return await this.sdk.getProfileByProviderNullable({
provider: convertToPubKeyIdentityProvider(provider),
providerId,
})
} catch (e) {
return null
}
}

async getUserProfiles(): Promise<PubKeyProfile[]> {
Expand All @@ -234,14 +252,45 @@ export class ApiProfileService {
throw new Error('User not found')
}

const profile = await this.sdk.getProfileByUsernameNullable({ username: user.username })
const publicKeys: string[] = user.identities
.filter((i) => i.provider === IdentityProvider.Solana)
.map((i) => i.providerId)
const profile = await this.findProfile({ username: user.username, publicKeys })
if (!profile) {
throw new Error('User profile not found')
}

return { user, profile }
}

private async findProfile({ username, publicKeys }: { username: string; publicKeys: string[] }) {
const profile = await this.sdk.getProfileByUsernameNullable({ username })

if (profile) {
console.log(`No profile found`)
return profile
}

const profiles = await Promise.all(
publicKeys.map((providerId) => {
console.log(` -> Searching ${providerId}`)
return this.sdk.getProfileByProviderNullable({
provider: PubKeyIdentityProvider.Solana,
providerId,
})
}),
)

if (profiles?.length === 1) {
return profiles[0]
}

if (profiles.length > 1) {
throw new Error('TODO: handle case with multiple profiles')
}
throw new Error('User profile not found')
}

private ensureValidProvider(provider: PubKeyIdentityProvider) {
if (!this.validProviders.includes(provider)) {
throw new Error(`Invalid provider: ${provider}`)
Expand Down Expand Up @@ -323,7 +372,17 @@ function diffProfileIdentities(
)
}

function convertToPubKeyIdentityProvider(provider: IdentityProvider): PubKeyIdentityProvider {
function diffProfileDetails(
left: { avatarUrl?: string; username?: string },
right: { avatarUrl?: string; username?: string },
): { avatarUrl?: string; username?: string } {
return {
avatarUrl: left?.avatarUrl !== right?.avatarUrl ? right?.avatarUrl : undefined,
username: left?.username !== right?.username ? right?.username : undefined,
}
}

export function convertToPubKeyIdentityProvider(provider: IdentityProvider): PubKeyIdentityProvider {
switch (provider.toString()) {
case 'Discord':
return PubKeyIdentityProvider.Discord
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'

@ObjectType()
export class PubkeyProfile {
@Field(() => Int)
bump!: number

@Field()
username!: string

@Field()
avatarUrl?: string

@Field()
feePayer!: string

@Field(() => [String])
authorities!: string[]

@Field(() => [PubkeyProfileIdentity])
identities!: PubkeyProfileIdentity[]

@Field()
publicKey!: string
}

@ObjectType()
export class PubkeyProfileIdentity {
@Field()
provider!: string

@Field()
providerId!: string

@Field()
name!: string
}
14 changes: 11 additions & 3 deletions libs/api/profile/feature/src/lib/api-profile.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { UseGuards } from '@nestjs/common'
import { Args, Int, Mutation, Query, Resolver } from '@nestjs/graphql'
import { ApiAuthGraphQLUserGuard, CtxUserId } from '@pubkey-network/api-auth-data-access'
import { IdentityProvider } from '@pubkey-network/api-identity-data-access'
import { ApiProfileService } from '@pubkey-network/api-profile-data-access'
import { ApiProfileService, PubkeyProfile } from '@pubkey-network/api-profile-data-access'
import { GraphQLJSON } from 'graphql-scalars'

@Resolver()
Expand Down Expand Up @@ -45,12 +45,20 @@ export class ApiProfileResolver {
return this.service.syncUserProfile(userId)
}

@Query(() => GraphQLJSON)
@Query(() => PubkeyProfile, { nullable: true })
getUserProfileByUsername(@Args('username') username: string) {
return this.service.getUserProfileByUsername(username)
}

@Query(() => GraphQLJSON)
@Query(() => PubkeyProfile, { nullable: true })
getUserProfileByProvider(
@Args({ name: 'provider', type: () => IdentityProvider }) provider: IdentityProvider,
@Args('providerId') providerId: string,
) {
return this.service.getUserProfileByProviderNullable(provider, providerId)
}

@Query(() => PubkeyProfile, { nullable: true })
getUserProfile(@CtxUserId() userId: string) {
return this.service.getUserProfile(userId)
}
Expand Down
Loading

0 comments on commit 91f295e

Please sign in to comment.