how to redirect to a url with dynamic parameter with declarativeNetRequest rule in chrome exension? [duplicate] - google-chrome-extension

I need to get the url of a chrome tab when it's navigated but before the user is redirected from a rule that is set using declarativeNetRequest.
At the moment the user can add a rule using context menu, it will be redirected to an internal extension page when try to visit the filtered host.
chrome.contextMenus.onClicked.addListener( ( clickData) => {
switch (clickData.menuItemId) {
case 'blockHost':
blockHost(clickData)
console.log('Added host')
break;
case 'unblockHost':
unblockHost(clickData)
chrome.declarativeNetRequest.getDynamicRules( rules => console.log(rules) )
console.log('Removed host')
break;
}
})
const blockHost = async (clickData) => {
let hostname = new URL(clickData.pageUrl).hostname
console.log(hostname)
let rules = await chrome.declarativeNetRequest.getDynamicRules()
console.log(rules.length, rules)
let newRule = await chrome.declarativeNetRequest.updateDynamicRules({
addRules: [{
id: rules.length + 1,
action: {type: 'redirect', redirect: {extensionPath: '/forbidden.html'}},
condition: {urlFilter: `${hostname}/`, resourceTypes: ['main_frame', 'sub_frame']}
}]
});
console.log(newRule)
let updatedRules = await chrome.declarativeNetRequest.getDynamicRules()
console.log('blockedhost executed', updatedRules)
}
since the user is redirected, it's impossible for me at the moment to remove a certain url. My idea is to get the url before the redirection is occur, but how I can do this?

Use regexFilter + substitution to append the original URL to extension page URL:
const EXT_PAGE = chrome.runtime.getURL('/forbidden.html');
const RULES = [{
id: 1,
action: {
type: 'redirect',
redirect: { regexSubstitution: EXT_PAGE + '#\\0' },
},
condition: {
requestDomains: ['example.com'], // remove this line to match all sites
regexFilter: '^.+$',
resourceTypes: ['main_frame', 'sub_frame'],
},
}];
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: RULES.map(r => r.id),
addRules: RULES,
});
Now your extension page (forbidden.html) can read this URL:
const origUrl = location.hash.slice(1);
You can also hide the original URL from the address bar:
history.replaceState(document.title, null, location.href.split('#')[0]);
Hopefully there'll be a better solution if https://crbug.com/1241397 is implemented.

Related

Wrong redirect when I use declarativeNetRequest.updateDynamicRules [duplicate]

I need to get the url of a chrome tab when it's navigated but before the user is redirected from a rule that is set using declarativeNetRequest.
At the moment the user can add a rule using context menu, it will be redirected to an internal extension page when try to visit the filtered host.
chrome.contextMenus.onClicked.addListener( ( clickData) => {
switch (clickData.menuItemId) {
case 'blockHost':
blockHost(clickData)
console.log('Added host')
break;
case 'unblockHost':
unblockHost(clickData)
chrome.declarativeNetRequest.getDynamicRules( rules => console.log(rules) )
console.log('Removed host')
break;
}
})
const blockHost = async (clickData) => {
let hostname = new URL(clickData.pageUrl).hostname
console.log(hostname)
let rules = await chrome.declarativeNetRequest.getDynamicRules()
console.log(rules.length, rules)
let newRule = await chrome.declarativeNetRequest.updateDynamicRules({
addRules: [{
id: rules.length + 1,
action: {type: 'redirect', redirect: {extensionPath: '/forbidden.html'}},
condition: {urlFilter: `${hostname}/`, resourceTypes: ['main_frame', 'sub_frame']}
}]
});
console.log(newRule)
let updatedRules = await chrome.declarativeNetRequest.getDynamicRules()
console.log('blockedhost executed', updatedRules)
}
since the user is redirected, it's impossible for me at the moment to remove a certain url. My idea is to get the url before the redirection is occur, but how I can do this?
Use regexFilter + substitution to append the original URL to extension page URL:
const EXT_PAGE = chrome.runtime.getURL('/forbidden.html');
const RULES = [{
id: 1,
action: {
type: 'redirect',
redirect: { regexSubstitution: EXT_PAGE + '#\\0' },
},
condition: {
requestDomains: ['example.com'], // remove this line to match all sites
regexFilter: '^.+$',
resourceTypes: ['main_frame', 'sub_frame'],
},
}];
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: RULES.map(r => r.id),
addRules: RULES,
});
Now your extension page (forbidden.html) can read this URL:
const origUrl = location.hash.slice(1);
You can also hide the original URL from the address bar:
history.replaceState(document.title, null, location.href.split('#')[0]);
Hopefully there'll be a better solution if https://crbug.com/1241397 is implemented.

