How to get only one user instead of a list? - javascript

I try to get from a list of users to only one user and display his profile on another page.
I want to do so with the routerLink and passing on an id of this specific user to the next page.
The routing is working, Im directed to the profile page but when I log the results of the http request I still get back the whole list of users like in the users page instead of the details of one user.
I have tried many things like changing the path of the url in my user.service.ts but that didn't solve the problem I even got 404 request errors when using this path ${this.url}/users/${id}/ instead of ${this.url}/users/?i=${id}/ (where its working).
The api docs is saying though that in order to retrieve one single user its http://1234//users/{id}/ it this scheme while id is an integer. But when I want to apply that scheme I get the 404 error.
Thats why I have to use the ?I= version but there the problem is I only get the full list of users on the next page.
MY CODE:
user.service.ts
// get a user's profile
getUserDetails(id): Observable<any> {
return this.http.get(`${this.url}/users/?i=${id}/`); // why add ?i
}
user.page.ts
// get all users in the users page
getAllUsers() {
this.userList = this.userService.getList()
.pipe(map(response => response.results));
}
user.page.html
<ion-avatar class="user-image" slot="start" [routerLink]="['/','profile', 'user.id']">
<ion-img src="assets/22.jpeg"> </ion-img>
</ion-avatar>
profile.page.ts
information = null;
...
ngOnInit() {
// Get the ID that was passed with the URL
let id = this.activatedRoute.snapshot.paramMap.get('id');
// Get the information from the API
this.userService.getUserDetails(id).subscribe(result => {
this.information = result;
console.log(result);
});
}

It seems like the url is wrong. If it was me I would console.log the url and compare it to the docs. Heres a snippet to try a few variations:
const id = 1;
const options = [
`${this.url}/users/?i=${id}/`,
`${this.url}/users/?i=${id}`,
`${this.url}/users/i/${id}/`,
`${this.url}/users/i/${id}`,
`${this.url}/user/?i=${id}/`,
`${this.url}/user/?i=${id}`,
`${this.url}/user/i/${id}/`,
`${this.url}/user/i/${id}`,
];
for (const option of options) {
try {
const response = await this.http.get(option);
console.log(options, response);
} catch (e) {
}
}
I would also consider dropping the second http request. If the first request returns all the required data you could just store it in a variable on the service.

Related

Let Strapi CMS create pages based on html template file

