Implement user-specific tutorial retrieval and enhance authentication details

This commit is contained in:
liosha84
2025-07-06 14:04:19 +03:00
parent 83c1917651
commit f7b2b189b3
12 changed files with 143 additions and 6 deletions
@@ -142,6 +142,7 @@ export class MainComponent implements OnInit{
//window.location.reload(); //window.location.reload();
this.router.navigate([environment.default_page]); this.router.navigate([environment.default_page]);
window.location.reload();
}, },
error: err => { error: err => {
console.log(err); console.log(err);
@@ -17,6 +17,8 @@ export class TutorialService {
return this.http.get<Tutorial[]>(baseUrl); return this.http.get<Tutorial[]>(baseUrl);
} }
get(id: any): Observable<Tutorial> { get(id: any): Observable<Tutorial> {
return this.http.get(`${baseUrl}/${id}`); return this.http.get(`${baseUrl}/${id}`);
} }
@@ -1,6 +1,26 @@
<p>tutorials-list.component works!</p> <p>tutorials-list.component works!</p>
<mat-list role="list"> <mat-list role="list">
<mat-list-item role="listitem">Item 1</mat-list-item> @for (tutorial of tutorials; track tutorial) {
<mat-list-item role="listitem">Item 2</mat-list-item> <!--
<mat-list-item role="listitem">Item 3</mat-list-item> <mat-list-item role="listitem">
{{tutorial.title}}
<span class="spacer"></span>
<button mat-button>
<mat-icon>edit</mat-icon>
</button>
<button mat-button>
<mat-icon>delete</mat-icon>
</button>
</mat-list-item>-->
<mat-option >
<div style="display:flex; justify-content: space-between">
<span>{{tutorial.title}}</span>
<span></span>
<span (click)="deleteOption($event, tutorial)">X</span>
</div>
</mat-option>
}
</mat-list> </mat-list>
@@ -0,0 +1,3 @@
.spacer{
flex: 1 1 auto;
}
@@ -1,15 +1,46 @@
import { Component } from '@angular/core'; import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {MatList, MatListItem} from '@angular/material/list'; import {MatList, MatListItem} from '@angular/material/list';
import {Tutorial} from '../../models/tutorial.model';
import {TutorialService} from '../../services/tutorial.service';
import {UserApiService} from '../user-api.service';
import {MatButton} from '@angular/material/button';
import {MatLine, MatOption} from '@angular/material/core';
import {MatIcon} from '@angular/material/icon';
@Component({ @Component({
selector: 'app-tutorials-list.component', selector: 'app-tutorials-list.component',
imports: [ imports: [
MatList, MatList,
MatListItem MatListItem,
MatLine,
MatButton,
MatIcon,
MatOption
], ],
schemas:[CUSTOM_ELEMENTS_SCHEMA],
templateUrl: './tutorials-list.component.html', templateUrl: './tutorials-list.component.html',
styleUrl: './tutorials-list.component.scss' styleUrl: './tutorials-list.component.scss'
}) })
export class TutorialsListComponent { export class TutorialsListComponent {
tutorials?: Tutorial[];
constructor(private userApiService: UserApiService) {
this.retrieveTutorials();
}
retrieveTutorials(): void {
this.userApiService.getUserAllTutorials()
.subscribe(
data => {
this.tutorials = data;
console.log(data);
},
error => {
console.log(error);
});
}
deleteOption($event: MouseEvent, option: any) {
}
} }
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { UserApiService } from './user-api.service';
describe('UserApiService', () => {
let service: UserApiService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UserApiService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import {Observable} from 'rxjs';
import {Tutorial} from '../models/tutorial.model';
import {HttpClient} from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UserApiService {
baseUrl = 'http://localhost:8080/api/user';
constructor(private http: HttpClient) {
}
getUserAllTutorials(): Observable<Tutorial[]> {
return this.http.get<Tutorial[]>(`${this.baseUrl}/tutorials`);
}
}
@@ -37,6 +37,34 @@ public class TutorialController {
@Autowired @Autowired
TutorialRepository tutorialRepository; TutorialRepository tutorialRepository;
@GetMapping("/user/tutorials")
public ResponseEntity<List<Tutorial>> getUserTutorials(@RequestParam(required = false) String title) {
try {
List<Tutorial> tutorials = new ArrayList<Tutorial>();
User user = userRepository.findById(authenticationFacade.getUserDetails().getId()).get();
if(title == null){
// If no title is provided, return all tutorials for the user
tutorialRepository.findByUserId(user.getId()).forEach(tutorials::add);
} else {
// If a title is provided, filter tutorials by user and title
tutorialRepository.findByUserIdAndTitle(user.getId(), title).forEach(tutorials::add);
}
if (tutorials.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(tutorials, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@GetMapping("/tutorials") @GetMapping("/tutorials")
public ResponseEntity<List<Tutorial>> getAllTutorials(@RequestParam(required = false) String title) { public ResponseEntity<List<Tutorial>> getAllTutorials(@RequestParam(required = false) String title) {
try { try {
@@ -12,6 +12,7 @@ import java.util.List;
public interface TutorialRepository extends JpaRepository<Tutorial, Long> { public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
List<Tutorial> findByUserId(Long userId); List<Tutorial> findByUserId(Long userId);
List<Tutorial> findByUserIdAndTitle(Long userId, String title);
List<Tutorial> findByPublished(boolean published); List<Tutorial> findByPublished(boolean published);
List<Tutorial> findByTitleContaining(String title); List<Tutorial> findByTitleContaining(String title);
} }
@@ -1,7 +1,9 @@
package com.jambotronGroup.jambotron.security; package com.jambotronGroup.jambotron.security;
import com.jambotronGroup.jambotron.security.services.UserDetailsImpl;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@@ -12,5 +14,16 @@ public class AuthenticationFacade implements IAuthenticationFacade {
return SecurityContextHolder.getContext().getAuthentication(); return SecurityContextHolder.getContext().getAuthentication();
} }
@Override
public UserDetailsImpl getUserDetails() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return (UserDetailsImpl) userDetails;
}
} }
@@ -1,7 +1,10 @@
package com.jambotronGroup.jambotron.security; package com.jambotronGroup.jambotron.security;
import com.jambotronGroup.jambotron.security.services.UserDetailsImpl;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
public interface IAuthenticationFacade { public interface IAuthenticationFacade {
Authentication getAuthentication(); Authentication getAuthentication();
UserDetailsImpl getUserDetails();
} }
@@ -116,7 +116,7 @@ public class WebSecurityConfig implements WebMvcConfigurer {// extends WebSecuri
.requestMatchers("/main/**").permitAll() .requestMatchers("/main/**").permitAll()
.requestMatchers("/api/test/**").permitAll() .requestMatchers("/api/test/**").permitAll()
.requestMatchers("/api/tutorials").hasRole("ADMIN") //.requestMatchers("/api/tutorials").hasRole("ADMIN")
.requestMatchers("/api/zhipuai/image/**").permitAll() .requestMatchers("/api/zhipuai/image/**").permitAll()