fix(api-profile-filter): Fix several bugs filtering data in profile requests

profile-routes-options: Profile-related routes were not properly instantiating/passing a ProfileOptions object - this has now been fixed.
profile-options: Some of the logic for the ProfileOptions class was rewritten/reorganised for clarity and stability.
profile-v2: Because some fields were nullish, the conversion between v2 and v1 wasn't working properly. Now, everything checks for nullability AFAIK.
This commit is contained in:
tecc 2023-06-02 00:21:52 +02:00
parent 8bb0a7fde0
commit 5c68d11b80
No known key found for this signature in database
GPG Key ID: 400AAD881FCC028B
2 changed files with 65 additions and 59 deletions

View File

@ -7,12 +7,14 @@ const opinions = {
} }
const upgradeOpinionsListToV2 = (opinionsListV1) => { const upgradeOpinionsListToV2 = (opinionsListV1) => {
if (opinionsListV1 == null) return undefined;
return Object.entries(opinionsListV1).map(([value, opinion]) => { return Object.entries(opinionsListV1).map(([value, opinion]) => {
return { value, opinion: Object.keys(opinions).find(key => opinions[key] === opinion) }; return { value, opinion: Object.keys(opinions).find(key => opinions[key] === opinion) };
}); });
} }
const downgradeOpinionsListToV1 = (opinionsListV2) => { const downgradeOpinionsListToV1 = (opinionsListV2) => {
if (opinionsListV2 == null) return undefined;
const opinionsListV1 = {}; const opinionsListV1 = {};
for (let {value, opinion} of opinionsListV2) { for (let {value, opinion} of opinionsListV2) {
opinionsListV1[value] = opinions[opinion]; opinionsListV1[value] = opinions[opinion];
@ -21,12 +23,14 @@ const downgradeOpinionsListToV1 = (opinionsListV2) => {
} }
const upgradeCustomFlagsListToV2 = (customFlagListV1) => { const upgradeCustomFlagsListToV2 = (customFlagListV1) => {
if (customFlagListV1 == null) return undefined;
return Object.entries(customFlagListV1).map(([value, name]) => { return Object.entries(customFlagListV1).map(([value, name]) => {
return { value, name }; return { value, name };
}); });
} }
const downgradeCustomFlagsToV1 = (customFlagListV2) => { const downgradeCustomFlagsToV1 = (customFlagListV2) => {
if (customFlagListV2 == null) return undefined;
const customFlagListV1 = {}; const customFlagListV1 = {};
for (let {value, name} of customFlagListV2) { for (let {value, name} of customFlagListV2) {
customFlagListV1[value] = name; customFlagListV1[value] = name;
@ -39,7 +43,7 @@ module.exports.upgradeToV2 = (profileV1) => {
...profileV1, ...profileV1,
names: upgradeOpinionsListToV2(profileV1.names), names: upgradeOpinionsListToV2(profileV1.names),
pronouns: upgradeOpinionsListToV2(profileV1.pronouns), pronouns: upgradeOpinionsListToV2(profileV1.pronouns),
words: profileV1.words.map(column => { words: profileV1.words && profileV1.words.map(column => {
return {'header': null, 'values': upgradeOpinionsListToV2(column)}; return {'header': null, 'values': upgradeOpinionsListToV2(column)};
}), }),
customFlags: upgradeCustomFlagsListToV2(profileV1.customFlags), customFlags: upgradeCustomFlagsListToV2(profileV1.customFlags),
@ -51,7 +55,7 @@ module.exports.downgradeToV1 = (profileV2) => {
...profileV2, ...profileV2,
names: downgradeOpinionsListToV1(profileV2.names), names: downgradeOpinionsListToV1(profileV2.names),
pronouns: downgradeOpinionsListToV1(profileV2.pronouns), pronouns: downgradeOpinionsListToV1(profileV2.pronouns),
words: profileV2.words.map(({values}) => { words: profileV2.words && profileV2.words.map(({values}) => {
return downgradeOpinionsListToV1(values); return downgradeOpinionsListToV1(values);
}), }),
customFlags: downgradeCustomFlagsToV1(profileV2.customFlags), customFlags: downgradeCustomFlagsToV1(profileV2.customFlags),

View File

@ -72,10 +72,7 @@ class ProfileOptions {
enabled: true, enabled: true,
default_value: true default_value: true
}; };
locale_specific_props = { locale_specific_props = {};
enabled: true,
default_value: true
};
constructor(query_obj, locales) { constructor(query_obj, locales) {
if (query_obj == null) return; if (query_obj == null) return;
@ -84,13 +81,14 @@ class ProfileOptions {
this.default_props = ProfileOptions._parse_props(default_props) this.default_props = ProfileOptions._parse_props(default_props)
if (locales != null) { if (locales != null) {
for (const key of Object.keys(locales)) { for (const locale of Object.values(locales)) {
const key = locale.code.toLowerCase(); // i'm purely paranoid here
const lprops_obj = query_obj["lprops"]; const lprops_obj = query_obj["lprops"];
let props; let props;
if (typeof lprops_obj === "object") { if (typeof lprops_obj === "object") {
props = lprops_obj[key]; props = lprops_obj[key];
} else { } else {
props = query_obj[`lprops.${key.toLowerCase()}`]; props = query_obj[`lprops.${key}`];
} }
if (props != null) { if (props != null) {
this.locale_specific_props[key] = ProfileOptions._parse_props(props); this.locale_specific_props[key] = ProfileOptions._parse_props(props);
@ -102,13 +100,16 @@ class ProfileOptions {
} }
static _parse_props(raw_param) { static _parse_props(raw_param) {
if (raw_param) { if (raw_param == null) {
return {
enabled: true,
default_value: true
}
}
/** @type {Array<string>} */ /** @type {Array<string>} */
let properties; let properties;
let default_value = false; let default_value = false;
const obj = { const obj = {};
default_value
};
if (Array.isArray(raw_param)) { if (Array.isArray(raw_param)) {
properties = raw_param properties = raw_param
} else if (typeof raw_param == "object") { } else if (typeof raw_param == "object") {
@ -118,25 +119,27 @@ class ProfileOptions {
default_value: false, default_value: false,
} }
} else if (typeof raw_param === 'string') { } else if (typeof raw_param === 'string') {
if (raw_param === "none") { switch (raw_param) {
case "none":
// Don't show the locale at all // Don't show the locale at all
return { return {
enabled: false, enabled: false,
default_value: false default_value: false
} }
} else if (raw_param === "empty") { case "empty":
// Include it as an object, but don't include any data // Include it as an object, but don't include any data
return { return {
enabled: true, enabled: true,
default_value: false default_value: false
} }
} else if (raw_param === "all") { case "all":
// All properties should be shown // All properties should be shown
return { return {
enabled: true, enabled: true,
default_value: true default_value: true
} }
} }
// console.log("unrecognised: ", raw_param)
properties = raw_param.split(','); properties = raw_param.split(',');
} }
@ -147,17 +150,15 @@ class ProfileOptions {
return { return {
...obj, ...obj,
enabled: true, enabled: true,
default_value
}; };
} else {
return {
enabled: true,
default_value: true
}
}
} }
_data_for(locale) { _data_for(locale) {
if (typeof locale != "string") {
throw new Error("Locale must be string")
}
return this.locale_specific_props[locale] ?? this.default_props; return this.locale_specific_props[locale] ?? this.default_props;
} }
@ -174,8 +175,10 @@ class ProfileOptions {
* @return {boolean} * @return {boolean}
*/ */
prop(locale, property) { prop(locale, property) {
if (!this.show_at_all(locale)) return false;
// it's duplicate data getting (show_at_all also calls _data_for),
// but it's not that important to optimise
const data = this._data_for(locale); const data = this._data_for(locale);
if (!(data.enabled ?? true)) return false;
return data[property] ?? data.default_value ?? true; return data[property] ?? data.default_value ?? true;
} }
@ -225,7 +228,7 @@ const fetchProfiles = async (db, username, self, opts) => {
const p = {} const p = {}
for (let profile of profiles) { for (let profile of profiles) {
if (!opts.show_at_all(profile)) continue; if (!opts.show_at_all(profile.locale)) continue;
const links = JSON.parse(profile.links).map(l => normaliseUrl(l)).filter(l => !!l); const links = JSON.parse(profile.links).map(l => normaliseUrl(l)).filter(l => !!l);
const linksMetadata = {}; const linksMetadata = {};
for (let link of await db.all(SQL`SELECT * FROM links WHERE url IN (`.append(links.map(k => `'${k.replace(/'/g, "''")}'`).join(',')).append(SQL`)`))) { for (let link of await db.all(SQL`SELECT * FROM links WHERE url IN (`.append(links.map(k => `'${k.replace(/'/g, "''")}'`).join(',')).append(SQL`)`))) {
@ -236,8 +239,7 @@ const fetchProfiles = async (db, username, self, opts) => {
}; };
} }
const propv = (property, value) => opts.propv(profile.locale, property, value);
const propv = (key, value) => opts.propv(profile, key, value);
const profile_obj = { const profile_obj = {
opinions: propv("opinions", () => JSON.parse(profile.opinions)), opinions: propv("opinions", () => JSON.parse(profile.opinions)),