Feathers: Customizing find() for two different queries - reactjs

I'm using FeathersJS and ReactJs to build an application and now I am stuck in a certain point.
The user interface I'm working on is a table and I have a navigation bar to control the data exhibited, like in the image.
In the select users may choose how many results they are going to see in a page. The navigation buttons move among different pages. Every time one of these thing change I calculate
let skip = (this.state.page - 1) * this.state.limit;
let url = '/users?$sort[name]=1&$skip=' + skip + '&$limit=' + this.state.limit;
and then make a REST call to Feathers backend. This is working perfectly well.
The red arrow indicates my problem.
When the user types part of a name in this input field I need to search the Users table to find all users with the typed string in the name, whatever the position and preferably case insensitive. In this case I am creating an url like
let url = '/users?name=<typed input'>;
and then making the REST call.
It happens that this call will try to find a name equal to , and this is not what I need. Then I am assuming I'll have to customize my find() method to perform differently when it receives the two different sets of parameters, like in
users.class.js
const { Service } = require('feathers-sequelize');
exports.Users = class Users extends Service {
find(data,params) {
if (data.query.name) {
// Do something to get the search I need
}
return super.find(data,params);
}
};
But I really don't know to proceed from this point on.
Should I implement a Sequelize raw query inside this if? What would be the best way to get the data I need?

This isn't really a Feathers question, or even a Sequelize question, but a database function. It depends on what your database is! For MySQL, you can use the LIKE command to search for a substring. Google how to make it case insensitive, if need. For the Sequelize query I believe something like this would work:
query = {
name: { $like: '%searchterm%'}
}

Related

Can you update firestore query dynamically based on router location?

