Home > Software design >  Why is the user not set here?
Why is the user not set here?

Time:12-15

I`m having problems understanding why I'm not able to set the user in the app. Register and login work. Upon refreshing the app the user is lost, but the access token is still there. Also when I try to create a product, the manufacturer(owner) of it is undefined and not listed in the DB. I've been debugging it and I can see that req.user is not found by the app and stays undefined/null.

I`m attaching the whole github project for easier code check, if someone decides to help me out here. https://github.com/theBoomstick7/projectOils2

Thanks in advance everyone!

Changed all possible setting of the user, register and logout and login do work, but not the intended way.

I understand the design is not good, will be fixed later

As I understand this is not a good way to ask a question here, let me add some parts of the code.

This is the server controller of the product:

const {getAll,createProduct} = require(`../services/productService`)

const productController = require(`express`).Router()

productController.post(`/create`, async(req,res) => {
    const data = req.body
    console.log(req.user)
    try {
        const userId = req?.user?._id
        const product = await createProduct(data,userId)
        res.status(201).json(product)
    } catch (error) {
        res.status(400).json({error:error.message})
    }

    res.end()
})

This is the angular auth service :

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { tap } from 'rxjs';
import { IUser } from '../interfaces/user';


const AUTH_API_URL = 'http://localhost:3000' // Change this to environment directory later


@Injectable({
  providedIn: 'root'
})
export class AuthService {

  user: null | IUser | undefined
  constructor(private http: HttpClient, private router: Router) { }

  get isLogged(): boolean {
    if(this.user){
      return true
    }else 
    {
      return false
    }
  }   

  register(data: {}){
    return this.http.post<IUser>(`${AUTH_API_URL}/register`,data).pipe(
      tap((user) => {
        this.user = user
        localStorage.setItem(`accessToken`, this.user.accessToken)
      })
    )
  }
  login(data: {}){
    return this.http.post<IUser>(`${AUTH_API_URL}/login`, data). pipe(
      tap((user) => {
        this.user = user
        localStorage.setItem(`accessToken`, this.user.accessToken)
      })
    )
  }
  logout(){
    this.user = null
    return localStorage.removeItem(`accessToken`)
  }

}

This is the way the user register is handled :

export class RegisterComponent {
  
  errors: any;
  
 
  constructor(private fb: FormBuilder, private userService: AuthService, private router: Router) {}
  
  registerForm = this.fb.group({
    email: [``,[Validators.required, Validators.email]],
    username: [``, [Validators.required, Validators.minLength(6)]],
    password: [``, [Validators.required, Validators.minLength(6)]],
    rePass: [``, [Validators.required,passwordValidator]]
  })


  register(): void{
    this.userService.register(this.registerForm.value).subscribe
      ({

        next: () => this.router.navigate([`/`]),
        error:(err)=>   {
          this.errors = err.error?.error
        }

      })
  
    this.registerForm.reset()
    
  }    
}
This is how a product is created Product Angular service :

export class ProductsService {

 
  constructor(private http : HttpClient, private router : Router) { }

  createProduct(data : {}){
    return this.http.post<IProduct>(`${API_URL}/create`, data)
  }
}

Create product form :

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Route, Router } from '@angular/router';
import { ProductsService } from '../products.service'
@Component({
  selector: 'app-create-product',
  templateUrl: './create-product.component.html',
  styleUrls: ['./create-product.component.css']
})
export class CreateProductComponent {

  errors: string | undefined = undefined;
  constructor(private fb : FormBuilder, private productService: ProductsService, private router : Router){}

  createProductForm = this.fb.group({
    title : [``, [Validators.required, Validators.maxLength(12)]],
    imageUrl: [``, [ Validators.required]],
    description: [``, [Validators.required, Validators.minLength(10)]]
  })

  createProduct(){
    this.productService.createProduct(this.createProductForm.value).subscribe({
      next: () => this.router.navigate([`/products`]),
      error: (err) => {
        this.errors = err.error?.error
      }
    })
   
    
    
    this.createProductForm.reset()
  }
}

I hope this makes it easier to everyone.

PP, this is my app interceptor :

import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HTTP_INTERCEPTORS } from "@angular/common/http";
import { Injectable, Provider } from "@angular/core";
import { mergeMap, Observable, tap } from "rxjs";

@Injectable()
export class AppInterceptor implements HttpInterceptor{
    accessToken:any | [] | null = localStorage.getItem(`accessToken`)

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
    {
       if(this.accessToken)
       {
        return next.handle(req.clone({ setHeaders: {'X-Authorization' : this.accessToken}}))
    }
        else 
        {
            return next.handle(req.clone())
        }
    }
    }

    export const AppInterceptorProvider: Provider = {
        provide:HTTP_INTERCEPTORS,
        useClass: AppInterceptor,
        multi:true
    }

CodePudding user response:

I hope I understood well your question. If not, let me know. I will edit my answer.

I could debug your App.

You save your accessToken in the local storage, but not the User object. When you refresh the browser, the "accessToken" is there, but the user not because it was removed from the browser's memory.

In this case, your server knows that you are logged in, but your app (frontend) not.

In the auth.service.ts you have to save the user:

localStorage.setItem(`user`,  JSON.stringify(this.user));

In the app.component.ts you have to load the user again and set it into the userService instance:

  const myUser: string= localStorage.getItem('user')   '';
  const loadedUser: IUser = JSON.parse(myUser);
  console.log('Loaded User: '   loadedUser)
  this.userService.setLoggedUser(loadedUser);

An alternative solution could be check in the app.component.tsthe presence of the accessToken. If it is there, you can call a new REST method on the server to get the logged user for that token.

  • Related