How to get random records from Strapi v4 ? (I answered this question)

Strapi doesn't have any endpoint to get random data for this purpose you should write some custom code for your endpoint
custom route for that endpoint you want
// path: ./src/api/[your-endpiont]/routes/[custom-route].js
module.exports = {
"routes": [
{
"method": "GET",
"path": "/[your-endpiont]/random", // you can define everything you want for url endpoint
"handler": "[your-endpiont].random", // random is defined as a method
"config": {
"policies": []
}
}
]
}
now you have to run yarn develop or npm ... to display a random method in your strapi panel
Save this setting and retry to reach the random endpoint.
create a function as a service for getting random data in your endpoint API services.
// path: ./src/api/[your-endpiont]/services/[your-endpiont].js
'use strict';
/**
* news-list service.
*/
const { createCoreService } = require('#strapi/strapi').factories;
module.exports = createCoreService('api::news-list.news-list', ({ strapi }) => ({
async serviceGetRandom({ locale, id_nin }) { // these parametrs come from query
function getRandomElementsFromArray(array, numberOfRandomElementsToExtract = 1) {
const elements = [];
function getRandomElement(arr) {
if (elements.length < numberOfRandomElementsToExtract) {
const index = Math.floor(Math.random() * arr.length)
const element = arr.splice(index, 1)[0];
elements.push(element)
return getRandomElement(arr)
} else {
return elements
}
}
return getRandomElement([...array])
}
const newsListArray = await strapi
.db
.query("api::news-list.news-list")
.findMany({
where: {
locale: locale, // if you have multi-language data
$not: {
id: id_nin, // depend on where this endpoint API use
},
publishedAt: {
$notNull: true,
},
},
sort: [{ datetime: 'asc' }],
limit: 10,
populate: {
content: {
populate: {
thumbnail: true,
},
},
},
//? filter object throws an error when you used populate object, everything you want to filter properly best write into where{}
// filters: {
// publishedAt: {
// $notNull: true,
// },
// locale: locale
// }
})
if (!newsListArray.length) {
return null
}
return getRandomElementsFromArray(newsListArray, 2)
}
}));
explain code:
Strapi provides a Query Engine API to interact with the database layer at a lower level
strapi.db.query("api::news-list.news-list").findMany({})
The Query Engine allows operations on database entries,
I wrote this for my purpose probably you should change based on what you needed
{
where: {
locale: locale,
$not: {
id: id_nin
},
publishedAt: {
$notNull: true,
},
},
sort: [{ datetime: 'asc' }],
limit: 10,
populate: {
content: {
populate: {
thumbnail: true,
},
},
}
}
when you get data from your query, passed it to that function getRandomElementsFromArray(newsListArray, 2) to get some random item (how many random items do you want ? pass the second parameter)
At least if your array is null return null otherwise return data
create the controller
Controllers are JavaScript files that contain a set of methods, called actions, reached by the client according to the requested route so we going to call our services in this section
// path: ./src/api/[your-endpoint]/controllers/[your-endpoint].js
'use strict';
/**
* news-list controller
*/
const { createCoreController } = require('#strapi/strapi').factories;
module.exports = createCoreController('api::news-list.news-list', ({ strapi }) => ({
async random(ctx) { // name of this methods related to something we define in route ("handler": "[your-endpiont].random",)
const entity = await strapi.service('api::news-list.news-list').serviceGetRandom(ctx.query) // call our services, you can send all query you get from url endpoint (notice that you should write your endpoint api in strapi.service("your-endpoint"))
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
return this.transformResponse(sanitizedEntity);
// console.log(entity);
}
}));
I call this endpoint in my project nextjs & stapi cms
export const getRandomNewsItem = (id, locale) => {
return API
.get(`/news-list/random?locale=${locale}&id_nin=${id}`)
.then(res => res.data);
};
That's it, I'll hope you all get what to do
all resources you need
https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html#creating-custom-routers
https://docs.strapi.io/developer-docs/latest/development/backend-customization/services.html#implementation
https://docs.strapi.io/developer-docs/latest/development/backend-customization/controllers.html#adding-a-new-controller
https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/query-engine-api.html
https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/query-engine/filtering.html#and
https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service/order-pagination.html#ordering
https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/entity-service/order-pagination.html#ordering
https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/query-engine/populating.html