So basically, I have a simple React app connected to Firebase that lists different types of food from firestore collections.
Example:
I have a few categories. The default one is "All" that displays top 8 popular dishes from all other available categories and this part is easy but I want an user to be able to click on other category and update my query.
Category is actually a NavLink that updates location on click so: if user click on "Pizza" category the url looks like this localhost:3000/Pizza if he clicks on Salad it is localhost:3000/Salad etc.
I have a "Wall" component that is a section and it displays those items from firestore.
My query ref in this wall component look like this: const foodRef = db.collection("food").doc("all").collection("items");
But I want to set .doc dynamically and make query on every update so I changed the query to something like that:
const location = useLocation();
const foodRef = db.collection("food").doc('${location.pathname}').collection("items");
And when user click on different Card (NavLink) url updates but query does not.
I know it is a bad solution but I actually have no idea how to do that.
I have read about Recursive Paths in react router but I do not know if it is what I am looking for.
If you know how to approach that please let me know.
Thanks for your time.
Firestore does not support wildcards or replacements in queries and Query objects are fully immutable (they can't be changed). You have to know the names of the documents and collections ahead of time to build a query. If you want to change some part of a query, you have to rebuild a whole new query object every time, and run the query again to get a new set results.

How to replicate gatsbyjs filter and search, like the one they have for their starters page?

I want to build a search page that lets user query data based on certain criteria that they can choose from select and radio checkboxes, on behalf of which a query string is generated that gives the key/value pair for searching, the functionality is somewhat similar to what they have for their staters page.
Please check the link below to get an idea of what I am looking for:
https://www.gatsbyjs.org/starters/?v=2 <---- query string.
These pages need to be shareable so query strings are essential and data fetching need be as quick as it is on their website.
From what I have understood so far, according to documentation:
https://www.gatsbyjs.org/docs/data-fetching
I have two options:
Get data during build time
Get data during run time
For a run time, I think, I would need to use redux-thunk to make network calls to an ExpressJs, MongoDB REST API but my concern is that it can be slow.
For build time, I am sure on how can I source data from Graphql queries, and render them.
Any help on this will be great. Thanks
The Gatsby Starters Library is parsing the URL param in this urlToSearch method in the PluginSearchBar component:
urlToSearch = () => {
if (this.props.location.search) { // get the params from the location prop
const match = /(\?|&)=([^&]+)/.exec(this.props.location.search)
if (match) return decodeURIComponent(match[2])
return ``
}
return ``
}
Mainly, it uses the Gatsby location prop (from #reach/router under the hood) to get the search keyword from the query string.
Search is then implemented client-side using Algolia's react-instantsearch library. You can find the complete implementation in plugin-searchbar-body.js.
There are naturally other ways to implement search. A good place to start for inspiration is Gatsby's Adding Search documentation.

Like/Dislike function for Firebase

The system itself is pretty easy to understand but tricky to implement. Moreover, security reasons made me think how to do that.
I was thinking to make the function work in frontend firebase scripts simply doing everything there as checking if there is already like/dislike posted by this user and remove/add/switch if user clicked. The problem lies in security of this method: can't user create a new function which won't check if the like was posted?
And if that's possible, how should this system work? Right now my logic:
Clicked like:
locally activate/deactivate like button and remove dislike active class if on
check docs for this user/doc like
`1`? -> remove this doc from collection
`0`? -> switch to `1`, because `0` is dislike
`undefined`? -> create doc with `vote: 1`
change (+1/-1 or +2/-2) the value of post votes fields
Same for dislike. But this sounds really complicated as for such a small feature. Maybe it is possible to wave additional collection with user/votes without losing that level of security? Or using http-triggers may help with this somehow? This feature would be much easier on some PHP-like languages, so I am freaking out right now.
Here are my assumptions.
You have a post with a unique id, let's call it post_id
You have a user with a unique id, let's call it user_id
There are 3 valid states: (Undefined), (Like), (Dislike)
Basic process follows
To store the likes/dislikes, you create a collection called feelings which uses post_id+':'+user_id as it's document id (this makes it easy to look up).
Documents in feelings have a single field called state that stores -1 for dislike, 1 for like.
As you mention, you can simply set or overwrite this value to whatever the user desires. If they decide to remove their 'feeling' and neither like or dislike, issue a delete command (this is cheaper than doing a write to set state to 0).
Use Cloud Functions to listen to the feelings collection and update the post documents like/dislike count based on how this state changes (or gets created/deleted).
Security Rules can enforce only allow states of -1 and 1, and if you're using Firebase Auth, you can trivially enforce only allowing the user matching user_id from being able to change state.
What have you got now?
You now have a system with the following properties:
Users can like and dislike posts
Users can remove and/or change their like/dislikes
Users can only like or dislike a post once - they cannot do it multiple times
Only valid states (like, dislike) can be written to the database
Only the user can update their likes/dislikes
Scalable: Whether it's 10 posts, or millions of posts, this system will work
Bonus credit
Using the same Cloud Functions event you register to update counts, you can also use this to add or remove from a list of user ids in both a like and dislike array. This would allow you to list out users who liked or disliked a post without have to query for each individual document in the feelings collection
Also remember that Cloud Functions has is a small chance it gets triggered more than once for a single event. If you want the counts to be guaranteed to be accurate, either make the code idempotent, or just have a manually triggered 'recount' process you can trigger if you or a user detects the counts seem off by one.
If somebody's wondering for Realtime Database!
var ref = firebase.database().ref(selectchapter + questionId + user_id);
ref.once("value", function (snapshot) {
var exists = snapshot.val() !== null;
if (!exists) {
firebase
.database()
.ref(
selectchapter +
questionId + user_id
)
.set({
status: 1
}).then(function () {
firebase.database().ref(q +
questionId + "likes").transaction(function (likes) {
return (likes || 0) + 1
});
});
}
});

Reflected XSS and Stored XSS in checmarx

I am having 2 pages
parent page consist a link, on click of this link i am calling an javascript function
function callPage( productId ){
var product = document.getElementById(ProductId).id;
var OpptyId = {!oppty.Id};
var urlToOpen = "/apex/" + '{!namespacePrefix}' + 'testPage?product='+product+'&OpptyId'=OpptyId ;
window.open(urlToOpen ,'','resizable=0,location=0,status=0,scrollbars=0,width=850,height=350,top=100,left=220')
}
where Oppty Id is taken from controller.
While in my child page I am getting all these paramiters as
ProductValueId = ApexPages.currentPage().getParameters().get('product');
opptyValue = ApexPages.currentPage().getParameters().get('OpptyId');
and these fields are then used in javascript as
function setValue()
{
var productId = '{!productValueId}';
window.parent.opener.document.getElementById(productId).value='{!productValue}';
}
where {!productValue} is taken from controller.
I am not understanding how and where should i make changes for soving my checkmarx issue.
So, please help me as I would want to submit the application for code review.
Best Regards
You are taking the query string parameter product, reading it into the productValueId controller member/property and then directly outputting it into the Visualforce page.
So basically whatever I give you on the query string ends up output into the page response.
With some effort it may be possible to encode a query string that will break out of your JavaScript and execute whatever I wan't.
E.g.
/apex/ABC__testPage?product=productId';alert('xss&OpptyId=006100000000001
Or something like that. To be fair, Visualforce will encode the expression for you.
Checkmarx has found the potential path. You will need to either remove this direct path or provide sufficient justification that it isn't open to XSS.
One helpful thing to do is enforce the data type on the values read from the query string. E.g. Explicitly use Id rather than string as the type for productValueId.
Then you could also verify that the records referenced in the query string params are actually valid for the current user. I.e. they haven't changed some of the values to gain access to records they otherwise shouldn't see.
Incidentally, the Salesforce StackExchange is a great place to ask Salesforce specific questions.

Write to multiple tables in joomla component?

I'm trying to create a component (front end) that uses multiple tables. I found 1 or 2 post that partially answer to the question but none really does. The point seems always simple and evident for the one who knows how to do it but it is never really explained (or I missed the right post).
In my component, the user enters data in one view that need to be stored in two tables:
the standard Joomla User table i.e. # __users
an additional table to store data that are not included in Joomla i.e. # __users_complements
I'm a beginner, so maybe I'm wrong, but I understood that the standard functions of joomla can only save results of a form in one table .
In my case, I guess that I have to override the standard functions in my model: com_component / model / my_model.php.
1) I'm confused because I do not really understand which function must be overrided: save ()? store ()? other?
2) Let's say I override the save() function, should I rewrite all the code to save data (explode the data array and create all the update queries) or should I create 2 standard table objects.
In this case, (2 objects) it seems weird to send each time the whole data array to the parent function as I know that a part is for table 1 and the other part for the table 2. I should be able to split before don't I?
3) Should I create 2 models and manage those models from my controller when I get back data from the form and call the save function of the model?
Could you help me to clarify how to do this saving in multiple tables?
An example with code will be very much appreciated.
Thank you
I finally made it. As I spent many hours on this and found that a lot of people where looking for an answer, here is how I did.
I suppose you know how to create a component, using the standard MVC structure:
Component entry point
Component controller
Eventually component router
Component view
Component model
Component controller
In model components\my_component\models\my_model.php create your own save function
public function save($data)
{
// Initialise variables.
$userId = (!empty($data['id'])) ? $data['id'] : (int)$this->getState('user.id');
$user = JFactory::getUser();
$table_one = $this->getTable('TableOne', 'MyComponentTable', array());
$table_two = $this->getTable('TableTwo', 'MyComponentTable', array());
// Bind the data.
if (!$table_one->bind($data))
{
$this->setError(JText::sprintf('USERS PROFILE BIND FAILED', $user->getError()));
return false;
}
if (!$table_two->bind($data))
{
$this->setError(JText::sprintf('USERS PROFILE BIND FAILED', $user->getError()));
return false;
}
// Store the data.
if (!$table_one->save($data))
{
$this->setError($user->getError());
return false;
}
if (!$table_two->save($data))
{
$this->setError($user->getError());
return false;
}
return $user->id;
}
Of course, you need the getTable function called in the save function
public function getTable($type = 'TableOne', $prefix = 'MyComponentTable', $config = array())
{
// call the administrator\components\com_mycomponent\tables\__tablename__.php
$this->addTablePath(JPATH_COMPONENT_ADMINISTRATOR . '/tables');
return JTable::getInstance($type, $prefix, $config);
}
And it works! So simple!
Of course, as I said in my question the whole $data is sent to the parent save() function to with data that are not necessary for table_one or table_two. It works this way with the standard joomla structure (no hack or direct query in the code).
Hope it helps.
There may be those out there who disagree with the way that the following method disrupts the MVC structure just a bit, but I've found it to be the simplest for me.
Typically, you have a model that fits one of the tables. In your example with pushing data to the users table as well as one in your component, I would add the following to the model for the table in your component:
public function save($data) {
if (!parent::save($data)) {
return false;
}
// add necessary code to save to the users table, since there isn't a standard way to do this that I'm aware of
// sometimes I will grab another model even
require_once(JPATH_BASE . '/administrator/components/com_users/models/user.php');
$other_model = $this->getInstance('user', 'UsersModel');
$other_model->save($data);
return true;
}
The first part of this function should save the data to the components table just like normal. But you can tack what you need on to the rest of the component to make whatever you like happen.
I would almost guarantee that there is a better way to chain models (and I've seen some of the changes happening in the Joomla Platform core that will lead to better ways in the future), but this should get you going for now.
In addition, for prompt 3, I would handle in the controller if you need to sometimes save just one table and sometimes save both. I've found that the save functions are pretty safe to run even when parts aren't loaded, so I usually just let it run.

Resources