Skip to content

Commit

Permalink
feat(API): send the app_name param in every API call (#588)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphodn authored Jun 4, 2024
1 parent b627f00 commit 5a6af2f
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 73 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"lint-staged": {
"*.{js,ts,vue}": [
"yarn lint --max-warnings=0"
"yarn lint --max-warnings=0 --no-warn-ignored"
]
},
"dependencies": {
Expand Down
4 changes: 3 additions & 1 deletion src/components/UserRecentProofsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
</v-row>
<v-row v-if="userProofList.length < userProofTotal" class="mb-2">
<v-col align="center">
<v-btn size="small" :loading="loading" @click="getUserProofs">{{ $t('ProofDetail.LoadMore') }}</v-btn>
<v-btn size="small" :loading="loading" @click="getUserProofs">
{{ $t('ProofDetail.LoadMore') }}
</v-btn>
</v-col>
</v-row>
</v-card-text>
Expand Down
2 changes: 2 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ const OPF_ICON = 'mdi-bookshelf'

export default {
APP_NAME: 'Open Prices',
APP_USER_AGENT: 'Open Prices Web App',
OFF_NAME: OFF_NAME,
OFF_URL: 'https://world.openfoodfacts.org',
OFF_ICON: OFF_ICON,
OFF_WIKI_URL: 'https://wiki.openfoodfacts.org/Main_Page',
OFF_WIKI_APP_URL: 'https://wiki.openfoodfacts.org/Project:Open-Prices',
OFF_WIKI_GDPR_REQUEST_URL: 'https://wiki.openfoodfacts.org/GDPR_request',
OFF_API_URL: 'https://world.openfoodfacts.org/api/v2/product',
OBF_NAME: OBF_NAME,
OBF_URL: 'https://world.openbeautyfacts.org',
OBF_ICON: OBF_ICON,
Expand Down
125 changes: 64 additions & 61 deletions src/services/api.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
import { useAppStore } from '../store'
import constants from '../constants'

const OPENFOODFACTS_PRODUCT_URL = 'https://world.openfoodfacts.org/api/v2/product'

const DEFAULT_HEADERS = {
'Content-Type': 'application/json'
}

const DEFAULT_PARAMS = {
'app_name': constants.APP_USER_AGENT
}

function buildURLParams(params = {}) {
return new URLSearchParams({...DEFAULT_PARAMS, ...params})
}


export default {
signIn(username, password) {
let formData = new FormData()
formData.append('username', username)
formData.append('password', password)
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/auth`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/auth?${buildURLParams()}`
return fetch(url, {
method: 'POST',
body: formData,
headers: DEFAULT_HEADERS
})
.then((response) => response.json())
},

getUsers(params = {}) {
const defaultParams = {page: 1, size: 10} // order_by default ?
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/users?${new URLSearchParams({...defaultParams, ...params})}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/users?${buildURLParams({...defaultParams, ...params})}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS
})
.then((response) => response.json())
},
Expand All @@ -33,11 +44,12 @@ export default {
let formData = new FormData()
formData.append('file', proofImage, proofImage.name)
formData.append('type', type)
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/upload`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/upload?${buildURLParams()}`
return fetch(url, {
method: 'POST',
headers: {
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`
},
}),
body: formData,
})
.then((response) => response.json())
Expand All @@ -47,179 +59,170 @@ export default {
getProofs(params = {}) {
const store = useAppStore()
const defaultParams = {page: 1, size: 10, order_by: '-created'}
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs?${new URLSearchParams({...defaultParams, ...params})}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs?${buildURLParams({...defaultParams, ...params})}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`
},
}),
})
.then((response) => response.json())
},

// will return only the user's proof
getProofById(proofId) {
const store = useAppStore()
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/${proofId}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/${proofId}?${buildURLParams()}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`
},
}),
})
.then((response) => response.json())
},

updateProof(proofId, params = {}) {
const store = useAppStore()
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/${proofId}`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/${proofId}?${buildURLParams()}`
return fetch(url, {
method: 'PATCH',
headers: {
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`,
'Content-Type': 'application/json',
},
}),
body: JSON.stringify(params),
})
.then((response) => response.json())
},

deleteProof(proofId) {
const store = useAppStore()
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/${proofId}`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/proofs/${proofId}?${buildURLParams()}`
return fetch(url, {
method: 'DELETE',
headers: {
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`
},
}),
})
// .then((response) => response.json())
},

createPrice(priceData) {
const store = useAppStore()
store.user.last_product_mode_used = priceData.product_code ? 'barcode' : 'category'
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices?${buildURLParams()}`
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${store.user.token}`
},
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`,
}),
body: JSON.stringify(priceData),
})
.then((response) => response.json())
},

getPrices(params = {}) {
const defaultParams = {page: 1, size: 10, order_by: '-created'}
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices?${new URLSearchParams({...defaultParams, ...params})}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices?${buildURLParams({...defaultParams, ...params})}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS,
})
.then((response) => response.json())
},