Change the line height of all content in a Google doc using the API via nodejs using batchupdate()

Using Method: documents.get I can retrieve a document. The result is structured as described at Resource: documents.
However, I need to select the whole document and change the line-height to 1.5, but I am unable to find a way to do it.
var updateObject = {
documentId: documentId,
resource: {
requests: [{
'updateTextStyle': {
'range': {
'startIndex': 1,
'endIndex': 0
},
'textStyle': {
'line-height': 1.5
},
'fields': 'line-height'
}
}],
},
};
docs.documents.batchUpdate(updateObject)
.then(function(res) { // Modified
console.log(res);
}, function(err) {
console.error(err);
});
Get your document and calculate start and end indexes of all paragraphs within the body.
Issue updateParagraphStyle request for each of the above paragraphs with linespacing as 150 for 1.5 times the normal space.
I managed to do this using Google Apps Script...
function setLineHeight() {
var d = DocumentApp.getActiveDocument();
var b = d.getBody()
var pars = b.getParagraphs();
// for each paragraph in the active document...
pars.forEach(function(e) {
// clean up paragraphs that only contain whitespace
e.setLineSpacing(1.5);
})
}

Node Elasticsearch module search not returning results

I'm setting up a project with node (v 12.4.0) and elasticsearch (7.4.0) using the official module.
I'm attempting to search using
import { Client, RequestParams, ApiResponse } from '#elastic/elasticsearch'
const client = new Client({ node: 'http://localhost:9200' })
const params: RequestParams.Search = { index: 'doc', body: { query: { match: { title: "castle" } } } };
const response: ApiResponse = await client.search(params);
This gives a 200 response, but no results.
Attempting the same thing using Postman returns the 1 result.
POST http://localhost:9200/doc/_search
{
"query": {
"match": { "title": "castle" }
}
}
I'm not having any luck figuring out why the search function is not working. I've also tested get, add, and delete, which all work.
To create the index, I used:
await client.indices.create({ index: "doc" });
To add a document, I use:
await client.index({
index: 'doc',
body: {
title: "Castle Title",
body: "This is text that is not the title."
}
});
What am I doing wrong?
I've tested this and it works, the only thing is that elasticsearch is near real-time searchable. You need to wait 1 second before the document becomes searchable.
Basically, if you are running a test or something, where you save the record just before searching you need to either:
wait for 1 second before searching
trigger a manual refresh https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html
wait for it to be refreshed when saving https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-refresh.html

Why is the apostrophe-pages _children array is always empty?

I am trying to get the children of apostrophe pages to appear in my navigation object - however the _children array is always empty. My page does have child pages set up via the front end Pages UI.
My index.js for the lib/modules/apostrophe-pages module contains the following:
construct: function(self,options) {
// store the superclass method and call at the end
var superPageBeforeSend = self.pageBeforeSend;
self.pageBeforeSend = function(req, callback) {
// Query all pages with top_menu setting = true and add to menu collection
self.apos.pages.find(req, { top_menu: true }, {slug: 1, type: 1, _id: 1, title: 1})
.children(true)
.toArray(
function (err, docs) {
if (err) {
return callback(err);
}
req.data.navpages = docs;
return superPageBeforeSend(req, callback);
});
};
},
...
My top_menu attribute is set via apostrophe-custom-pages:
module.exports = {
beforeConstruct: function(self, options) {
options.addFields = [
{
name: 'subtitle',
label: 'Subtitle',
type: 'string'
},
{
name: 'css_class',
label: 'CSS Class',
type: 'string'
},
{
name: 'top_menu',
label: 'Include In Top Menu',
type: 'boolean'
}
].concat(options.addFields || []);
}
};
This gives me the pages I need with the top_menu setting.. but I want to get child pages too..
When debugging the code I can see that the docs._children array is present but is always empty, even though a page has child pages...
I have tried adding the following both to my app.js and to my index.js but it doesn't change the result:
filters: {
// Grab our ancestor pages, with two levels of subpages
ancestors: {
children: {
depth: 2
}
},
// We usually want children of the current page, too
children: true
}
How can I get my find() query to actually include the child pages?
Solved it..
I needed to add 'rank: 1, path: 1, level: 1' to the projection as per this page in the documentation: https://apostrophecms.org/docs/tutorials/howtos/children-and-joins.html#projections-and-children

Resources