Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Add block remote config #124

Merged
merged 1 commit into from
Nov 19, 2020
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
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ jobs:
command: |
mv build-production build
cp ./resources/apple-app-site-association build
cp ./robots.txt build
echo ${GA_ACCESS_TOKEN} | npx wrangler secret put GA_ACCESS_TOKEN --env production
npx wrangler publish --env production

Expand Down
5 changes: 4 additions & 1 deletion src/containers/deleted-page/DeletedPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ type DeletedPageContentProps = {
canonicalUrl: string
playable: Playable
user: User
deletedByArtist?: boolean
}

const DeletedPage = ({
title,
description,
canonicalUrl,
playable,
user
user,
deletedByArtist = true
}: DeletedPageContentProps) => {
const isMobile = useIsMobile()

Expand All @@ -34,6 +36,7 @@ const DeletedPage = ({
canonicalUrl={canonicalUrl}
playable={playable}
user={user}
deletedByArtist={deletedByArtist}
>
{content}
</DeletedPageProvider>
Expand Down
5 changes: 4 additions & 1 deletion src/containers/deleted-page/DeletedPageProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type OwnProps = {
canonicalUrl: string
user: User
playable: Playable
deletedByArtist: boolean

children:
| React.ComponentType<DesktopDeletedPageProps>
Expand All @@ -39,6 +40,7 @@ const DeletedPageProvider = ({
description,
canonicalUrl,
user,
deletedByArtist = true,
playable,
children: Children,
currentQueueItem,
Expand Down Expand Up @@ -88,7 +90,8 @@ const DeletedPageProvider = ({
playable,
user,
goToArtistPage,
getLineupProps
getLineupProps,
deletedByArtist
}

return <Children {...childProps} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import Playable from 'models/Playable'
import { NestedNonNullable } from 'utils/typeUtils'

const messages = {
trackDeleted: 'Track [Deleted By Artist]',
trackDeleted: 'Track [Deleted]',
trackDeletedByArtist: 'Track [Deleted By Artist]',
playlistDeleted: 'Playlist [Deleted by Artist]',
albumDeleted: 'Album [Deleted By Artist]',
checkOut: (name: string) => `Check out more by ${name}`,
Expand Down Expand Up @@ -59,6 +60,7 @@ export type DeletedPageProps = {
title: string
description: string
canonicalUrl: string
deletedByArtist: boolean

playable: Playable
user: User | null
Expand All @@ -79,6 +81,7 @@ const DeletedPage = g(
canonicalUrl,
playable,
user,
deletedByArtist = true,
getLineupProps,
goToArtistPage
}) => {
Expand All @@ -91,6 +94,8 @@ const DeletedPage = g(
? isAlbum
? messages.albumDeleted
: messages.playlistDeleted
: deletedByArtist
? messages.trackDeletedByArtist
: messages.trackDeleted

const renderTile = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import Playable from 'models/Playable'
import { NestedNonNullable } from 'utils/typeUtils'

const messages = {
trackDeleted: 'Track [Deleted By Artist]',
trackDeleted: 'Track [Deleted]',
trackDeletedByArtist: 'Track [Deleted By Artist]',
playlistDeleted: 'Playlist [Deleted by Artist]',
albumDeleted: 'Album [Deleted By Artist]',
checkOut: (name: string) => `Check out more by ${name}`,
Expand Down Expand Up @@ -56,6 +57,7 @@ export type DeletedPageProps = {
title: string
description: string
canonicalUrl: string
deletedByArtist: boolean

playable: Playable
user: User | null
Expand All @@ -75,6 +77,7 @@ const DeletedPage = g(
description,
canonicalUrl,
playable,
deletedByArtist = true,
user,
getLineupProps,
goToArtistPage
Expand All @@ -88,6 +91,8 @@ const DeletedPage = g(
? isAlbum
? messages.albumDeleted
: messages.playlistDeleted
: deletedByArtist
? messages.trackDeletedByArtist
: messages.trackDeleted

const renderTile = () => {
Expand Down
1 change: 1 addition & 0 deletions src/containers/track-page/TrackPageProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ class TrackPageProvider extends Component<
canonicalUrl={canonicalUrl}
playable={{ metadata: track, type: PlayableType.TRACK }}
user={user}
deletedByArtist={!track._blocked}
/>
)
}
Expand Down
2 changes: 2 additions & 0 deletions src/models/Track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ export type ComputedTrackProperties = {
_remix_parents?: Array<{ track_id: ID }>
// Present iff the track has been cosigned
_co_sign?: Nullable<Remix>

_blocked?: boolean
}

export type Track = TrackMetadata & ComputedTrackProperties
Expand Down
33 changes: 15 additions & 18 deletions src/services/AudiusBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import * as DiscoveryAPI from '@audius/libs/src/services/discoveryProvider/requests'
import * as IdentityAPI from '@audius/libs/src/services/identity/requests'
import { Timer } from 'utils/performance'
import { waitForRemoteConfig } from './remote-config/Provider'

export const IDENTITY_SERVICE = process.env.REACT_APP_IDENTITY_SERVICE
export const USER_NODE = process.env.REACT_APP_USER_NODE
Expand Down Expand Up @@ -56,6 +57,18 @@ export const AuthHeaders = Object.freeze({
Signature: 'Encoded-Data-Signature'
})

export const waitForWeb3 = async () => {
if (!window.web3Loaded) {
await new Promise(resolve => {
const onLoad = () => {
window.removeEventListener('WEB3_LOADED', onLoad)
resolve()
}
window.addEventListener('WEB3_LOADED', onLoad)
})
}
}

let AudiusLibs = null
let Utils = null
let SanityChecks = null
Expand Down Expand Up @@ -303,25 +316,9 @@ class AudiusBackend {

static async setup() {
// Wait for web3 to load if necessary
if (!window.web3Loaded) {
await new Promise(resolve => {
const onLoad = () => {
window.removeEventListener('WEB3_LOADED', onLoad)
resolve()
}
window.addEventListener('WEB3_LOADED', onLoad)
})
}
await waitForWeb3()
// Wait for optimizely to load if necessary
if (!window.optimizelyDatafile) {
await new Promise(resolve => {
const onLoad = () => {
window.removeEventListener('OPTIMIZELY_LOADED', onLoad)
resolve()
}
window.addEventListener('OPTIMIZELY_LOADED', onLoad)
})
}
await waitForRemoteConfig()

const { libs, libsUtils, libsSanityChecks } = await import(
'./audius-backend/AudiusLibsLazyLoader'
Expand Down
12 changes: 8 additions & 4 deletions src/services/remote-config/Provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,7 @@ export function getFeatureEnabled(flag: FeatureFlags) {
}
}

// Internal

const init = async () => {
console.time('remote-config')
export const waitForRemoteConfig = async () => {
// Wait for optimizely to load if necessary (as it can be an async or defer tag)
// @ts-ignore: injected in index.html
if (!window.optimizelyDatafile) {
Expand All @@ -146,6 +143,13 @@ const init = async () => {
})
if (cb) window.removeEventListener('OPTIMIZELY_LOADED', cb)
}
}

// Internal

const init = async () => {
console.time('remote-config')
await waitForRemoteConfig()

provider = optimizely.createInstance({
// @ts-ignore: injected in index.html
Expand Down
7 changes: 6 additions & 1 deletion src/services/remote-config/RemoteConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ export enum StringKeys {
/**
* Custom eth provider urls to use for talking to main-net contracts
*/
ETH_PROVIDER_URLS = 'ETH_PROVIDER_URLS'
ETH_PROVIDER_URLS = 'ETH_PROVIDER_URLS',

/**
* Blocks content
*/
CONTENT_BLOCK_LIST = 'CONTENT_BLOCK_LIST'
}

export type AllRemoteConfigKeys =
Expand Down
3 changes: 2 additions & 1 deletion src/services/remote-config/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const remoteConfigStringDefaults: {
[StringKeys.AUDIUS_LOGO_VARIANT]: null,
[StringKeys.AUDIUS_LOGO_VARIANT_CLICK_TARGET]: null,
[StringKeys.APP_WIDE_NOTICE_TEXT]: null,
[StringKeys.ETH_PROVIDER_URLS]: ETH_PROVIDER_URLS
[StringKeys.ETH_PROVIDER_URLS]: ETH_PROVIDER_URLS,
[StringKeys.CONTENT_BLOCK_LIST]: null
}
export const remoteConfigDoubleDefaults: {
[key in DoubleKeys]: number | null
Expand Down
44 changes: 44 additions & 0 deletions src/store/cache/tracks/utils/blocklist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { getRemoteVar, StringKeys } from 'services/remote-config'
import { TrackMetadata } from 'models/Track'
import { waitForRemoteConfig } from 'services/remote-config/Provider'
import { waitForWeb3 } from 'services/AudiusBackend'

declare global {
interface Window {
Web3: any
}
}

const IS_WEB_HOSTNAME =
window.location.hostname === process.env.REACT_APP_PUBLIC_HOSTNAME

let blockList: Set<string>

const setBlocked = async <T extends TrackMetadata>(track: T) => {
// Initialize the set if not present
if (!blockList) {
await waitForRemoteConfig()
blockList = new Set(
(getRemoteVar(StringKeys.CONTENT_BLOCK_LIST) || '').split(',')
)
}
if (IS_WEB_HOSTNAME) {
await waitForWeb3()
const shaId = window.Web3.utils.sha3(track.track_id.toString())
if (blockList.has(shaId)) {
return {
...track,
is_delete: true,
_blocked: true
}
}
}
// Most of the time this method is a no-op
return track
}

export const setTracksIsBlocked = async <T extends TrackMetadata>(
tracks: T[]
): Promise<T[]> => {
return await Promise.all(tracks.map(setBlocked))
}
7 changes: 5 additions & 2 deletions src/store/cache/tracks/utils/processAndCacheTracks.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { put } from 'redux-saga/effects'
import { put, call } from 'redux-saga/effects'
import * as cacheActions from 'store/cache/actions'
import { reformat } from './reformat'
import { Kind } from 'store/types'
import { makeUid } from 'utils/uid'
import { addUsersFromTracks } from './helpers'
import Track, { TrackMetadata } from 'models/Track'
import { setTracksIsBlocked } from './blocklist'

/**
* Processes tracks, adding users and calling `reformat`, before
Expand All @@ -17,8 +18,10 @@ export function* processAndCacheTracks<T extends TrackMetadata>(
// Add users
yield addUsersFromTracks(tracks)

const checkedTracks: T[] = yield call(setTracksIsBlocked, tracks)

// Remove users, add images
const reformattedTracks = tracks.map(reformat)
const reformattedTracks = checkedTracks.map(reformat)

// insert tracks into cache
yield put(
Expand Down
4 changes: 3 additions & 1 deletion src/store/cache/tracks/utils/retrieveTracks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { fetchAndProcessStems } from './fetchAndProcessStems'
import apiClient from 'services/audius-api-client/AudiusAPIClient'
import { getUserId } from 'store/account/selectors'
import { setTracksIsBlocked } from './blocklist'

type UnlistedTrackRequest = { id: ID; url_title: string; handle: string }
type RetrieveTracksArgs = {
Expand Down Expand Up @@ -150,7 +151,8 @@ export function* retrieveTracks({
deleteExistingEntry: false,
onBeforeAddToCache: function* <T extends TrackMetadata>(tracks: T[]) {
yield addUsersFromTracks(tracks)
return tracks.map(track => reformat(track))
const checkedTracks = yield call(setTracksIsBlocked, tracks)
return checkedTracks.map(reformat)
}
})

Expand Down
3 changes: 1 addition & 2 deletions src/store/reachability/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ const REACHABILITY_SHORT_TIMEOUT = 5 * 1000 // 5s
const REACHABILITY_REQUEST_TIMEOUT = 15 * 1000 // 15s

// Check that a response from REACHABILITY_URL is valid
const isResponseValid = (response: Response) =>
response && response.ok && response.status === 204
const isResponseValid = (response: Response) => response && response.ok

function* ping() {
// If there's no reachability url available, consider ourselves reachable
Expand Down