updatePrice(priceId, params = {}) {
const store = useAppStore()
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices/${priceId}`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices/${priceId}?${buildURLParams()}`
return fetch(url, {
method: 'PATCH',
headers: {
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`,
'Content-Type': 'application/json',
},
}),
body: JSON.stringify(params),
})
.then((response) => response.json())
},

deletePrice(priceId) {
const store = useAppStore()
return fetch(`${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices/${priceId}`, {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/prices/${priceId}?${buildURLParams()}`
return fetch(url, {
method: 'DELETE',
headers: {
headers: Object.assign({}, DEFAULT_HEADERS, {
'Authorization': `Bearer ${store.user.token}`
},
}),
})
// .then((response) => response.json())
},

getProducts(params = {}) {
const defaultParams = {page: 1, size: 10} // order_by default ?
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products?${new URLSearchParams({...defaultParams, ...params})}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products?${buildURLParams({...defaultParams, ...params})}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS,
})
.then((response) => response.json())
},

getProductById(productId) {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products/${productId}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products/${productId}?${buildURLParams()}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS,
})
.then((response) => response.json())
},

getProductByCode(productCode) {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products/code/${productCode}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products/code/${productCode}?${buildURLParams()}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS,
})
.then((response) => response.json())
},

getLocations(params = {}) {
const defaultParams = {page: 1, size: 10} // order_by default ?
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/locations?${new URLSearchParams({...defaultParams, ...params})}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/locations?${buildURLParams({...defaultParams, ...params})}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS,
})
.then((response) => response.json())
},

getLocationById(locationId) {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/locations/${locationId}`
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/locations/${locationId}?${buildURLParams()}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
headers: DEFAULT_HEADERS,
})
.then((response) => response.json())
},

openfoodfactsProductSearch(code) {
return fetch(`${OPENFOODFACTS_PRODUCT_URL}/${code}.json`, {
return fetch(`${constants.OFF_API_URL}/${code}.json`, {
method: 'GET',
headers: DEFAULT_HEADERS
})
.then((response) => response.json())
},

openstreetmapNominatimSearch(q) {
return fetch(`${constants.OSM_NOMINATIM_SEARCH_URL}?q=${q}&addressdetails=1&format=json&limit=10`, {
method: 'GET',
headers: DEFAULT_HEADERS
})
.then((response) => response.json())
.then((data) => data.filter(l => !constants.NOMINATIM_RESULT_TYPE_EXCLUDE_LIST.includes(l.type)))
},
openstreetmapPhotonSearch(q) {
return fetch(`${constants.OSM_PHOTON_SEARCH_URL}?q=${q}&limit=10`, {
method: 'GET',
headers: DEFAULT_HEADERS
})
.then((response) => response.json())
.then(data => data.features)
Expand Down
20 changes: 10 additions & 10 deletions tests/e2e/spec.cy.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
describe('Basic tests', () => {
beforeEach(() => {
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products?page=1&size=10&order_by=-price_count', { fixture: 'products.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products?page=1&size=10&code=3011360030498', { fixture: 'products_3011360030498.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products/code/3011360030498', { fixture: 'product_3011360030498.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products/code/0000000000000', { statusCode: 404, body: { "detail": "Product with code 35647000112700 not found" }})
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?page=1&size=1&order_by=-created*', { fixture: 'prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?page=1&size=10&order_by=-created', { fixture: 'prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?page=1&size=1&order_by=-date&product_code=3011360030498', { fixture: 'product_3011360030498_prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?page=1&size=10&order_by=-date&product_code=3011360030498', { fixture: 'product_3011360030498_prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?page=1&size=10&order_by=-date&category_tag=en%3Apitted-apricot', { fixture: 'pitted_apricot_prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?page=1&size=10&order_by=-date&category_tag=en%3Aaaaaaaaaaaaa', { body: {"items":[],"total":0,"page":1,"size":10,"pages":0} })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products?app_name=Open+Prices+Web+App&page=1&size=10&order_by=-price_count', { fixture: 'products.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products?app_name=Open+Prices+Web+App&page=1&size=10&code=3011360030498', { fixture: 'products_3011360030498.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products/code/3011360030498?app_name=Open+Prices+Web+App', { fixture: 'product_3011360030498.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/products/code/0000000000000?app_name=Open+Prices+Web+App', { statusCode: 404, body: { "detail": "Product with code 35647000112700 not found" }})
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?app_name=Open+Prices+Web+App&page=1&size=1&order_by=-created*', { fixture: 'prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?app_name=Open+Prices+Web+App&page=1&size=10&order_by=-created', { fixture: 'prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?app_name=Open+Prices+Web+App&page=1&size=1&order_by=-date&product_code=3011360030498', { fixture: 'product_3011360030498_prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?app_name=Open+Prices+Web+App&page=1&size=10&order_by=-date&product_code=3011360030498', { fixture: 'product_3011360030498_prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?app_name=Open+Prices+Web+App&page=1&size=10&order_by=-date&category_tag=en%3Apitted-apricot', { fixture: 'pitted_apricot_prices.json' })
cy.intercept('GET', 'http://127.0.0.1:8000/api/v1/prices?app_name=Open+Prices+Web+App&page=1&size=10&order_by=-date&category_tag=en%3Aaaaaaaaaaaaa', { body: {"items":[],"total":0,"page":1,"size":10,"pages":0} })
})

it('loads the home page', () => {
Expand Down

0 comments on commit 5a6af2f

Please sign in to comment.