So probably my explanation is awful, but i really don’t know how to express my problem or what to search for.
I got a site (www.example.com/blog.html) showing all blog post entries created in a headless cms (Strapi). The site receives the posts by making an url request and parsing the resulting JSON data. This data also contains an unique url slug for each post serving as an identifier.
I want to create one page for each blog post created in the headless cms based on a „template“ html.
What I tried is passing the urlslug as a url parameter (www.example.com/blog/article.html?id=*URLSLUG*) and then using this url parameter to fetch the corresponding post data from the cms. I followed this guide: https://strapi.io/blog/build-an-editorial-website-with-vanilla-java-script-and-strapi
It works, but I don’t want to rely on url parameters for seo reasons. Instead I want something like www.example.com/blog/*URLSLUG*. In other words: I want to have one page for each blog post entry in my headless cms based on a „template“ html.
Any suggestions?
Code can be added if necessary
well there is few options here:
The first one is most reliable, and easy but seems not that fancy as you want:
https://market.strapi.io/plugins/strapi-plugin-slugify
The main reason to use this solution is that it handles slug creation when you create post via REST api. The uuid field needs extra work when post created not from admin panel.
So second option is do it yourself style:
/api/article/controller/article.js
module.exports = createCoreController('api::article.article', ({strapi}) => ({
findOne(ctx){
const { slug } = ctx.params;
return strapi.db.query('api::article.article').findOne({where: {slug});
}
});
then in the routes create routes.js file
/api/article/routes/routes.js
module.exports = {
routes: [
{
method: 'GET',
path: '/articles/:slug'
handler: 'article.findOne'
}
]
}
then if you want to create articles for outside of admin, create lifecycles.js in
/api/article/content-types/article/lifecycles.js
module.exports = {
async beforeCreate(event) {
// here you have to do something like
let slug = slugify(event.result.name);
let isNotFree = await strapi.db.query("api::article.article").findOne({where: {slug}});
if (Boolean(!isNotFree)) // < not sure prolly need an empty object check
for (let i = 1; i < 9999 ; i++) {
slug = `${slug}-${i}`;
isNotFree = await strapi.db.query("api::article.article").findOne({where: {slug}});
if (Boolean(!isNotFree))
break;
}
event.result.slug = slug
}
}
pleas note the lifecycle code is just a first thing came to my mind, should be tested and optimized prolly
the implementation gives you the findOne controller, you gonna need to do it for each other update, delete, etc...

How to fetch a single data value out of firebase database with reactjs

Im working on a project trying to fetch a name of the current user that is logged in.
When we create a user its getting added in the database with a unique id as row name.
Here you can see all the users that are registered but i only want the one that is logged in so i can pick the first and last name to say "Hello (bla) (bla)"
The code i have now it this :
import React from "react"
import { auth, database } from '../../handlers/Firebase'
export default function Dashboard() {
const user = auth.currentUser
const refUserInformation = database.ref('UserInformation/')
refUserInformation.on('value', function(data){
console.log(data.val())
})
return (
<div className="page-dashboard">
<div className="maxtext">
<p>userid: {user.uid}</p>
<p>Naam: </p>
</div>
</div>
)
}
Can just someone help me out with fetching the logged in user (so not a loop)
In summary, the problem is that I currently get all users back in my console log, but I only need the one that is logged in and on the appropriate dashboard. I would like to post this name (not with a loop but a single request)
To get just the user with a given user_id value, you will have to use a query:
const refUserInformation = database.ref('UserInformation/')
const currentUserQuery = refUserInformation.orderByChild('user_id').equalTo(user.uid);
currentUserQuery.on('value', function(snapshot){
snapshot.forEach((data) => {
console.log(data.val())
});
})
In general, I'd recommend storing user information with the UID as the key. That way:
Each UID can by definition occur only once in the database, since keys are unique under a parent node.
Looking up the user info by their UID becomes simpler, since you won't need a query.
To store the user under their UID use refUserInformation.child(user.uid).set(...) instead of refUserInformation.push(..).

Is it possible to validate user in backend without user providing credientals?

I need to make a page with a button that fills certain text area with data from database. However I need it to also require administrator privileges.
Is it possible to have an API method that doesn't require credientals, but an Identity session instead? Ideally something that gets a HttpContext.User?
I don't know anything about JavaScript, I managed to put together this thing:
const url = '/api/clients/';
function getItems() {
fetch(url + document.getElementById('input').value)
.then(response => response.json())
.then(data => _displayItems(data));
}
function _displayItems(arrayOfResults) {
const textbox = document.getElementById('textbox');
textbox.value = "";
arrayOfResults.forEach(json => {
textbox.value += json.deviceIdentifier + "\n";
});
}
I have an API endpoint at http://localhost/api/clients/{string} that does a database query and it works as expected. But I can not allow just about anybody to access that data and I have trouble figuring out how to make user:
not provide his credentials
be able to use it with minimal effort (ie. just click the button and get results)
be unable to use this endpoint while not currently logged in on the website
Normally I just use this line to get the user that tries to access the controller:
var currentUser = await _userManager.FindByNameAsync(_userManager.GetUserName(HttpContext.User));
and go from there. But when my JS script is accessing the API it doesn't provide a way to validate using HttpContext, from what I'm seeing.

Most browsers do not 'remember' the result of Ajax request when going back to page

I have a page with a form that gives a user the option to filter a list of objects (programs) by selecting options. For example, they could select the option architecture to show only the programs which contain that subject. An AJAX-request is sent to the server, which then returns the results. So far, everything works.
My problem: in some browser when someone clicks to go to another page and then goes back to the page where the form is, the results are reset, although the form selection(s) are still visible. In Chrome this is a problem, whereas in Firefox this does not happen. On this page you can see a live example.
My JavaScript AJAX post-request looks like this:
let sendQuery = () => {
let programsList = document.getElementById('programs-list');
axios.post('/programs/getByFilter', filter )
.then(function (response) {
programsList.innerHTML = response.data;
})
.catch(function (error) {
console.log(error);
});
}
And then in PHP (I use Symfony):
/**
* #Route("/getByFilter", name="program_get_by_filter")
*/
public function returnProgramsByFilter(Request $request, SearchHelper $searchHelper)
{
$jsonFilter = $request->getContent();
$filter = json_decode($jsonFilter, true);
// the query is done here.
$programs = $searchHelper->findByFilter($filter);
return $this->render('program/programs_ajax.html.twig', [
'programs' => $programs ]);
}
Now I have looked for similar questions and found this one and this one, but I haven't been able to solve the problem. Initially I tried to send the request as a GET-request instead of a POST-request, but the data I send is JSON and I did not manage to make it work. I am not really sure if that has to do with the JSON or not. My understanding of JS is really poor. Then I tried with a session variable like so:
$jsonFilter = $request->getContent();
$filter = json_decode($jsonFilter, true);
$session->set('filter', $filter);
And then:
if($session->has('filter')){
$programs = $searchHelper->findByFilter($session->get('filter'));
} else {
$programs = $programRepository->findAll();
}
This does not really work either because the original options will be overwritten when going back and making a new selection. Also, with my JS I show the current filters that are being used and the number of results. That's gone too.
Is there a JS solution or should I try to fix this in PHP?
Update:
I have been able to set filter as a cookie every time an ajax call is made by making it a string with JSON.stringify(filter) and then I get it and use it with:
// Getting the cookie, parsing it and running the query.
var filterCookie = getCookie('filter');
if (filterCookie) {
var objectCookieFilter = JSON.parse(filterCookie);
let programsList = document.getElementById('programs-list');
axios
.post('/programs/getByFilter', objectCookieFilter )
.then(function (response) {
programsList.innerHTML = response.data;
})
.catch(function (error) {
console.log(error);
});
}
This will re-run the last query that was set in the cookie. The problem that remains though is that all the filter-badges are set on a change event of the checkboxes and I cannot figure out how to show them based on the cookie (or perhaps some other way?)

