mirror of
https://codeberg.org/beerbrawl/beerbrawl.git
synced 2024-09-23 05:40:51 +02:00
bug/(#63): bugs fixes, Confirm Action dialog
This commit is contained in:
parent
e77aecad36
commit
be6d9cfdae
|
@ -2,8 +2,12 @@ package at.ac.tuwien.sepr.groupphase.backend.endpoint;
|
|||
|
||||
import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.UserDetailDto;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.endpoint.dto.UserLoginDto;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.entity.Tournament;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.exception.UserAlreadyExistsException;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.service.TournamentService;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.service.UserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -11,6 +15,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
|
@ -25,6 +30,10 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = UserEndpoint.BASE_ENDPOINT)
|
||||
|
@ -33,10 +42,12 @@ public class UserEndpoint {
|
|||
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final UserService userService;
|
||||
private final TournamentService tournamentService;
|
||||
|
||||
@Autowired
|
||||
public UserEndpoint(UserService userService) {
|
||||
public UserEndpoint(UserService userService, TournamentService tournamentService) {
|
||||
this.userService = userService;
|
||||
this.tournamentService = tournamentService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,11 +84,12 @@ public class UserEndpoint {
|
|||
*/
|
||||
@DeleteMapping("{username}")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PreAuthorize("isAuthenticated()") //see JwtAuthFilter UsernamePasswordAuthenticationToken
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@Operation(summary = "Delete user and all data belonging to them(Tournaments, Teams, etc) from the database.", security = @SecurityRequirement(name = "apiKey"))
|
||||
public ResponseEntity<?> delete(@PathVariable(value = "username") String username, Authentication authentication) {
|
||||
LOG.info("DELETE {}/{}", BASE_ENDPOINT, username);
|
||||
if (!username.equals(authentication.getPrincipal())) {
|
||||
return new ResponseEntity<>("Forbidden", HttpStatus.FORBIDDEN); // ToDo: Check why PreAUth("#username == authentication.principal") not working (string == object)
|
||||
throw new AccessDeniedException("Username does not match.");
|
||||
}
|
||||
|
||||
userService.deleteUser(username);
|
||||
|
@ -93,35 +105,53 @@ public class UserEndpoint {
|
|||
@PutMapping("{username}")
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@Operation(summary = "Update username and password for user.", security = @SecurityRequirement(name = "apiKey"))
|
||||
public ResponseEntity<?> update(@PathVariable(value = "username") String username, @Valid @RequestBody UserLoginDto userUpdate, Authentication authentication) {
|
||||
LOG.info("UPDATE {}/{}", BASE_ENDPOINT, username);
|
||||
if (!username.equals(authentication.getPrincipal())) {
|
||||
return new ResponseEntity<>("Forbidden", HttpStatus.FORBIDDEN);
|
||||
throw new AccessDeniedException("Username does not match.");
|
||||
}
|
||||
userService.updateUser(userUpdate, username);
|
||||
try {
|
||||
userService.updateUser(userUpdate, username);
|
||||
} catch (UserAlreadyExistsException e) {
|
||||
HttpStatus status = HttpStatus.CONFLICT;
|
||||
logClientError(status, "User already exists", e);
|
||||
return new ResponseEntity<>(e.getMessage(), status);
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Username and password for user. ToDo: Add futher info like Num of Tournaments
|
||||
* Get Username and password for user.
|
||||
* The target user is retrieved through the JWT
|
||||
*/
|
||||
@GetMapping("/detail/{username}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@Operation(summary = "Get detailed information about user and their tournaments.", security = @SecurityRequirement(name = "apiKey"))
|
||||
public ResponseEntity<UserDetailDto> details(@PathVariable(value = "username") String username, Authentication authentication) {
|
||||
LOG.info("GET-DETAILS {}/detail/{}", BASE_ENDPOINT, username);
|
||||
|
||||
if (!username.equals(authentication.getPrincipal())) {
|
||||
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
|
||||
throw new AccessDeniedException("Username does not match.");
|
||||
}
|
||||
|
||||
var user = userService.findApplicationUserByUsername(username);
|
||||
var tournaments = tournamentService.findAllByOrganizer(username);
|
||||
|
||||
//Todo: Move filtering to tournamentService?
|
||||
var tournamentNames = tournaments.stream().map(Tournament::getName).toList();
|
||||
Predicate<Tournament> isPast = t -> t.getRegistrationEnd().isBefore(LocalDateTime.now());
|
||||
Map<Boolean, Long> counts = tournaments.stream()
|
||||
.collect(Collectors.partitioningBy(isPast, Collectors.counting()));
|
||||
|
||||
if (user != null) {
|
||||
var dto = UserDetailDto.UserDetailDtoBuilder
|
||||
.anUserDetailDto()
|
||||
.withUsername(user.getUsername())
|
||||
.withPassword(user.getPassword())
|
||||
.withRole(user.getAdmin() ? "ADMIN" : "USER")
|
||||
.withTournaments(tournamentNames)
|
||||
.withOpen(counts.get(false).intValue())
|
||||
.withClosed(counts.get(true).intValue())
|
||||
.build();
|
||||
return ResponseEntity.ok(dto);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package at.ac.tuwien.sepr.groupphase.backend.endpoint.dto;
|
|||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class UserDetailDto {
|
||||
|
@ -11,75 +12,75 @@ public class UserDetailDto {
|
|||
@Size(min = 3, max = 256)
|
||||
private String username;
|
||||
|
||||
//Todo: Discuss possible security concerns
|
||||
@NotNull(message = "Password must not be null")
|
||||
@Size(min = 8, max = 1024)
|
||||
private String password;
|
||||
|
||||
@NotNull
|
||||
private String role;
|
||||
private List<String> tournaments;
|
||||
@NotNull
|
||||
private int closedTournaments;
|
||||
@NotNull
|
||||
private int openTournaments;
|
||||
|
||||
public List<String> getTournaments() {
|
||||
return tournaments;
|
||||
}
|
||||
|
||||
public void setTournaments(List<String> tournaments) {
|
||||
this.tournaments = tournaments;
|
||||
}
|
||||
|
||||
public int getClosedTournaments() {
|
||||
return closedTournaments;
|
||||
}
|
||||
|
||||
public void setClosedTournaments(int closedTournaments) {
|
||||
this.closedTournaments = closedTournaments;
|
||||
}
|
||||
|
||||
public int getOpenTournaments() {
|
||||
return openTournaments;
|
||||
}
|
||||
|
||||
public void setOpenTournaments(int openTournaments) {
|
||||
this.openTournaments = openTournaments;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
// Setters
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
// hashCode
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(username, password, role);
|
||||
}
|
||||
|
||||
// equals
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
UserDetailDto user = (UserDetailDto) o;
|
||||
return Objects.equals(username, user.username)
|
||||
&& Objects.equals(password, user.password)
|
||||
&& Objects.equals(role, user.role);
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
UserDetailDto that = (UserDetailDto) o;
|
||||
return closedTournaments == that.closedTournaments && openTournaments == that.openTournaments && Objects.equals(username, that.username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(username, tournaments, closedTournaments, openTournaments);
|
||||
}
|
||||
|
||||
// toString
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{"
|
||||
+ "username='" + username + '\''
|
||||
+ ", password='[PROTECTED]'"
|
||||
+ ", role='" + role + '\''
|
||||
+ '}';
|
||||
return "UserDetailDto{" +
|
||||
"username='" + username + '\'' +
|
||||
", TournamentCount=" + tournaments.size() +
|
||||
", closedTournaments=" + closedTournaments +
|
||||
", openTournaments=" + openTournaments +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static final class UserDetailDtoBuilder {
|
||||
private String username;
|
||||
private String password;
|
||||
private String role;
|
||||
private List<String> tournaments;
|
||||
private int closedTournaments;
|
||||
private int openTournaments;
|
||||
|
||||
private UserDetailDtoBuilder() {
|
||||
}
|
||||
|
@ -88,26 +89,33 @@ public class UserDetailDto {
|
|||
return new UserDetailDto.UserDetailDtoBuilder();
|
||||
}
|
||||
|
||||
public UserDetailDto.UserDetailDtoBuilder withTournaments(List<String> tournaments) {
|
||||
this.tournaments = tournaments;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetailDto.UserDetailDtoBuilder withClosed(int closedTournaments) {
|
||||
this.closedTournaments = closedTournaments;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetailDto.UserDetailDtoBuilder withOpen(int openTournaments) {
|
||||
this.openTournaments = openTournaments;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetailDto.UserDetailDtoBuilder withUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetailDto.UserDetailDtoBuilder withPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetailDto.UserDetailDtoBuilder withRole(String role) {
|
||||
this.role = role;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetailDto build() {
|
||||
UserDetailDto userDetailDto = new UserDetailDto();
|
||||
userDetailDto.setUsername(username);
|
||||
userDetailDto.setPassword(password);
|
||||
userDetailDto.setRole(role);
|
||||
userDetailDto.setTournaments(tournaments);
|
||||
userDetailDto.setClosedTournaments(closedTournaments);
|
||||
userDetailDto.setOpenTournaments(openTournaments);
|
||||
return userDetailDto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,13 @@ public class ApplicationUser {
|
|||
public ApplicationUser() {
|
||||
}
|
||||
|
||||
public ApplicationUser(String username, String password, Boolean admin) {
|
||||
public ApplicationUser(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public ApplicationUser(String username, String password, Boolean admin) {
|
||||
this(username, password);
|
||||
this.admin = admin;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import at.ac.tuwien.sepr.groupphase.backend.entity.ApplicationUser;
|
|||
public interface UserRepository extends JpaRepository<ApplicationUser, Long> {
|
||||
ApplicationUser findByUsername(String username);
|
||||
|
||||
boolean existsByUsername(String username);
|
||||
|
||||
void deleteByUsername(String username);
|
||||
}
|
|
@ -64,5 +64,5 @@ public interface UserService extends UserDetailsService {
|
|||
* @return updated user
|
||||
* @throws NotFoundException if the user to update is not found by the username
|
||||
*/
|
||||
ApplicationUser updateUser(UserLoginDto user, String username) throws NotFoundException;
|
||||
ApplicationUser updateUser(UserLoginDto user, String username) throws NotFoundException, UserAlreadyExistsException;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class CustomUserDetailService implements UserService {
|
||||
|
@ -92,20 +93,17 @@ public class CustomUserDetailService implements UserService {
|
|||
public ApplicationUser register(UserLoginDto dto) throws UserAlreadyExistsException {
|
||||
LOGGER.debug("Trying to register user '{}'", dto.getUsername());
|
||||
|
||||
try {
|
||||
loadUserByUsername(dto.getUsername());
|
||||
} catch (UsernameNotFoundException e) {
|
||||
var newUser = new ApplicationUser(
|
||||
dto.getUsername(),
|
||||
passwordEncoder.encode(dto.getPassword()),
|
||||
false
|
||||
if (userRepository.existsByUsername(dto.getUsername())) {
|
||||
throw new UserAlreadyExistsException(
|
||||
"User with username '%s' already exists".formatted(dto.getUsername())
|
||||
);
|
||||
return userRepository.save(newUser);
|
||||
}
|
||||
|
||||
throw new UserAlreadyExistsException(
|
||||
"User with username '%s' already exists".formatted(dto.getUsername())
|
||||
var newUser = new ApplicationUser(
|
||||
dto.getUsername(),
|
||||
passwordEncoder.encode(dto.getPassword()),
|
||||
false
|
||||
);
|
||||
return userRepository.save(newUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,9 +121,13 @@ public class CustomUserDetailService implements UserService {
|
|||
|
||||
@Override
|
||||
@Transactional
|
||||
public ApplicationUser updateUser(UserLoginDto user, String username) throws NotFoundException {
|
||||
public ApplicationUser updateUser(UserLoginDto user, String username) throws NotFoundException, UserAlreadyExistsException {
|
||||
LOGGER.debug("Updating registered user '{}'", user.getUsername());
|
||||
|
||||
if (!Objects.equals(username, user.getUsername()) && userRepository.existsByUsername(user.getUsername())) {
|
||||
throw new UserAlreadyExistsException("User with username '%s' already exists.".formatted(user.getUsername()));
|
||||
}
|
||||
|
||||
var targetUser = userRepository.findByUsername(username);
|
||||
if (targetUser != null) {
|
||||
targetUser.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
|
|
|
@ -9,6 +9,7 @@ import at.ac.tuwien.sepr.groupphase.backend.entity.QualificationParticipation;
|
|||
import at.ac.tuwien.sepr.groupphase.backend.entity.Team;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.entity.Tournament;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.exception.NotFoundException;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.exception.UserAlreadyExistsException;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.repository.BeerPongTableRepository;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.repository.QualificationMatchRepository;
|
||||
import at.ac.tuwien.sepr.groupphase.backend.repository.TeamRepository;
|
||||
|
@ -81,7 +82,7 @@ public class UserDetailServiceTest implements TestData {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void checkUpdatedInformationOfRegisteredUser() {
|
||||
public void checkUpdatedInformationOfRegisteredUser() throws Exception {
|
||||
|
||||
var user = new ApplicationUser("Username", "Password", false);
|
||||
userRepository.save(user);
|
||||
|
@ -90,6 +91,7 @@ public class UserDetailServiceTest implements TestData {
|
|||
.withUsername("Updated").withPassword("UpPass").build();
|
||||
var updates = userService.updateUser(userUpdate, user.getUsername());
|
||||
|
||||
|
||||
assertAll(
|
||||
() -> assertNotNull(updates),
|
||||
() -> assertEquals(user.getAdmin(), updates.getAdmin()),
|
||||
|
@ -98,6 +100,24 @@ public class UserDetailServiceTest implements TestData {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkUpdateInformationOfRegisteredUser_UsernameAlreadyExists() throws Exception {
|
||||
|
||||
var sameUsername = "Username";
|
||||
var uniqueUsername = "Unique";
|
||||
var firstUser = new ApplicationUser(sameUsername, "Password");
|
||||
userRepository.save(firstUser);
|
||||
var secondUser = new ApplicationUser(uniqueUsername, "Password");
|
||||
userRepository.save(secondUser);
|
||||
|
||||
var userUpdate = UserLoginDto.UserLoginDtoBuilder.anUserLoginDto()
|
||||
.withUsername(sameUsername).withPassword("UpPass").build();
|
||||
assertThrows(UserAlreadyExistsException.class, () -> {
|
||||
var updated = userService.updateUser(userUpdate, uniqueUsername);
|
||||
}, "User with username '%s' already exists.".formatted(sameUsername));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDeleteOfRegisteredUserCascading_SharedQualificationParticipationAndMatch() {
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ export class UserEndpointService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete user and all data belonging to them(Tournaments, Teams, etc) from the database.
|
||||
* @param username
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
* @param reportProgress flag to report request and response progress.
|
||||
|
@ -157,6 +158,7 @@ export class UserEndpointService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about user and their tournaments.
|
||||
* @param username
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
* @param reportProgress flag to report request and response progress.
|
||||
|
@ -293,6 +295,7 @@ export class UserEndpointService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Update username and password for user.
|
||||
* @param username
|
||||
* @param userLoginDto
|
||||
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
|
||||
export interface UserDetailDto {
|
||||
username: string;
|
||||
password: string;
|
||||
role: string;
|
||||
tournaments: Array<string>;
|
||||
closedTournaments: number;
|
||||
openTournaments: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import { TournamentsComponent } from './components/tournaments/tournaments.compo
|
|||
import { TournamentCardComponent } from './components/tournament-card/tournament-card.component';
|
||||
import { UserDetailComponent } from './components/user-detail/user-detail.component';
|
||||
import { UpdateUserComponent } from './components/update-user/update-user.component';
|
||||
import { ConfirmDialogComponent } from './components/confirm-dialog/confirm-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -39,6 +40,7 @@ import { UpdateUserComponent } from './components/update-user/update-user.compon
|
|||
TournamentCardComponent,
|
||||
UserDetailComponent,
|
||||
UpdateUserComponent,
|
||||
ConfirmDialogComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<h1 mat-dialog-title>Confirm {{ actionToPerform }}</h1>
|
||||
<div mat-dialog-content>Are you sure you want to do this?</div>
|
||||
<div mat-dialog-actions>
|
||||
<button mat-flat-button color="warn" aria-label="cancel-action button" (click)="this.dialogRef.close(false);">
|
||||
Cancel
|
||||
<mat-icon>cancel</mat-icon>
|
||||
</button>
|
||||
<button mat-flat-button color="primary" aria-label="ok button" (click)="this.dialogRef.close(true);" class="center-content">
|
||||
Confirm
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ConfirmDialogComponent } from './confirm-dialog.component';
|
||||
|
||||
describe('ConfirmDialogComponent', () => {
|
||||
let component: ConfirmDialogComponent;
|
||||
let fixture: ComponentFixture<ConfirmDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ConfirmDialogComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ConfirmDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-confirm-dialog',
|
||||
templateUrl: './confirm-dialog.component.html',
|
||||
styleUrl: './confirm-dialog.component.scss'
|
||||
})
|
||||
export class ConfirmDialogComponent {
|
||||
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) private action: string,
|
||||
public dialogRef: MatDialogRef<ConfirmDialogComponent>,
|
||||
) {}
|
||||
|
||||
actionToPerform: string = this.action;
|
||||
}
|
|
@ -11,6 +11,7 @@ import { Message } from '../../dtos/message';
|
|||
import { UntypedFormBuilder, NgForm } from '@angular/forms';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { UsernameService } from 'src/app/services/user/username.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-message',
|
||||
|
@ -20,6 +21,7 @@ import { HttpErrorResponse } from '@angular/common/http';
|
|||
export class MessageComponent implements OnInit {
|
||||
// After first submission attempt, form validation will start
|
||||
submitted = false;
|
||||
username: string = ""
|
||||
|
||||
currentMessage: Message = new Message();
|
||||
|
||||
|
@ -30,7 +32,7 @@ export class MessageComponent implements OnInit {
|
|||
private formBuilder: UntypedFormBuilder,
|
||||
private cd: ChangeDetectorRef,
|
||||
private snackBar: MatSnackBar,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.loadMessage();
|
||||
|
|
|
@ -11,6 +11,7 @@ import { AuthService } from '../../services/auth.service';
|
|||
import { Router } from '@angular/router';
|
||||
import { AuthRequest } from 'src/app/dtos/auth-request';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { UsernameService } from 'src/app/services/user/username.service';
|
||||
|
||||
const passwordMatchingValidator: ValidatorFn = (
|
||||
control: AbstractControl,
|
||||
|
@ -46,6 +47,7 @@ export class RegisterComponent {
|
|||
private authService: AuthService,
|
||||
private router: Router,
|
||||
private snackBar: MatSnackBar,
|
||||
private usernameService: UsernameService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
@ -78,6 +80,7 @@ export class RegisterComponent {
|
|||
this.snackBar.open(`Successfully registered new user '${authRequest.username}'`, 'Close', {
|
||||
duration: 3000,
|
||||
});
|
||||
this.usernameService.setData(authRequest.username);
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
error: error => {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { FormControl, FormGroup, UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Router } from '@angular/router';
|
||||
import { UserEndpointService, UserLoginDto } from 'openapi-generated';
|
||||
import { AuthRequest } from 'src/app/dtos/auth-request';
|
||||
import { AuthService } from 'src/app/services/auth.service';
|
||||
import { UserService } from 'src/app/services/user/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-update-user',
|
||||
|
@ -19,12 +20,12 @@ export class UpdateUserComponent {
|
|||
});
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) private userInfo: String,
|
||||
@Inject(MAT_DIALOG_DATA) private userInfo: string,
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
private router: Router,
|
||||
private dialogRef: MatDialogRef<UpdateUserComponent>,
|
||||
private snackBar: MatSnackBar,
|
||||
private userService: UserService,
|
||||
private userService: UserEndpointService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
this.updateForm = this.formBuilder.group({
|
||||
|
@ -38,11 +39,11 @@ export class UpdateUserComponent {
|
|||
*/
|
||||
updateUser() {
|
||||
if (this.updateForm.valid) {
|
||||
const updatedInfo: AuthRequest = new AuthRequest(
|
||||
this.updateForm.controls.username.value!,
|
||||
this.updateForm.controls.password.value!,
|
||||
);
|
||||
this.userService.update(updatedInfo, this.userInfo).subscribe({
|
||||
const updatedInfo: UserLoginDto = {
|
||||
username: this.updateForm.controls.username.value!,
|
||||
password: this.updateForm.controls.password.value!,
|
||||
};
|
||||
this.userService.update(this.userInfo, updatedInfo).subscribe({
|
||||
next: next => {
|
||||
this.snackBar.open('Successfully updated user', 'OK', { duration: 3000 });
|
||||
this.authService.logoutUser();
|
||||
|
@ -51,7 +52,7 @@ export class UpdateUserComponent {
|
|||
},
|
||||
error: error => {
|
||||
console.log(error);
|
||||
this.snackBar.open('Error updating account data.', 'OK', { duration: 2500 });
|
||||
this.defaultServiceErrorHandling(error);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
@ -62,4 +63,17 @@ export class UpdateUserComponent {
|
|||
cancel() {
|
||||
console.log('Cancel Update User');
|
||||
}
|
||||
|
||||
private defaultServiceErrorHandling(error: HttpErrorResponse) {
|
||||
let errorMessage = '';
|
||||
console.log(JSON.stringify(error))
|
||||
if (typeof error.error === 'object') {
|
||||
errorMessage = error.error.error;
|
||||
} else {
|
||||
errorMessage = error.error;
|
||||
}
|
||||
this.snackBar.open("Error: " + errorMessage, 'OK', {
|
||||
duration: 5000,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,12 @@
|
|||
<mat-card-title>User Information</mat-card-title>
|
||||
<mat-card-content>
|
||||
<p><strong>Username:</strong> {{ username }}</p>
|
||||
<p><strong>Password:</strong> {{ password }}</p>
|
||||
<p><strong>Open Registrations:</strong> {{ openTournaments }}</p>
|
||||
<p><strong>Closed Registrations:</strong> {{ closedTournaments }}</p>
|
||||
<p><strong>List of Tournaments:</strong></p>
|
||||
<ul>
|
||||
<li *ngFor="let tournament of tournaments">{{ tournament }}</li>
|
||||
</ul>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button color="warn" (click)="onDelete()">
|
||||
|
|
|
@ -7,6 +7,8 @@ import { OpenLoginService } from 'src/app/services/open-login.service';
|
|||
import { UserService } from 'src/app/services/user/user.service';
|
||||
import { UpdateUserComponent } from '../update-user/update-user.component';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { UserEndpointService, UserDetailDto } from 'openapi-generated';
|
||||
import { ConfirmDialogComponent } from '../confirm-dialog/confirm-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-detail',
|
||||
|
@ -15,14 +17,15 @@ import { HttpErrorResponse } from '@angular/common/http';
|
|||
})
|
||||
export class UserDetailComponent implements OnInit {
|
||||
username: string = '';
|
||||
password: string = '';
|
||||
tournaments: Array<string> = [];
|
||||
closedTournaments: number = -1;
|
||||
openTournaments: number = -1;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private authService: AuthService,
|
||||
private openLoginService: OpenLoginService,
|
||||
private userService: UserService,
|
||||
private userEndpointService: UserEndpointService,
|
||||
private snackBar: MatSnackBar,
|
||||
private matDialog: MatDialog,
|
||||
) {}
|
||||
|
@ -30,11 +33,13 @@ export class UserDetailComponent implements OnInit {
|
|||
ngOnInit(): void {
|
||||
this.route.params.subscribe(params => {
|
||||
this.username = params['username'];
|
||||
console.log(params['username']);
|
||||
this.userService.detail(this.username).subscribe({
|
||||
next: next => {
|
||||
console.log("UserDetailCOmponent: " + params['username']);
|
||||
this.userEndpointService.details(this.username).subscribe({
|
||||
next: next => {
|
||||
this.username = next.username;
|
||||
this.password = next.password;
|
||||
this.openTournaments = next.openTournaments;
|
||||
this.closedTournaments = next.closedTournaments;
|
||||
this.tournaments = next.tournaments;
|
||||
},
|
||||
error: error => {
|
||||
console.error('Error fetching user data', error);
|
||||
|
@ -46,16 +51,21 @@ export class UserDetailComponent implements OnInit {
|
|||
|
||||
onDelete() {
|
||||
console.log('Delete user');
|
||||
this.userService.delete(this.username).subscribe({
|
||||
next: resp => {
|
||||
this.authService.logoutUser();
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
error: error => {
|
||||
console.error('Error deleting user', error);
|
||||
this.defaultServiceErrorHandling(error);
|
||||
},
|
||||
});
|
||||
const dialogRef = this.matDialog.open(ConfirmDialogComponent, { width: '300px', data: `Delete ${this.username}` })
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.userEndpointService._delete(this.username).subscribe({
|
||||
next: _ => {
|
||||
this.authService.logoutUser();
|
||||
this.router.navigate(['/']);
|
||||
},
|
||||
error: error => {
|
||||
console.error('Error deleting user', error);
|
||||
this.defaultServiceErrorHandling(error);
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onChange() {
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, OnInit } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UsernameService {
|
||||
export class UsernameService implements OnInit {
|
||||
inited: boolean = false;
|
||||
|
||||
ngOnInit(): void {
|
||||
console.log("OnINit Usernameservice");
|
||||
this.inited = true;
|
||||
}
|
||||
private username: string = '';
|
||||
|
||||
setData(data: string) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@import '@fontsource/roboto';
|
||||
@import '@fontsource/material-icons';
|
||||
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
|
|
Loading…
Reference in a new issue