How and where can I create a getUserById function? - authentication

I'm trying to find a way to get users in strapi by ID. But I don't have access to the User identity in the controller.
I have tried go write a function in the controller and service both diedn't work cause I cant access the find or findOne method
getById: async(ctx) => {
console.log('from user controller', ctx);
return User.find({ _id: ctx.request.body.id })
}

I reckon you are using typeorm? and User is your User repository?
So in that case a small change should do
getById: async(ctx) => {
console.log('from user controller', ctx);
return User.find({ where: {_id: ctx.request.body.id} })
}
(Also make sure you have sanitized your input somewhere)

Related

Angular Subscription to SQL DB

I am having difficulty grasping some of the concepts. Such as I have created a subscription to my SQL DB (users) upon login and I am able to present the data on the page (DOM). However, I a now trying to pull out specific data from the item to save for later use in my typescript file.
login.component.ts
this.usersService.getUsers()
.subscribe((result: users) => (this.users[0] = result));
users.service.ts
public getUsers() : Observable<users> {
let userEmail = sessionStorage.getItem('userEmail');
return this.http.get<users>(`${environment.apiUrl}/${this.url}/${userEmail}`);
login.component.html
<div class="row" style="background-color:transparent;">
<mat-card *ngFor="let user of user" class="ecard">
<mat-card-title>{{user.role}}</mat-card-title>
</mat-card>
</div>
This works as expected.
However, I would like to use information from the 'user' to perform other functions in the ts file.
The below actions are returning undefined values
console.log(this.users);
console.log(this.users.values);
And this action returns an error of "can not read 'fname'
sessionStorage.setItem('userDisplayName', this.users[0].fname);
An observable is asynchronous. So you only can be sure you get the value inside "subscribe function" (well, in subscribe function you can call to another function passing as argument the response)
**WRONG**
this.usersService.getUsers()
.subscribe((result: users) => (this.users[0] = result));
sessionStorage.setItem('userDisplayName', this.users[0].fname); //<--this is outside
// subscribe function
**OK**
this.usersService.getUsers()
.subscribe((result: users) => {
this.users[0] = result;
sessionStorage.setItem('userDisplayName', this.users[0].fname);
})
**OR OK Too**
this.usersService.getUsers()
.subscribe((result: users) => {
this.users[0] = result;
doSomething(this.users[0])
})
doSomething(user:any)
{
sessionStorage.setItem('userDisplayName', this.users[0].fname);
}
NOTE: To log or store the result, it's common use the rxjs operator "tap" in the observable. This operator makes that, when someone subscribe it's executed the function
public getUsers() : Observable<users> {
let userEmail = sessionStorage.getItem('userEmail');
return this.http.get<users>(`${environment.apiUrl}/${this.url}/${userEmail}`).pipe(
tap((res:any)=>{
sessionStorage.setItem('userDisplayName', res.fname);
})
)

Nestjs: Cannot PUT, Cannot DELETE (404 not found)

I'm on a task to write a simple CRUD program for a users list, following a similar nestjs example. While GET, POST and GET by id works fine, PUT and DELETE does not work properly. I get 'User does not exist' however user exists in database.
Controller
#Controller('users')
export class UsersController {
constructor(private userService: UsersService) {}
.....
//Update a user's details
#Put('/update')
async updateUser(
#Res() res,
#Query('userid') userID,
#Body() createUserDto: CreateUserDto
) {
const user = await this.userService.updateUser(userID, createUserDto);
if (!user) throw new NotFoundException('User does not exist!');
return res.status(HttpStatus.OK).json({
message: 'User has been successfully updated',
user
})
}
//Delete a user
#ApiParam({ name: 'id' })
#Delete('/delete')
async deleteUser(#Res() res, #Query('userid') userID) {
const user = await this.userService.deleteUser(userID);
if (!user) throw new NotFoundException('Customer does not exist');
return res.status(HttpStatus.OK).json({
message: 'User has been deleted',
user
})
}
Service
// Edit user details
async updateUser(userID, createUserDto: CreateUserDto): Promise<User> {
const updatedUser = await this.userModel
.findByIdAndUpdate(userID, createUserDto, { new: true });
return updatedUser;
}
// Delete a customer
async deleteUser(userID): Promise<any> {
const deletedUser = await this.userModel
.findByIdAndRemove(userID);
return deletedUser;
}
I'm using swagger to perform my tests. I'm passing id as a parameter to find and update user.
Based on your code repository, you aren't using URL Parameters, but rather you are using Query Parameters. The difference in the two is how they are passed to the server and how they are told to the server to listen for them.
Query Parameters
With query parameters, you pass them to your server starting with a ? in the url, and concatenating each one after by using a &. An example could look something like http://localhost:3000?name=Test&id=a26408f3-69eb-4443-8af7-474b896a9e70. Notice that there are two Query parameters, one named name and one named id. In Nest, to get these parameters in your route handler, you would use the #Query() decorator. A sample class could look like
#Controller()
export class AppController {
#Get()
getHello(#Query() query: { name: string, id: string }) {
return `Hello ${name}, your ID is ${id}`;
}
}
Notice how with the url above, the route called is the base route (/), with the query parameters added on.
URL Parameters
URL parameters are a way to dynamically build your routes without needing to specify what each possible URL. This is useful for things like IDs that are dynamically generated. Taking a similar URL as above, the sample URL this time could look like http://localhost:3000/Test/a26408f3-69eb-4443-8af7-474b896a9e70. Notice how this time there is no ? or & and it just looks like a full URL. To specify URL Params in nest, you need to a a colon(:) before the param name in the resource declaration decorator, along with any other part of the path necessary. Then to access the URL Parameters, you need to use the #Param() decorator in the route handler, similar to how you would the #Query() decorator. The class sample for this would be
#Controller()
export class AppController {
#Get(':name/:id')
getHello(#Param() params: { name: string, id: string })
return `Hello ${name}, your ID is ${id}`;
}
}
Problem and Solution
You're currently calling off to http://localhost/users/update/<ID> acting as if you are using URL parameters, but in your route handler you are expecting #Query() to grab the id. Because of this, there is no handler to find /users/update/:id and so you are getting a 404 in return. You can either modify your server to listen for URL Parameters as described above, or you can modify the URL to send the request using Query Parameters instead of URL parameters.

Accessing information of authenticated user in request scope using express

I'm using Express with TypeORM and currently I got stuck in the following situation:
Before inserting or updating a record, I always want to set the username to the current record to persist the information who last updated this record.
With TypeORM, this can easily be done by using subscribers:
#EventSubscriber()
export class Subscriber implements EntitySubscriberInterface {
beforeUpdate(event: UpdateEvent<any>) {
const entity = event.entity;
if(entity instanceof Base) {
entity.lastUpdatedBy = 'username'; // TODO
}
}
}
The user is known after he was successfully authenticated:
#Put('/entity')
public updateEntity(#CurrentUser({required: true}) user: User, #Body enity: Entity): Promise<Entity> {
Log.info('User successfully authenticated: ' + user)
return this.manager.update(entity);
}
My question is: What is the simpliest way to store and access user information in a request scope?
What I found out so far:
The following stackoverflow-post seems to be related, but the
solutions sounds like a overhead for me (GLOBAL data per HTTP/Session request?)
I also could append the user information in the updateEntity method, but then I have to explicitly all the time.
Is there any other option?
You can use the atttribute data of type any of the SaveOptions.
#Put('/entity')
public updateEntity(#CurrentUser({required: true}) user: User, #Body enity: Entity): Promise<Entity> {
Log.info('User successfully authenticated: ' + user)
return this.manager.update(entity, {data: user});
}
And then, you can use the data in Subscriber with:
event.queryRunner.data
I used the following npm package to save the user in my request scope: https://www.npmjs.com/package/cls-hooked.
This package did not work for me since async/await seems not to be supported: continuation-local-storage.

Meteor.loginWithPassword callback doesn't provide custom object in User accounts doc

Meteors loginWithPassword() function doesn't provide me the object systemData, which I adding to user doc (not to profile obj) during registration. The thing is, that if I look into console after logging in, I can see that object systemData (that means probably it's not publish issue), but not in callback of loginWithPassword() function, where I need them (to dynamically redirect user to proper page). Is there way to get this object, without any ugly things like timers?
Meteor.loginWithPassword(email, password, function(errorObject) {
if (errorObject) {
...
} else {
// returns true
if (Meteor.userId()) {
// returns false
if (Meteor.user().systemData) {
...
}
// user doc without systemData object
console.log(JSON.stringify(Meteor.user());
}
}
I've adding object systemData on creating user:
Accounts.onCreateUser(function(options, user) {
if (options.profile) {
user.profile = options.profile;
}
...
user.systemData = systemDataRegularUser;
return user;
});
Are you sure publish data to Client ?
I get User Info Using loginWithPassword in callback function.
Meteor.loginWithPassword username,password,(error,result1)->
options =
username: username
password: password
email: result['data']['email']
profile:
name: result['data']['display-name']
roles: result.roles
console.log Meteor.user(), result1
I Create user flowing code: (options contains systemData)
Accounts.createUser option
The first problem is that you want a custom field on a user document published to the client. This is a common question - see the answer here.
The next problem is that even after you add something like:
Meteor.publish("userData", function () {
return Meteor.users.find(this.userId, {fields: {systemData: 1}});
});
I think you still have a race condition. When you call loginWithPassword, the server will publish your user document, but it will also publish another version of the same document with the systemData field. You are hoping that both events have completed by the time Meteor.user() is called. In practice this may just work, but I'm not sure there is any guarantee that it always will. As you suggested, if you added a slight delay with a timer that would probably work but it's an ugly hack.
Alternatively, can you just add systemData to the user's profile so it will always be published?
I didn't find exact way how to solve this, but found easy workaround.
To make some action right after user logged in (eg. dynamically redirect user to proper page), you can hook on your home page with Iron router.(If you using it.) :
this.route('UsersListingHome', {
path: '/',
template: 'UsersListing',
data: function() { ... },
before: function() {
if (isCurrentUserAdmin() && Session.get('adminJustLogged') !== 'loggedIn') {
Router.go('/page-to-redirect');
Session.set('adminJustLogged','loggedIn');
}
}
});
After click on logout of course if (isCurrentUserAdmin()) { Session.set('adminJustLogged', null); }
I've further thought about calling Meteor.call('someMethod') to fetch userData object in Method callback, but now I'm satisfied.
PS: I know that it's not recommended to have plenty session variables or other reactive data source for speeding-up my app, but I believe, that one is not tragedy :)
PS2: Anyway, thanks for your answers.

zfcUser getState in another module

how could i getState from zfcUser
in view/index.phtml i get it from $this->zfcUserIdentity()->getState();
but now i need to get this value ( state for this user who is logged in ), in other module /controller (this is my costum module controller)
so i need to get State from:
zfcUser/Entity/User
to
myModule/Controller
i watch this https://github.com/ZF-Commons/ZfcUser/wiki/How-to-check-if-the-user-is-logged-in but this solutons is not helpful
and this helps too, for me:
$sm = $this->getServiceLocator();
$auth = $sm->get('zfcuserauthservice');
if ($auth->hasIdentity()) {
$user_edit = $auth->getIdentity()->getPrem();
}
The state is a property from the user itself. So if you get the user throught the identification service, you can grab the state from there.
public function myFooAction()
{
if ($this->zfcUserAuthentication()->hasIdentity()) {
$user = $this->zfcUserAuthentication()->getIdentity();
$state = $user->getState();
}
}
Mind that when the user is not logged in, the if condition is false. Also the state can be null or any arbitrary value, so do not expect that every user returns a valid state (in other words, check the returned value!)
follow this code, I had same problem then I have manage how to use identity of logged in user via zfcUser
in other modules controller at topside,
use Zend\EventManager\EventManagerInterface;
then create this two function in the sameclass,
public function setEventManager(EventManagerInterface $events)
{
parent::setEventManager($events);
$controller = $this;
$events->attach('dispatch', function ($e) use ($controller) {
if (is_callable(array($controller, 'checkUserIdentity')))
{
call_user_func(array($controller, 'checkUserIdentity'));
}
}, 100);
}
public function checkUserIdentity()
{
if ($this->zfcUserAuthentication()->hasIdentity()) {
echo "<pre>"; print_r($this->zfcUserAuthentication()->getIdentity());die;
}
}
it will give this kind of output
Admin\Entity\User Object
(
[id:protected] => 2
[username:protected] =>
[email:protected] => rajat.modi#softwebsolutions.com
[displayName:protected] =>
[password:protected] => $2y$14$2WxYLE0DV0mH7txIRm7GkeVJB3mhD4FmnHmxmrkOXtUFL7S9PqWy6
[state:protected] =>
)
That's it you will automatically get Identity whether user is logged in if not then it will redirect to login page.
Hope this will helps