Node-Craigslist syntax for details

Hello I am using the package node-craigslist https://github.com/brozeph/node-craigslist, and am hoping that someone can help me with some syntax with the details method.
In his documentation, he gives the example
client
.list()
.then((listings) => client.details(listings[0]))
.then((details) => {
console.log(details);
})
.catch((err) => {
console.error(err);
});
I currently have working the code to get the listings, but not the details. Below is my section of code where I retrieve the listings.
client
.list(options)
.then((listings) => {
listings.forEach((listing) => {
console.log(listing);
searchResults.title[counter] = listing.title;
searchResults.date[counter] = listing.date;
searchResults.location[counter] = listing.location;
searchResults.url[counter] = listing.url;
searchResults.price[counter] = listing.price;
counter++;
if(counter === listings.length) {
socket.emit('redirect'); //change to /results.ejs if done looping
};
});//end of listings foreach
});
I have been trying to incorporate the details into my own code unsuccessfully. Does anybody have any knowledge on how I can do this? Thanks.
You need to pass in a listing object into the method. In his example, he just grabs the most recent listings without any search options, then passes in the first listing from that array of listings. But you could obviously customize the search and the options.
client
.list()
.then((listings) => client.details(listings[0]))
.then((details) => {
console.log(details);
})
.catch((err) => {
console.error(err);
});
Depending on how the rest of your code is structured, you need to determine when to pass a specific listing. In my app that I built with this package, I make the initial search request that returns all the listings, and then when the user clicks on a listing for a search term, I make another request passing along that specific listing OBJECT and then it returns the details.
To be even more specific ...
On the client side the user searches, I emit that to the server then make the search request.
Once the request is finished I emit the results back to the client and then display the information to the user and store each listing object inside a custom data attribute inside each listing for later use.
Once the user clicks on a specific listing, I grab the object from the data-attribute and emit that to the server.
The server listens for that and makes the second DETAILS request using that listing object which is then emitted back to the clients browser.

Categories