Issue with Personalization Feature in Car Rental Website

Discussão em 'Angular' iniciado por Ahmed Alkali, Janeiro 29, 2025.

  1. Ahmed Alkali

    Ahmed Alkali Guest

    I'm currently working on a car rental website for a school project using Angular for the frontend and Python (Flask) for the backend. I'm facing challenges implementing a personalization feature where users should see reservations that belong to them and not someone else's when logged in.

    Problem Description: When a user logs in and navigates to the reservations page, the application should display only their reservations. However, I'm encountering difficulties with the user ID retrieval and data fetching process.

    Code Overview:

    I have two main components – frontend (Angular) and backend (Flask). I'm using SQLite for the database.

    Backend Code:

    User table and reservation table creation. Registration, login, and reservation endpoints. Storing user ID in the session after login. Frontend Code:

    Angular services for reservation and authorization. Components for making reservations and displaying user reservations. Reactive forms for login.

    Backend:

    from flask import Flask, request, jsonify, session
    from flask_cors import CORS
    import hashlib
    import sqlite3

    app = Flask(__name__)
    CORS(app)

    # Set the secret key
    app.config['SECRET_KEY'] = 'secret password'

    def hash_password(password):
    return hashlib.sha256(password.encode()).hexdigest()

    def create_users_table():
    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    firstname TEXT NOT NULL,
    lastname TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    mobile TEXT NOT NULL,
    gender TEXT NOT NULL,
    hashed_password TEXT NOT NULL,
    reservations TEXT DEFAULT '[]'
    )
    ''')
    conn.commit()

    def create_reservations_table():
    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS reservations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER,
    brand TEXT NOT NULL,
    from_location TEXT NOT NULL,
    to_location TEXT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users (id)
    )
    ''')
    conn.commit()

    create_users_table()
    create_reservations_table()

    @app.route('/register', methods=['POST'])
    def register_user():
    data = request.json

    # Validate required fields
    required_fields = ['firstname', 'lastname', 'email', 'mobile', 'gender', 'pwd']

    for field in required_fields:
    if field not in data:
    return jsonify({'error': f'Missing required field: {field}'}), 400

    # Validate email uniqueness
    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM users WHERE email = ?', (data['email'],))
    existing_user = cursor.fetchone()

    if existing_user:
    return jsonify({'error': 'Email is already registered'}), 400

    # Hash the password before storing it
    hashed_password = hash_password(data['pwd'])

    # Create a user object and add it to the users table
    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('''
    INSERT INTO users (firstname, lastname, email, mobile, gender, hashed_password)
    VALUES (?, ?, ?, ?, ?, ?)
    ''', (data['firstname'], data['lastname'], data['email'], data['mobile'], data['gender'], hashed_password))
    conn.commit()

    return jsonify({'message': 'Registration successful'})

    @app.route('/login', methods=['POST'])
    def login_user():
    data = request.json

    # Validate required fields
    required_fields = ['email', 'pwd']
    for field in required_fields:
    if field not in data:
    return jsonify({'error': f'Missing required field: {field}'}), 400

    # Check if the user exists
    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM users WHERE email = ?', (data['email'],))
    user = cursor.fetchone()

    if user:
    # Check if the provided password matches the hashed password in the database
    hashed_password = hash_password(data['pwd'])
    if hashed_password == user[6]: # Assuming hashed_password is at index 6
    # Store user ID in session
    session['user_id'] = user[0]
    return jsonify({'message': 'Login successful'})
    else:
    return jsonify({'error': 'Invalid password'}), 401
    else:
    return jsonify({'error': 'User not found'}), 404

    @app.route('/logout', methods=['POST'])
    def logout_user():
    # Clear the user ID from the session
    session.pop('user_id', None)
    return jsonify({'message': 'Logout successful'})

    @app.route('/make-reservation/<int:user_id>', methods=['POST'])
    def make_reservation(user_id):
    data = request.json

    # Print the received data
    print('Received Data:', data)

    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('''
    INSERT INTO reservations (user_id, brand, from_location, to_location)
    VALUES (?, ?, ?, ?)
    ''', (user_id, data.get('brand'), data.get('from_location'), data.get('to_location')))
    conn.commit()

    return jsonify({'message': 'Reservation successful'})



    @app.route('/user-reservations/<int:user_id>', methods=['GET'])
    def get_user_reservations(user_id):
    with sqlite3.connect('rental-users.db') as conn:
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM reservations WHERE user_id = ?', (user_id,))
    reservations = [
    {'id': row[0], 'user_id': row[1], 'brand': row[2], 'from_location': row[3], 'to_location': row[4]}
    for row in cursor.fetchall()
    ]
    print(reservations)
    return jsonify(reservations)



    if __name__ == '__main__':
    app.run(debug=True)


    frontend: AuthorizationService

    import { Injectable } from '@angular/core';
    import { Router } from '@angular/router';
    import { HttpClient } from '@angular/common/http';
    import { Observable, throwError } from 'rxjs';
    import { catchError, tap } from 'rxjs/operators';

    @Injectable({
    providedIn: 'root'
    })
    export class AuthorizationService {
    private apiUrl = 'http://localhost:5000';
    private user: any = { id: null, firstname: '', lastname: '', email: '' };
    private logged = false;
    private signedUp = false;

    get isLoggedIn(): boolean {
    return this.logged;
    }

    hasSignedUp(): boolean {
    return this.signedUp;
    }

    loginUser(loginData: any): Observable<any> {
    const url = `${this.apiUrl}/login`;
    return this.http.post(url, loginData).pipe(
    tap((user) => {
    this.user = user;
    this.logged = true;
    }),
    catchError((error) => {
    this.logged = false;
    return throwError(error);
    })
    );
    }

    logout(): Observable<any> {
    const url = `${this.apiUrl}/logout`;
    return this.http.post(url, {}).pipe(
    tap(() => {
    this.user = { id: null, firstname: '', lastname: '', email: '' };
    this.logged = false;
    this.router.navigate(['/login']);
    })
    );
    }

    registerUser(formData: any): Observable<any> {
    const url = `${this.apiUrl}/register`;
    return this.http.post(url, formData).pipe(
    tap((user) => {
    this.user = user;
    this.signedUp = true;
    }),
    catchError((error) => {
    this.signedUp = false;
    return throwError(error);
    })
    );
    }

    getUserId(): number | null {
    return this.user.id ?? null;
    }

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



    ReservationService

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Observable } from 'rxjs';

    @Injectable({
    providedIn: 'root',
    })
    export class ReservationService {
    private apiUrl = 'http://localhost:5000';

    constructor(private http: HttpClient) {}

    makeReservation(userId: number, selectedCar: string, fromLocation: string, toLocation: string): Observable<any> {
    const url = `${this.apiUrl}/make-reservation/${userId}`;
    const reservationData = {
    brand: selectedCar,
    from_location: fromLocation,
    to_location: toLocation,
    };
    return this.http.post(url, reservationData);
    }

    getUserReservations(userId: number): Observable<any[]> {
    const url = `${this.apiUrl}/user-reservations/${userId}`;
    return this.http.get<any[]>(url);
    }

    }



    MyReservationsComponent

    import { Component, OnInit } from '@angular/core';
    import { AuthorizationService } from '../authorization.service';
    import { ReservationService } from '../reservation.service';
    import { ToastrService } from 'ngx-toastr';
    import { AvailableCarsService } from '../available-cars.service';

    @Component({
    selector: 'app-my-reservations',
    templateUrl: './my-reservations.component.html',
    styleUrls: ['./my-reservations.component.css'],
    })
    export class MyReservationsComponent implements OnInit {
    reservationData = {
    brand: '',
    from_location: '',
    to_location: '',
    };

    reservations: any[] = [];
    availableCars: any[] = [];


    constructor(
    private reservationService: ReservationService,
    private authService: AuthorizationService,
    private toastr: ToastrService,
    private availableCarsService: AvailableCarsService
    ) {}

    ngOnInit() {
    this.loadReservationHistory();
    this.loadAvailableCars();
    }

    makeReservation() {
    const userId = this.authService.getUserId();

    console.log('Reservation Payload:', {
    userId: userId ?? 0,
    brand: this.reservationData.brand,
    from_location: this.reservationData.from_location,
    to_location: this.reservationData.to_location,
    });

    this.reservationService
    .makeReservation(
    userId ?? 0,
    this.reservationData.brand,
    this.reservationData.from_location,
    this.reservationData.to_location
    )
    .subscribe(
    (res) => {
    console.log(res);
    this.toastr.success('Reservation successful!', 'Success');
    this.loadReservationHistory();
    },
    (err) => {
    console.error(err);
    this.toastr.error('Error making reservation', 'Error');
    }
    );
    }

    loadReservationHistory() {
    const userId = this.authService.getUserId();

    this.reservationService.getUserReservations(userId ?? 0).subscribe(
    (res) => {
    console.log(res);
    this.reservations = res;
    },
    (err) => {
    console.error(err);
    }
    );
    }
    }



    LoginComponent

    import { Component, OnInit } from '@angular/core';
    import { AuthorizationService } from '../authorization.service';
    import { FormControl, FormGroup, Validators } from '@angular/forms';
    import { Router } from '@angular/router';
    import { ToastrService } from 'ngx-toastr'

    @Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css']
    })
    export class LoginComponent {
    constructor(private authService: AuthorizationService, private router: Router, private toastr: ToastrService) {}


    loginForm = new FormGroup({
    email: new FormControl("", [Validators.required, Validators.email]),
    pwd: new FormControl("", [Validators.required, Validators.minLength(6), Validators.maxLength(15)])
    });

    loginSubmitted() {
    this.authService.loginUser(this.loginForm.value).subscribe(
    res => {
    console.log(res);
    this.router.navigate(['/home']);
    },
    err => {
    console.error(err);
    }
    );
    }
    get Email(): FormControl {
    return this.loginForm.get('email') as FormControl;
    }

    get PWD(): FormControl {
    return this.loginForm.get('pwd') as FormControl;
    }

    ngOnInit(): void {}

    showToasterSuccess(){
    this.toastr.success("Logged in successfully !!", "Enjoy!!",{
    easing:"ease-in",
    easeTime: 1000
    });
    }

    }



    AppModule.ts

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import {HttpClientModule} from '@angular/common/http';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import { ToastrModule } from 'ngx-toastr';
    import { ToastModule } from 'primeng/toast';

    import { AppComponent } from './app.component';
    import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
    import { HeaderComponent } from './header/header.component';
    import { RouterModule } from '@angular/router';
    import { HomeComponent } from './home/home.component';
    import {FormsModule, ReactiveFormsModule} from '@angular/forms';
    import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
    import { MyAvailableCarsComponent } from './my-available-cars/my-available-cars.component';
    import { MyReservationsComponent } from './my-reservations/my-reservations.component';
    import { AboutUsComponent } from './about-us/about-us.component';
    import { LoginComponent } from './login/login.component';
    import { SignUpComponent } from './sign-up/sign-up.component';
    import { CarInfoComponent } from './car-info/car-info.component';
    import { ContactsComponent } from './contacts/contacts.component';


    @NgModule({
    declarations: [
    AppComponent,
    HeaderComponent,
    HomeComponent,
    MyAvailableCarsComponent,
    MyReservationsComponent,
    AboutUsComponent,
    LoginComponent,
    SignUpComponent,
    CarInfoComponent,
    ContactsComponent
    ],
    imports: [
    BrowserModule,
    NgbDropdownModule,
    RouterModule.forRoot([
    { path: 'my-reservations', component: MyReservationsComponent},
    { path: 'my-available-cars', component: MyAvailableCarsComponent},
    { path: 'about-us', component: AboutUsComponent},
    { path: 'sign-up', component: SignUpComponent},
    { path: 'login', component: LoginComponent},
    { path: 'home', component: HomeComponent},
    { path: 'contact', component: ContactsComponent},
    { path: '*', redirectTo:'/home' ,pathMatch : 'full'},
    ]),
    NgbModule,
    FormsModule,
    HttpClientModule,
    BrowserAnimationsModule,
    ToastrModule.forRoot({
    positionClass: "toast-top-right",
    preventDuplicates: true,
    timeOut: 2000,
    }),
    ToastModule,
    ReactiveFormsModule
    ],
    providers: [],
    bootstrap: [AppComponent]
    })
    export class AppModule { }


    MyreservationsHtml

    <div class="container mt-3">
    <h2>Make a Reservation</h2>
    <form (submit)="makeReservation()" #reservationForm="ngForm">
    <fieldset>
    <div class="mb-3">
    <label for="brand" class="form-label">Car Brand</label>
    <input type="text" class="form-control" id="brand" [(ngModel)]="reservationData.brand" name="brand" required>
    </div>


    <div class="mb-3">
    <label for="from_location" class="form-label">From Location</label>
    <input type="text" class="form-control" id="from_location" [(ngModel)]="reservationData.from_location" name="from_location" required>
    </div>

    <div class="mb-3">
    <label for="to_location" class="form-label">To Location</label>
    <input type="text" class="form-control" id="to_location" [(ngModel)]="reservationData.to_location" name="to_location" required>
    </div>

    <button type="submit" class="btn btn-primary">Make Reservation</button>
    </fieldset>
    </form>

    <div class="mt-5">
    <div class="text-center mb-4">
    <h2>Your Reservations</h2>
    </div>

    <div class="col">
    <div class="row row-cols-lg-4 row-cols-md-3 row-cols-sm-2 row-cols-1" >
    <table class="table table-hover table-striped">
    <thead>
    <tr class="table-info">
    <th scope="col">#</th>
    <th scope="col">Car</th>
    <th scope="col">From</th>
    <th scope="col">To</th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let reservation of reservations; let i = index">
    <th scope="row">{{ i + 1 }}</th>
    <td>{{ reservation.brand }}</td>
    <td>{{ reservation.from_location }}</td>
    <td>{{ reservation.to_location }}</td>
    </tr>
    </tbody>
    </table>
    <p *ngIf="reservations.length === 0">No reservations found.</p>
    </div>
    </div>
    </div>
    </div>

    Continue reading...

Compartilhe esta Página