mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
allow clients to filter content api call
This commit is contained in:
committed by
Sabe Jones
parent
ed790c1c4d
commit
39252c7828
@@ -1,4 +1,5 @@
|
|||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
|
import fs from 'fs';
|
||||||
import { langCodes } from '../../libs/i18n';
|
import { langCodes } from '../../libs/i18n';
|
||||||
import { CONTENT_CACHE_PATH, getLocalizedContentResponse } from '../../libs/content';
|
import { CONTENT_CACHE_PATH, getLocalizedContentResponse } from '../../libs/content';
|
||||||
|
|
||||||
@@ -6,6 +7,28 @@ const IS_PROD = nconf.get('IS_PROD');
|
|||||||
|
|
||||||
const api = {};
|
const api = {};
|
||||||
|
|
||||||
|
const CACHED_HASHES = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
const MOBILE_FILTER = `achievements,questSeriesAchievements,animalColorAchievements,animalSetAchievements,stableAchievements,
|
||||||
|
mystery,bundles,loginIncentives,pets,premiumPets,specialPets,questPets,wackyPets,mounts,premiumMounts,specialMounts,questMounts,
|
||||||
|
events,dropEggs,questEggs,dropHatchingPotions,premiumHatchingPotions,wackyHatchingPotions,backgroundsFlat,questsByLevel,gear.tree,
|
||||||
|
tasksByCategory,userDefaults,timeTravelStable,gearTypes,cardTypes`;
|
||||||
|
|
||||||
|
function hashForFilter (filter) {
|
||||||
|
let hash = 0;
|
||||||
|
let i; let
|
||||||
|
chr;
|
||||||
|
if (filter.length === 0) return '';
|
||||||
|
for (i = 0; i < filter.length; i++) { // eslint-disable-line
|
||||||
|
chr = filter.charCodeAt(i);
|
||||||
|
hash = ((hash << 5) - hash) + chr; // eslint-disable-line
|
||||||
|
hash |= 0; // eslint-disable-line
|
||||||
|
}
|
||||||
|
return String(hash);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /api/v3/content Get all available content objects
|
* @api {get} /api/v3/content Get all available content objects
|
||||||
* @apiDescription Does not require authentication.
|
* @apiDescription Does not require authentication.
|
||||||
@@ -65,14 +88,54 @@ api.getContent = {
|
|||||||
language = proposedLang;
|
language = proposedLang;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let filter = req.query.filter || '';
|
||||||
|
// apply defaults for mobile clients
|
||||||
|
if (filter === '') {
|
||||||
|
if (req.headers['x-client'] === 'habitica-android') {
|
||||||
|
filter = `${MOBILE_FILTER},appearance.background`;
|
||||||
|
} else if (req.headers['x-client'] === 'habitica-ios') {
|
||||||
|
filter = `${MOBILE_FILTER},backgrounds`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build usable filter object
|
||||||
|
const filterObj = {};
|
||||||
|
filter.split(',').forEach(item => {
|
||||||
|
if (item.includes('.')) {
|
||||||
|
const [key, subkey] = item.split('.');
|
||||||
|
if (!filterObj[key]) {
|
||||||
|
filterObj[key] = {};
|
||||||
|
}
|
||||||
|
filterObj[key][subkey.trim()] = true;
|
||||||
|
} else {
|
||||||
|
filterObj[item.trim()] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (IS_PROD) {
|
if (IS_PROD) {
|
||||||
res.sendFile(`${CONTENT_CACHE_PATH}${language}.json`);
|
const filterHash = language + hashForFilter(filter);
|
||||||
|
if (CACHED_HASHES.includes(filterHash)) {
|
||||||
|
// Content is already cached, so just send it.
|
||||||
|
res.sendFile(`${CONTENT_CACHE_PATH}${filterHash}.json`);
|
||||||
|
} else {
|
||||||
|
// Content is not cached, so cache it and send it.
|
||||||
|
res.set({
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
});
|
||||||
|
const jsonResString = getLocalizedContentResponse(language, filterObj);
|
||||||
|
fs.writeFileSync(
|
||||||
|
`${CONTENT_CACHE_PATH}${filterHash}.json`,
|
||||||
|
jsonResString,
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
CACHED_HASHES.push(filterHash);
|
||||||
|
res.status(200).send(jsonResString);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res.set({
|
res.set({
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
});
|
});
|
||||||
|
const jsonResString = getLocalizedContentResponse(language, filterObj);
|
||||||
const jsonResString = getLocalizedContentResponse(language);
|
|
||||||
res.status(200).send(jsonResString);
|
res.status(200).send(jsonResString);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,23 +5,31 @@ import packageInfo from '../../../package.json';
|
|||||||
|
|
||||||
export const CONTENT_CACHE_PATH = path.join(__dirname, '/../../../content_cache/');
|
export const CONTENT_CACHE_PATH = path.join(__dirname, '/../../../content_cache/');
|
||||||
|
|
||||||
function walkContent (obj, lang) {
|
function walkContent (obj, lang, removedKeys = {}) {
|
||||||
_.each(obj, (item, key, source) => {
|
_.each(obj, (item, key, source) => {
|
||||||
|
if (key in removedKeys && removedKeys[key] === true) {
|
||||||
|
delete source[key];
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_.isPlainObject(item) || _.isArray(item)) {
|
if (_.isPlainObject(item) || _.isArray(item)) {
|
||||||
walkContent(item, lang);
|
if (key in removedKeys && _.isPlainObject(removedKeys[key])) {
|
||||||
|
walkContent(item, lang, removedKeys[key]);
|
||||||
|
} else {
|
||||||
|
walkContent(item, lang);
|
||||||
|
}
|
||||||
} else if (_.isFunction(item) && item.i18nLangFunc) {
|
} else if (_.isFunction(item) && item.i18nLangFunc) {
|
||||||
source[key] = item(lang);
|
source[key] = item(lang);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function localizeContentData (data, langCode) {
|
export function localizeContentData (data, langCode, removedKeys = {}) {
|
||||||
const dataClone = _.cloneDeep(data);
|
const dataClone = _.cloneDeep(data);
|
||||||
walkContent(dataClone, langCode);
|
walkContent(dataClone, langCode, removedKeys);
|
||||||
return dataClone;
|
return dataClone;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocalizedContentResponse (langCode) {
|
export function getLocalizedContentResponse (langCode, removedKeys = {}) {
|
||||||
const localizedContent = localizeContentData(common.content, langCode);
|
const localizedContent = localizeContentData(common.content, langCode, removedKeys);
|
||||||
return `{"success": true, "data": ${JSON.stringify(localizedContent)}, "appVersion": "${packageInfo.version}"}`;
|
return `{"success": true, "data": ${JSON.stringify(localizedContent)}, "appVersion": "${packageInfo.version}"}`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user