Skip to content

Commit

Permalink
add github repo sync ability
Browse files Browse the repository at this point in the history
  • Loading branch information
kibagateaux committed Jan 16, 2024
1 parent 63cfaf9 commit af37f58
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 28 deletions.
109 changes: 102 additions & 7 deletions src/inventory/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,28 @@ import {
IntelligenceStat,
InventoryItem,
HoF,
ItemStatus,
Resource,
} from 'types/GameMechanics';
import { obj } from 'types/UserConfig';
import { cleanGql, qu } from 'utils/api';
import { ID_PLAYER_SLOT, ID_PROVIDER_IDS_SLOT, getCached } from 'utils/config';
import { debug, track } from 'utils/logging';
import { getProviderId } from 'utils/oauth';

export const ITEM_ID = 'Github';
export const ABILITY_SYNC_REPOS = 'github-sync-repos';

const equip: HoF = async (promptAsync) => {
console.log('equipping github!!!');
try {
// expo-auth-session only exposes API via hooks which we cant embed in this since its a conditional call
// should we roll our own OAuth lib or just keep this callback method?
// Slightly complicates equip() vs no params but also enables a ton of functionality for any item
// TODO We use Github App which includes OAuth but must be installed via Github directly
// might be good UX to have them send a message install of linking directly
// Linking.openURL("https://github.com/apps/jinni-health-dev");
// Server gets OAuth callback after install automatically

promptAsync!();

// TODO send mu(syncProvideId). If call fails then login unsuccessful
return true;
} catch (e) {
Expand All @@ -35,9 +48,9 @@ const unequip: HoF = async () => {
};

const item: InventoryItem = {
id: 'Github',
id: ITEM_ID,
name: 'Octopus Brains',
dataProvider: 'Github',
dataProvider: ITEM_ID,
image: 'https://pngimg.com/uploads/github/github_PNG90.png',
tags: ['digital', 'productivity'],
attributes: [
Expand All @@ -48,12 +61,94 @@ const item: InventoryItem = {
],
checkStatus: async () => {
// TODO api request to see if access_token exist on API
return 'unequipped';
const cached = (await getCached<obj>({ slot: ID_PROVIDER_IDS_SLOT }))?.[ITEM_ID];
console.log('sync id res', cached, await getCached<obj>({ slot: ID_PROVIDER_IDS_SLOT }));

// return 'unequipped';
return cached ? 'equipped' : 'unequipped';
},
canEquip: async () => true,
equip,
unequip,
abilities: [],
abilities: [
{
id: ABILITY_SYNC_REPOS,
name: 'Add Repos',
symbol: '💻',
description: 'Give your jinni access to your code repos to learn from your daily adds',
canDo: async (status: ItemStatus) => (status === 'equipped' ? 'doable' : 'unequipped'),
do: async () => {
track(ABILITY_SYNC_REPOS, {
ability: ABILITY_SYNC_REPOS,
activityType: 'initiated',
});
const pid = await getCached<string>({ slot: ID_PLAYER_SLOT });
if (!pid) {
track(ABILITY_SYNC_REPOS, {
ability: ABILITY_SYNC_REPOS,
activityType: 'unauthenticated',
});
return async () => false;
}

try {
// ensure provider id to pull
const providerId = await getProviderId({ playerId: pid, provider: ITEM_ID });
if (!providerId) {
track(ABILITY_SYNC_REPOS, {
ability: ABILITY_SYNC_REPOS,
activityType: 'unequipped',
providerId,
success: false,
});
return async () => false;
}

const response = await qu<{ data: { sync_repos: Resource[] } }>({
mutation: cleanGql(`
mutation sync_repos(
$player_id: String!,
$provider: String!,
$verification: SignedRequest
) {
sync_repos(
verification: $verification,
provider: $provider,
player_id: $player_id
) {
provider_id
name
url
}
}
`),
})({ player_id: pid, provider: ITEM_ID });
track(ABILITY_SYNC_REPOS, {
ability: ABILITY_SYNC_REPOS,
activityType: 'completed',
provider: providerId,
});
console.log('inv;Github:sync-repos:res', response);

return async () => (response?.data?.sync_repos ? true : false);
} catch (e) {
debug(e, {
extra: { ability: ABILITY_SYNC_REPOS },
tags: { ability: true },
});

return async () => false;
}

// fetch their playlists from spotify
// open modal
// display playlists
// player selects playlist
// open phone native share/contacts module
// player selects people to send to
},
},
],
widgets: [],
};

Expand Down
38 changes: 21 additions & 17 deletions src/inventory/spotify.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Platform, Share } from 'react-native';
import { qu } from 'utils/api';
import { cleanGql, qu } from 'utils/api';
import { getProviderId } from 'utils/oauth';

import {
Expand Down Expand Up @@ -83,24 +83,28 @@ const item: InventoryItem = {
do: async () => {
const pid = await getCached({ slot: ID_PLAYER_SLOT });
if (!pid) return async () => false;

qu<Resource[]>({
query: `
query spotify_top_playlist(
$verification: SignedRequest!
$target_player: SignedRequest!
) {
spotify_top_playlist(
verification: $verification
target_player: $target_player
try {
const response = qu<Resource[]>({
query: cleanGql(`
query spotify_top_playlist(
$verification: SignedRequest!
$target_player: String!
) {
id
name
href
spotify_top_playlist(
verification: $verification
target_player: $target_player
) {
id
name
href
}
}
}
`,
})({ player_id: pid });
`),
})({ player_id: pid });
console.log('inv:Spotify:SharePlaylist:res', response);
} catch (e) {
console.log('inv:Spotify:SharePlaylist:ERROR', e);
}
// fetch their playlists from spotify
// open modal
// display playlists
Expand Down
6 changes: 5 additions & 1 deletion src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ export const saveStorage: <T>(
try {
if (shouldMerge) {
console.log(
'Config:saveStorage:shouldMerge?',
'Config:saveStorage:shouldMerge isArray?',
Array.isArray(existingVal),
Array.isArray(defaultVal) || defaultVal === undefined,
);
Expand All @@ -347,6 +347,10 @@ export const saveStorage: <T>(
updateCache({ slot: key }, value);
return newVal;
} else {
console.log(
'Config:saveStorage:shouldMerge isObj?',
existingVal ? merge(existingVal, value) : merge(defaultVal ?? {}, value),
);
// assume its an object. technically could be a function but thats an object too
const newVal = existingVal
? merge(existingVal, value)
Expand Down
6 changes: 3 additions & 3 deletions src/utils/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ export const createOauthRedirectURI = memoize(() => {
if (Platform.OS !== 'web') {
return makeRedirectUri({
native: Platform.select({
android: `https://30d6-45-7-237-230.ngrok-free.app/oauth/callback`,
ios: `https://30d6-45-7-237-230.ngrok-free.app/oauth/callback`,
android: `https://d12f-31-217-248-130.ngrok-free.app/oauth/callback`,
ios: `https://d12f-31-217-248-130.ngrok-free.app/oauth/callback`,
// android: `${getAppConfig().API_URL}/oauth/callback`,
// ios: `${getAppConfig().API_URL}/oauth/callback`,
}),
Expand Down Expand Up @@ -124,6 +124,7 @@ export const QU_PROVIDER_ID = cleanGql(`
)
}
`);
const quProviderId = qu<{ data: { sync_provider_id: string } }>({ mutation: QU_PROVIDER_ID });

// frequent helper functions + extra caching
/**
Expand All @@ -133,7 +134,6 @@ export const QU_PROVIDER_ID = cleanGql(`
* @param provider - provider that issues id
* @returns id on provider or null
*/
const quProviderId = qu({ mutation: QU_PROVIDER_ID });
export const getProviderId = async ({ playerId, provider }: obj): Promise<string | null> => {
const cached = (await getCached<obj>({ slot: ID_PROVIDER_IDS_SLOT }))?.[provider];
console.log('util:oauth:getProviderId:cached', cached);
Expand Down

0 comments on commit af37f58

Please sign in to comment.