Skip to content

Commit

Permalink
Merge branch 'main' into dataset-project-proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
zackkrida authored Jul 12, 2023
2 parents ab53d93 + cf3f9d1 commit a19882e
Show file tree
Hide file tree
Showing 97 changed files with 354 additions and 256 deletions.
9 changes: 9 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,15 @@ module.exports = {
],
},
},
{
files: ["frontend/test/{playwright,storybook}/**"],
plugins: ["playwright"],
extends: ["plugin:playwright/recommended"],
rules: {
// Enable once https://github.com/playwright-community/eslint-plugin-playwright/issues/154 is resolved
"playwright/expect-expect": ["off"],
},
},
{
files: [
"automations/js/src/**",
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1080,5 +1080,5 @@ jobs:
with:
payload: ${{ steps.report.outputs.payload }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_OV_ALERTS_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"test:unit": "jest",
"test:unit:watch": "pnpm test:unit --collectCoverage=false --watch",
"test:playwright": "./bin/playwright.sh",
"test:playwright:local": "pnpm exec playwright test -c test/playwright",
"test:playwright:local": "playwright test -c test/playwright",
"test:playwright:debug": "PWDEBUG=1 pnpm test:playwright:local",
"test:playwright:recreate-tapes": "rimraf test/tapes && pnpm test:playwright:update-tapes",
"test:playwright:update-tapes": "UPDATE_TAPES=true pnpm test:playwright",
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions frontend/src/components/VErrorSection/VErrorImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type { ErrorCode } from "~/constants/errors"
import { AttributableMedia, getAttribution } from "~/utils/attribution-html"
import { useI18n } from "~/composables/use-i18n"
import imageInfo from "~/assets/error_images/image_info.json"
import imageInfo from "~/assets/error_images.json"
interface ErrorImage extends AttributableMedia {
src: string
Expand Down Expand Up @@ -51,7 +51,7 @@ export default defineComponent({
const errorImage: ErrorImage = {
...image,
originalTitle: image.title,
src: require(`~/assets/error_images/${image.file}.jpg`),
src: `/error_images/${image.file}.jpg`,
alt: `errorImages.${image.id}`,
license: image.license as License,
license_version: image.license_version as LicenseVersion,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/VHeader/VSearchBar/VSearchBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- Form action is a fallback for when JavaScript is disabled. -->
<form
action="/search"
role="search"
class="search-bar group flex h-12 flex-row items-center rounded-sm border-tx bg-white"
@submit.prevent="handleSearch"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<!-- Form action is a fallback for when JavaScript is disabled. -->
<form
action="/search"
role="search"
class="search-bar group flex h-14 flex-row items-center rounded-sm border-tx bg-white sm:h-16"
@submit.prevent="handleSearch"
>
Expand Down
6 changes: 2 additions & 4 deletions frontend/src/components/VHomeGallery/VHomeGallery.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import useResizeObserver from "~/composables/use-resize-observer"
import VLink from "~/components/VLink.vue"
import imageInfo from "~/assets/homepage_images/image_info.json"
import imageInfo from "~/assets/homepage_images.json"
export const GALLERY_SETS = [
"universe",
Expand Down Expand Up @@ -112,9 +112,7 @@ export default defineComponent({
const imageList = computed(() => {
return imageSet.value.images.map((image, idx) => ({
...image,
src: require(`~/assets/homepage_images/${imageSet.value.key}/${
idx + 1
}.png`),
src: `/homepage_images/${imageSet.value.key}/${idx + 1}.png`,
url: router.resolve(
app.localePath({
name: "image-id",
Expand Down
15 changes: 0 additions & 15 deletions frontend/src/composables/use-browser-detection.ts

This file was deleted.

16 changes: 16 additions & 0 deletions frontend/src/constants/content-safety.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Contains constants pertaining to the content safety feature. These include
* different types of sensitivities.
*/

export const USER_REPORTED = "user_reported_sensitive"
export const PROVIDER_SUPPLIED = "provider_supplied_sensitive"
export const TEXT_FILTERED = "sensitive_text"

export const SENSITIVITIES = [
USER_REPORTED,
PROVIDER_SUPPLIED,
TEXT_FILTERED,
] as const

export type Sensitivity = (typeof SENSITIVITIES)[number]
9 changes: 9 additions & 0 deletions frontend/src/constants/user-agent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* A user agent string by which Openverse.org identifies itself to services
*/
const userAgent =
"Openverse/0.1 (https://openverse.org; [email protected])"

module.exports = {
userAgent,
}
37 changes: 25 additions & 12 deletions frontend/src/data/api-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"
import { warn } from "~/utils/console"
import { AUDIO, IMAGE } from "~/constants/media"

import { userAgent } from "~/constants/user-agent"

const DEFAULT_REQUEST_TIMEOUT = 30000

/**
* Openverse Axios request config with adjusted types for our use-case.
*/
export type OpenverseAxiosRequestConfig = Required<
Pick<AxiosRequestConfig, "headers">
> &
AxiosRequestConfig

/**
* Returns a slug with trailing slash for a given resource name.
* For media types, converts the name into resource slug when necessary (i.e. pluralizes 'image'),
Expand All @@ -24,7 +34,7 @@ export const getResourceSlug = (resource: string): string => {
const validateRequest = (
errorCondition: boolean,
message: string,
config: AxiosRequestConfig
config: OpenverseAxiosRequestConfig
): void => {
if (errorCondition) {
warn(
Expand Down Expand Up @@ -63,22 +73,22 @@ export interface ApiService {
post<T = unknown>(
resource: string,
data: Parameters<AxiosInstance["post"]>[1],
headers?: AxiosRequestConfig["headers"]
headers?: OpenverseAxiosRequestConfig["headers"]
): Promise<AxiosResponse<T>>
update<T = unknown>(
resource: string,
slug: string,
data: Parameters<AxiosInstance["put"]>[1],
headers: AxiosRequestConfig["headers"]
headers: OpenverseAxiosRequestConfig["headers"]
): Promise<AxiosResponse<T>>
put<T = unknown>(
resource: string,
params: AxiosRequestConfig
params: OpenverseAxiosRequestConfig
): Promise<AxiosResponse<T>>
delete<T = unknown>(
resource: string,
slug: string,
headers: AxiosRequestConfig["headers"]
headers: OpenverseAxiosRequestConfig["headers"]
): Promise<AxiosResponse<T>>
}

Expand All @@ -87,24 +97,27 @@ export const createApiService = ({
accessToken = undefined,
isVersioned = true,
}: ApiServiceConfig = {}): ApiService => {
const axiosParams: AxiosRequestConfig = {
const axiosParams: OpenverseAxiosRequestConfig = {
baseURL: isVersioned ? `${baseUrl}v1/` : baseUrl,
timeout: DEFAULT_REQUEST_TIMEOUT,
headers: { "User-Agent": userAgent },
}

if (accessToken) {
axiosParams.headers = { Authorization: `Bearer ${accessToken}` }
axiosParams.headers["Authorization"] = `Bearer ${accessToken}`
}

const client = axios.create(axiosParams)
client.interceptors.request.use(function (config) {
validateRequest(
!config.url?.endsWith("/"),
"API request urls should have a trailing slash",
config
config as OpenverseAxiosRequestConfig
)
validateRequest(
config.url?.includes("//") ?? false,
"API request urls should not have two slashes",
config
config as OpenverseAxiosRequestConfig
)
return config
})
Expand Down Expand Up @@ -174,7 +187,7 @@ export const createApiService = ({
resource: string,
slug: string,
data: Parameters<(typeof client)["put"]>[1],
headers: AxiosRequestConfig["headers"]
headers: OpenverseAxiosRequestConfig["headers"]
): Promise<AxiosResponse<T>> {
return client.put(`${getResourceSlug(resource)}${slug}`, data, {
headers,
Expand All @@ -188,7 +201,7 @@ export const createApiService = ({
*/
put<T = unknown>(
resource: string,
params: AxiosRequestConfig
params: OpenverseAxiosRequestConfig
): Promise<AxiosResponse<T>> {
return client.put(getResourceSlug(resource), params)
},
Expand All @@ -202,7 +215,7 @@ export const createApiService = ({
delete<T = unknown>(
resource: string,
slug: string,
headers: AxiosRequestConfig["headers"]
headers: OpenverseAxiosRequestConfig["headers"]
): Promise<AxiosResponse<T>> {
return client.delete(`${getResourceSlug(resource)}${slug}`, { headers })
},
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/locales/scripts/axios.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const axios = require("axios")
const rateLimit = require("axios-rate-limit")

const userAgent =
"Openverse/0.1 (https://wordpress.org/openverse; [email protected])"
const { userAgent } = require("../../constants/user-agent")

module.exports = rateLimit(
axios.create({
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/stores/media/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import { initServices } from "~/stores/media/services"
import { isSearchTypeSupported, useSearchStore } from "~/stores/search"
import { useRelatedMediaStore } from "~/stores/media/related-media"
import { deepFreeze } from "~/utils/deep-freeze"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import { markFakeSensitive } from "~/utils/content-safety"

export type MediaStoreResult = {
count: number
Expand Down Expand Up @@ -438,12 +436,6 @@ export const useMediaStore = defineStore("media", {
}
this._updateFetchState(mediaType, "end", errorMessage)

// Fake ~50% of results as mature. This leaves actual mature results unchanged.
const featureFlagStore = useFeatureFlagStore()
if (featureFlagStore.isOn("fake_sensitive")) {
Object.values(data.results).forEach(markFakeSensitive)
}

this.setMedia({
mediaType,
media: data.results,
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/stores/media/single-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { initServices } from "~/stores/media/services"
import { useMediaStore } from "~/stores/media/index"
import { useRelatedMediaStore } from "~/stores/media/related-media"
import { useProviderStore } from "~/stores/provider"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import { markFakeSensitive } from "~/utils/content-safety"

export type MediaItemState =
| {
Expand Down Expand Up @@ -119,12 +117,6 @@ export const useSingleResultStore = defineStore("single-result", {
const service = initServices[type](accessToken)
const item = this._addProviderName(await service.getMediaDetail(id))

// Fake ~50% of results as mature. This leaves actual mature results unchanged.
const featureFlagStore = useFeatureFlagStore()
if (featureFlagStore.isOn("fake_sensitive")) {
markFakeSensitive(item)
}

this.mediaItem = item
this.mediaType = type

Expand Down
8 changes: 7 additions & 1 deletion frontend/src/types/media.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { SupportedMediaType } from "~/constants/media"
import type { License, LicenseVersion } from "~/constants/license"
import type { Sensitivity } from "~/constants/content-safety"

export interface Tag {
name: string
Expand Down Expand Up @@ -46,6 +47,8 @@ export interface Media {
fields_matched?: string[]

mature: boolean
sensitivity: Sensitivity[]
isSensitive: boolean
}

export interface ImageDetail extends Media {
Expand Down Expand Up @@ -90,7 +93,10 @@ export type DetailFromMediaType<T extends SupportedMediaType> =
* being decoded in the `decodeMediaData` function.
*/
export interface ApiMedia
extends Omit<Media, "frontendMediaType" | "title" | "originalTitle"> {
extends Omit<
Media,
"frontendMediaType" | "title" | "originalTitle" | "isSensitive"
> {
title?: string
originalTitle?: string
}
Expand Down
43 changes: 32 additions & 11 deletions frontend/src/utils/content-safety.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,43 @@
* Contains utilities related to content safety.
*/

import type { Media } from "~/types/media"
import { hash, rand as prng } from "~/utils/prng"
import { log } from "~/utils/console"
import {
USER_REPORTED,
PROVIDER_SUPPLIED,
TEXT_FILTERED,
Sensitivity,
} from "~/constants/content-safety"

/**
* Marks the given item as mature based on a random number seeded with the
* item's UUID v4 identifier. The `frac` param controls the probability of an
* item being marked as mature.
* Get an array of randomly selected sensitive content flags for an item with
* the given UUID v4 identifier. The `frac` param controls the probability of an
* item having sensitivity flags.
*
* @param item - the item to mark as mature
* @param frac - the fraction of items to mark as mature
* @param id - the ID of the item for which to calculate the flags
* @param frac - the fraction of items to probabilistically flag
* @returns an array of strings representing the mature flags
*/
export const markFakeSensitive = (item: Media, frac = 0.5) => {
const random = prng(hash(item.id))()
if (random < frac) {
item.mature = true
log("Fake mature", item.frontendMediaType, item.id)
export const getFakeSensitivities = (id: string, frac = 0.5): Sensitivity[] => {
const random = prng(hash(id))()

if (random > frac) {
return []
}

const sensitivityMask = Math.floor((random * 7) / frac) + 1
const sensitivity: Sensitivity[] = []
if ((sensitivityMask & 4) !== 0) {
sensitivity.push(USER_REPORTED)
}
if ((sensitivityMask & 2) !== 0) {
sensitivity.push(PROVIDER_SUPPLIED)
}
if ((sensitivityMask & 1) !== 0) {
sensitivity.push(TEXT_FILTERED)
}

log("Fake mature", id, sensitivity)
return sensitivity
}
Loading

0 comments on commit a19882e

Please sign in to comment.