Added quotes to NQL filters with ids (#18958)
refs https://github.com/TryGhost/Product/issues/4120 Updated some places where we don't add quotes around ids in NQL filters, which can be an issue when the id is a number
This commit is contained in:
parent
660f5fef6f
commit
14927ee24b
@ -124,7 +124,7 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}: {site
|
||||
browse({page, postId}: {page: number, postId: string}) {
|
||||
firstCommentsLoadedAt = firstCommentsLoadedAt ?? new Date().toISOString();
|
||||
|
||||
const filter = encodeURIComponent(`post_id:${postId}+created_at:<=${firstCommentsLoadedAt}`);
|
||||
const filter = encodeURIComponent(`post_id:'${postId}'+created_at:<=${firstCommentsLoadedAt}`);
|
||||
const order = encodeURIComponent('created_at DESC, id DESC');
|
||||
|
||||
const url = endpointFor({type: 'members', resource: 'comments', params: `?limit=5&order=${order}&filter=${filter}&page=${page}`});
|
||||
|
@ -4,15 +4,15 @@ const FEEDBACK_RELATION_OPTIONS = [
|
||||
];
|
||||
|
||||
export const AUDIENCE_FEEDBACK_FILTER = {
|
||||
label: 'Responded with feedback',
|
||||
name: 'newsletter_feedback',
|
||||
valueType: 'string',
|
||||
resource: 'email',
|
||||
label: 'Responded with feedback',
|
||||
name: 'newsletter_feedback',
|
||||
valueType: 'string',
|
||||
resource: 'email',
|
||||
relationOptions: FEEDBACK_RELATION_OPTIONS,
|
||||
feature: 'audienceFeedback',
|
||||
feature: 'audienceFeedback',
|
||||
buildNqlFilter: (filter) => {
|
||||
// Added brackets to make sure we can parse as a single AND filter
|
||||
return `(feedback.post_id:${filter.value}+feedback.score:${filter.relation})`;
|
||||
return `(feedback.post_id:'${filter.value}'+feedback.score:${filter.relation})`;
|
||||
},
|
||||
parseNqlFilter: (filter) => {
|
||||
if (!filter.$and) {
|
||||
|
@ -96,8 +96,8 @@ export default class Analytics extends Component {
|
||||
const values = [this.post.count.positive_feedback, this.post.count.negative_feedback];
|
||||
const labels = ['More like this', 'Less like this'];
|
||||
const links = [
|
||||
{filterParam: '(feedback.post_id:' + this.post.id + '+feedback.score:1)'},
|
||||
{filterParam: '(feedback.post_id:' + this.post.id + '+feedback.score:0)'}
|
||||
{filterParam: '(feedback.post_id:\'' + this.post.id + '\'+feedback.score:1)'},
|
||||
{filterParam: '(feedback.post_id:\'' + this.post.id + '\'+feedback.score:0)'}
|
||||
];
|
||||
const colors = ['#F080B2', '#8452f633'];
|
||||
return {values, labels, links, colors};
|
||||
@ -234,7 +234,7 @@ export default class Analytics extends Component {
|
||||
return link;
|
||||
});
|
||||
|
||||
const filter = `post_id:${this.post.id}+to:'${currentLink}'`;
|
||||
const filter = `post_id:'${this.post.id}'+to:'${currentLink}'`;
|
||||
let bulkUpdateUrl = this.ghostPaths.url.api(`links/bulk`) + `?filter=${encodeURIComponent(filter)}`;
|
||||
yield this.ajax.put(bulkUpdateUrl, {
|
||||
data: {
|
||||
@ -246,7 +246,7 @@ export default class Analytics extends Component {
|
||||
});
|
||||
|
||||
// Refresh links data
|
||||
const linksFilter = `post_id:${this.post.id}`;
|
||||
const linksFilter = `post_id:'${this.post.id}'`;
|
||||
let statsUrl = this.ghostPaths.url.api(`links/`) + `?filter=${encodeURIComponent(linksFilter)}`;
|
||||
let result = yield this.ajax.request(statsUrl);
|
||||
this.updateLinkData(result.links);
|
||||
@ -271,7 +271,7 @@ export default class Analytics extends Component {
|
||||
|
||||
@task
|
||||
*_fetchLinks() {
|
||||
const filter = `post_id:${this.post.id}`;
|
||||
const filter = `post_id:'${this.post.id}'`;
|
||||
let statsUrl = this.ghostPaths.url.api(`links/`) + `?filter=${encodeURIComponent(filter)}`;
|
||||
let result = yield this.ajax.request(statsUrl);
|
||||
this.updateLinkData(result.links);
|
||||
@ -286,7 +286,7 @@ export default class Analytics extends Component {
|
||||
|
||||
@task
|
||||
*_fetchMentions() {
|
||||
const filter = `resource_id:${this.post.id}+resource_type:post`;
|
||||
const filter = `resource_id:'${this.post.id}'+resource_type:post`;
|
||||
this.mentions = yield this.store.query('mention', {limit: 5, order: 'created_at desc', filter});
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ export default class Analytics extends Component {
|
||||
return link;
|
||||
});
|
||||
|
||||
const filter = `post_id:${this.post.id}+to:'${currentLink}'`;
|
||||
const filter = `post_id:'${this.post.id}'+to:'${currentLink}'`;
|
||||
let bulkUpdateUrl = this.ghostPaths.url.api(`links/bulk`) + `?filter=${encodeURIComponent(filter)}`;
|
||||
yield this.ajax.put(bulkUpdateUrl, {
|
||||
data: {
|
||||
@ -216,7 +216,7 @@ export default class Analytics extends Component {
|
||||
});
|
||||
|
||||
// Refresh links data
|
||||
const linksFilter = `post_id:${this.post.id}`;
|
||||
const linksFilter = `post_id:'${this.post.id}'`;
|
||||
let statsUrl = this.ghostPaths.url.api(`links/`) + `?filter=${encodeURIComponent(linksFilter)}`;
|
||||
let result = yield this.ajax.request(statsUrl);
|
||||
this.updateLinkData(result.links);
|
||||
@ -241,7 +241,7 @@ export default class Analytics extends Component {
|
||||
|
||||
@task
|
||||
*_fetchLinks() {
|
||||
const filter = `post_id:${this.post.id}`;
|
||||
const filter = `post_id:'${this.post.id}'`;
|
||||
let statsUrl = this.ghostPaths.url.api(`links/`) + `?filter=${encodeURIComponent(filter)}`;
|
||||
let result = yield this.ajax.request(statsUrl);
|
||||
this.updateLinkData(result.links);
|
||||
|
@ -3,8 +3,8 @@ import Component from '@glimmer/component';
|
||||
export default class FooterLinks extends Component {
|
||||
get feedbackLinks() {
|
||||
const post = this.args.post;
|
||||
const positiveLink = {filterParam: '(feedback.post_id:' + post.id + '+feedback.score:1)', label: 'More like this'};
|
||||
const negativeLink = {filterParam: '(feedback.post_id:' + post.id + '+feedback.score:0)', label: 'Less like this'};
|
||||
const positiveLink = {filterParam: '(feedback.post_id:\'' + post.id + '\'+feedback.score:1)', label: 'More like this'};
|
||||
const negativeLink = {filterParam: '(feedback.post_id:\'' + post.id + '\'+feedback.score:0)', label: 'Less like this'};
|
||||
|
||||
const data = [
|
||||
{link: positiveLink, hidden: !post.count.positive_feedback},
|
||||
|
@ -33,7 +33,7 @@ export default class HistoryEventFilter extends Helper {
|
||||
}
|
||||
|
||||
if (user) {
|
||||
filterParts.push(`actor_id:${user}`);
|
||||
filterParts.push(`actor_id:'${user}'`);
|
||||
}
|
||||
|
||||
return filterParts.join('+');
|
||||
|
@ -45,11 +45,11 @@ export default class MembersEventFilter extends Helper {
|
||||
}
|
||||
|
||||
if (member) {
|
||||
filterParts.push(`data.member_id:${member}`);
|
||||
filterParts.push(`data.member_id:'${member}'`);
|
||||
}
|
||||
|
||||
if (post) {
|
||||
filterParts.push(`data.post_id:${post}`);
|
||||
filterParts.push(`data.post_id:'${post}'`);
|
||||
}
|
||||
|
||||
return filterParts.join('+');
|
||||
|
@ -39,7 +39,7 @@ export default class MentionsRoute extends AuthenticatedRoute {
|
||||
let extension = undefined;
|
||||
|
||||
if (params.post_id) {
|
||||
paginationSettings.filter = `resource_id:${params.post_id}+resource_type:post`;
|
||||
paginationSettings.filter = `resource_id:'${params.post_id}'+resource_type:post`;
|
||||
} else {
|
||||
// Only return mentions with the same source once
|
||||
paginationSettings.unique = true;
|
||||
|
@ -78,7 +78,7 @@ const Comment = ghostBookshelf.Model.extend({
|
||||
// Enforce _blank and safe URLs
|
||||
transformTags: {
|
||||
a: sanitizeHtml.simpleTransform('a', {
|
||||
target: '_blank',
|
||||
target: '_blank',
|
||||
rel: 'ugc noopener noreferrer nofollow'
|
||||
})
|
||||
}
|
||||
@ -106,7 +106,7 @@ const Comment = ghostBookshelf.Model.extend({
|
||||
if (options.parentId === null) {
|
||||
return 'parent_id:null';
|
||||
}
|
||||
return 'parent_id:' + options.parentId;
|
||||
return 'parent_id:\'' + options.parentId + '\'';
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -904,7 +904,7 @@ Post = ghostBookshelf.Model.extend({
|
||||
ops.push(function updateRevisions() {
|
||||
return ghostBookshelf.model('MobiledocRevision')
|
||||
.findAll(Object.assign({
|
||||
filter: `post_id:${model.id}`,
|
||||
filter: `post_id:'${model.id}'`,
|
||||
columns: ['id']
|
||||
}, _.pick(options, 'transacting')))
|
||||
.then((revisions) => {
|
||||
@ -958,7 +958,7 @@ Post = ghostBookshelf.Model.extend({
|
||||
ops.push(async function updateRevisions() {
|
||||
const revisionModels = await ghostBookshelf.model('PostRevision')
|
||||
.findAll(Object.assign({
|
||||
filter: `post_id:${model.id}`,
|
||||
filter: `post_id:'${model.id}'`,
|
||||
columns: ['id', 'lexical', 'created_at', 'author_id', 'title', 'reason', 'post_status', 'created_at_ts', 'feature_image']
|
||||
}, _.pick(options, 'transacting')));
|
||||
|
||||
|
@ -616,7 +616,7 @@ describe('Comments API', function () {
|
||||
.expectEmptyBody();
|
||||
|
||||
// Check report
|
||||
const reports = await models.CommentReport.findAll({filter: 'comment_id:' + commentId});
|
||||
const reports = await models.CommentReport.findAll({filter: 'comment_id:\'' + commentId + '\''});
|
||||
reports.models.length.should.eql(1);
|
||||
|
||||
const report = reports.models[0];
|
||||
@ -641,7 +641,7 @@ describe('Comments API', function () {
|
||||
.expectEmptyBody();
|
||||
|
||||
// Check report should be the same (no extra created)
|
||||
const reports = await models.CommentReport.findAll({filter: 'comment_id:' + commentId});
|
||||
const reports = await models.CommentReport.findAll({filter: 'comment_id:\'' + commentId + '\''});
|
||||
reports.models.length.should.eql(1);
|
||||
|
||||
const report = reports.models[0];
|
||||
|
@ -567,7 +567,7 @@ describe('Batch sending tests', function () {
|
||||
// Test if all links are replaced and contain the member id
|
||||
const cheerio = require('cheerio');
|
||||
const $ = cheerio.load(html);
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:' + emailModel.get('post_id')});
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:\'' + emailModel.get('post_id') + '\''});
|
||||
|
||||
for (const el of $('a').toArray()) {
|
||||
const href = $(el).attr('href');
|
||||
@ -612,7 +612,7 @@ describe('Batch sending tests', function () {
|
||||
|
||||
const {emailModel, html} = await sendEmail(agent);
|
||||
assert.match(html, /\m=/);
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:' + emailModel.get('post_id')});
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:\'' + emailModel.get('post_id') + '\''});
|
||||
|
||||
for (const link of links) {
|
||||
// Check ref not added to all replaced links
|
||||
@ -627,7 +627,7 @@ describe('Batch sending tests', function () {
|
||||
|
||||
const {emailModel, html} = await sendEmail(agent);
|
||||
assert.match(html, /\m=/);
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:' + emailModel.get('post_id')});
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:\'' + emailModel.get('post_id') + '\''});
|
||||
|
||||
for (const link of links) {
|
||||
// Check ref not added to all replaced links
|
||||
@ -640,7 +640,7 @@ describe('Batch sending tests', function () {
|
||||
|
||||
const {emailModel, html} = await sendEmail(agent);
|
||||
assert.doesNotMatch(html, /\m=/);
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:' + emailModel.get('post_id')});
|
||||
const links = await linkRedirectRepository.getAll({filter: 'post_id:\'' + emailModel.get('post_id') + '\''});
|
||||
assert.equal(links.length, 0);
|
||||
});
|
||||
});
|
||||
|
@ -216,7 +216,7 @@ class BatchSendingService {
|
||||
async getBatches(email) {
|
||||
logging.info(`Getting batches for email ${email.id}`);
|
||||
|
||||
return await this.#models.EmailBatch.findAll({filter: 'email_id:' + email.id});
|
||||
return await this.#models.EmailBatch.findAll({filter: 'email_id:\'' + email.id + '\''});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -501,7 +501,7 @@ class BatchSendingService {
|
||||
* @returns {Promise<MemberLike[]>}
|
||||
*/
|
||||
async getBatchMembers(batchId) {
|
||||
let models = await this.#models.EmailRecipient.findAll({filter: `batch_id:${batchId}`, withRelated: ['member', 'member.stripeSubscriptions', 'member.products']});
|
||||
let models = await this.#models.EmailRecipient.findAll({filter: `batch_id:'${batchId}'`, withRelated: ['member', 'member.stripeSubscriptions', 'member.products']});
|
||||
|
||||
const BATCH_SIZE = this.#sendingService.getMaximumRecipients();
|
||||
if (models.length > BATCH_SIZE) {
|
||||
|
@ -26,7 +26,7 @@ class EmailSegmenter {
|
||||
}
|
||||
|
||||
getMemberFilterForSegment(newsletter, emailRecipientFilter, segment) {
|
||||
const filter = [`newsletters.id:${newsletter.id}`, 'email_disabled:0'];
|
||||
const filter = [`newsletters.id:'${newsletter.id}'`, 'email_disabled:0'];
|
||||
|
||||
switch (emailRecipientFilter) {
|
||||
case 'all':
|
||||
|
@ -37,7 +37,7 @@ describe('Email segmenter', function () {
|
||||
);
|
||||
listStub.calledOnce.should.be.true();
|
||||
listStub.calledWith({
|
||||
filter: 'newsletters.id:newsletter-123+email_disabled:0'
|
||||
filter: 'newsletters.id:\'newsletter-123\'+email_disabled:0'
|
||||
}).should.be.true();
|
||||
response.should.eql(12);
|
||||
});
|
||||
@ -94,7 +94,7 @@ describe('Email segmenter', function () {
|
||||
|
||||
listStub.calledOnce.should.be.true();
|
||||
listStub.calledWith({
|
||||
filter: 'newsletters.id:newsletter-123+email_disabled:0+(labels:test)+status:-free'
|
||||
filter: 'newsletters.id:\'newsletter-123\'+email_disabled:0+(labels:test)+status:-free'
|
||||
}).should.be.true();
|
||||
response.should.eql(12);
|
||||
});
|
||||
@ -118,7 +118,7 @@ describe('Email segmenter', function () {
|
||||
|
||||
listStub.calledOnce.should.be.true();
|
||||
listStub.calledWith({
|
||||
filter: 'newsletters.id:newsletter-123+email_disabled:0+(labels:test)+(status:free)'
|
||||
filter: 'newsletters.id:\'newsletter-123\'+email_disabled:0+(labels:test)+(status:free)'
|
||||
}).should.be.true();
|
||||
response.should.eql(12);
|
||||
});
|
||||
|
@ -154,7 +154,7 @@ class LinkClickTrackingService {
|
||||
|
||||
// manages transformation of current url to relative for comparision
|
||||
const transformedOldUrl = this.#urlUtils.absoluteToTransformReady(redirectUrl.href);
|
||||
const filterQuery = `post_id:${postId}+to:'${transformedOldUrl}'`;
|
||||
const filterQuery = `post_id:'${postId}'+to:'${transformedOldUrl}'`;
|
||||
|
||||
const updatedFilterOptions = {
|
||||
...filterOptions,
|
||||
|
@ -764,9 +764,9 @@ module.exports = class MemberRepository {
|
||||
if (data.action === 'unsubscribe') {
|
||||
const hasNewsletterSelected = (Object.prototype.hasOwnProperty.call(data, 'newsletter') && data.newsletter !== null);
|
||||
if (hasNewsletterSelected) {
|
||||
const membersArr = memberIds.join(',');
|
||||
const membersArr = memberIds.map(i => `'${i}'`).join(',');
|
||||
const unsubscribeRows = await this._MemberNewsletter.getFilteredCollectionQuery({
|
||||
filter: `newsletter_id:${data.newsletter}+member_id:[${membersArr}]`
|
||||
filter: `newsletter_id:'${data.newsletter}'+member_id:[${membersArr}]`
|
||||
});
|
||||
const toUnsubscribe = unsubscribeRows.map(row => row.id);
|
||||
|
||||
|
@ -127,7 +127,7 @@ export class PostRevisions {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async removeAuthorFromRevisions(authorId: string, options: any): Promise<void> {
|
||||
const revisions = await this.model.findAll({
|
||||
filter: `author_id:${authorId}`,
|
||||
filter: `author_id:'${authorId}'`,
|
||||
columns: ['id'],
|
||||
transacting: options.transacting
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user