Skip to content

Commit

Permalink
Merge pull request #34 from AhmedYahia74/get-and-update-user-profile
Browse files Browse the repository at this point in the history
Get and update user profile
  • Loading branch information
AhmedYahia74 authored Oct 10, 2024
2 parents ecdb235 + e93b497 commit c49077a
Show file tree
Hide file tree
Showing 17 changed files with 329 additions and 18 deletions.
72 changes: 72 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,78 @@ Flyway is used to manage database migrations. The SQL scripts are located in `sr
- `id`: The ID of the user to reactivate
- **Response:** A `ResponseDto` object containing the result of the operation.
</details>
<details>
<summary>Get user profile</summary>

- **URL:** `/api/users/profile/{userId}`
- **Method:** `GET`
- **Description:** Retrieve the profile information for a specific user.
- **Path Parameters:**
- `id` (required): The ID of the user whose profile is to be retrieved.
- **Response:**
- **Status Code:** `200 OK`
- **Body:**
```json
{
"status": "OK",
"success": true,
"data": {
"id": 160,
"firstName": "Teddy",
"lastName": "Johnson",
"title": null,
"description": null,
"hourlyRate": null,
"location": null
},
"error": null
}
```
</details>
<details>
<summary>Update user profile</summary>

- **URL:** `/api/users/profile/{id}`
- **Method:** `PUT`
- **Description:** Update the profile information for a specific user.
- **Path Parameters:**
- `id` (required): The ID of the user whose currently logged in.
- **Request Body:**
- **Content-Type:** `application/json`
- **Body Example:**
```json
{
"id": 160,
"firstName": "string",
"lastName": "string",
"title": "string",
"description": "string",
"hourlyRate": 0,
"location": "string"
}
```
- **Response:**
- **Status Code:** `200 OK`
- **Body Example:**
```json
{
"status": "OK",
"success": true,
"data": {
"id": 160,
"firstName": "string",
"lastName": "string",
"title": "string",
"description": "string",
"hourlyRate": 0,
"location": "string"
},
"error": null
}

```

</details>

### Password Management

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

@SpringBootApplication
@EnableJpaAuditing

public class UpworkApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public ResponseEntity<ResponseDto> registerUser(@Valid @RequestBody Registration
description = "Login",
security = @SecurityRequirement(name = "")
)
@PostMapping("login")
@PostMapping("login")
public ResponseEntity<?> login(@Valid @RequestBody LoginRequestDto loginRequestDto) {
ResponseDto responseDto = authService.login(loginRequestDto);
Map<String, ResponseCookie> cookies = (Map<String, ResponseCookie>) responseDto.getData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.activecourses.upwork.exception.TokenRefreshException;
import com.activecourses.upwork.model.User;
import com.activecourses.upwork.service.authentication.AuthService;
import com.activecourses.upwork.service.authentication.RefreshTokenService;
import com.activecourses.upwork.service.RefreshTokenService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
package com.activecourses.upwork.controller.user;

import com.activecourses.upwork.dto.ResponseDto;
import com.activecourses.upwork.dto.user.UserProfileDto;
import com.activecourses.upwork.dto.user.UserResponseDto;
import com.activecourses.upwork.service.user.UserProfileService;
import com.activecourses.upwork.service.user.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.bind.annotation.*;

@Tag(name = "User", description = "User API")
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
@Tag(name = "User", description = "User API")
@RequestMapping("/api/users/")
public class UserController {

private final UserService userService;
private final UserProfileService userProfileService;

// TODO: update it so than it can be sorted by multiple fields
@Operation(summary = "Get all users",
Expand Down Expand Up @@ -54,4 +54,37 @@ public ResponseEntity<ResponseDto> getAllUsers(
.status(HttpStatus.OK)
.build());
}
}

@Operation(summary = "Get User Profile",
description = "Retrieve the profile information of the user specified by the userId.")
@GetMapping("/profile/{userId}")
public ResponseEntity<?> getUserProfile(@PathVariable int userId, HttpServletRequest httpRequest) {
try {
return userProfileService.getUserProfile(userId);
} catch (Exception e) {
return ResponseEntity.badRequest().body(ResponseDto.builder()
.status(HttpStatus.BAD_REQUEST)
.success(false)
.data(e.getMessage())
.build());
}
}

@Operation(summary = "Update User Profile",
description = "Update the profile information of the user specified by the userId")
@PutMapping("/profile/{userId}")
public ResponseEntity<?> updateUserProfile(
@PathVariable int userId,
@RequestBody @Valid UserProfileDto updateRequest) {
try {
return userProfileService.UpdateUserProfile(userId,updateRequest);
} catch (Exception e) {
return ResponseEntity.badRequest().body(ResponseDto.builder()
.status(HttpStatus.BAD_REQUEST)
.success(false)
.data(e.getMessage())
.build());
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.activecourses.upwork.dto.user;

import jakarta.persistence.Id;
import jakarta.validation.constraints.NotBlank;
import lombok.Builder;
import lombok.Data;

import java.math.BigDecimal;

@Data
@Builder
public class UserProfileDto {
@Id
private int id;
@NotBlank(message = "First Name is required")
private String firstName;
@NotBlank(message = "Last Name is required")
private String lastName;

private String title;

private String description;

private BigDecimal hourlyRate;

private String location;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.activecourses.upwork.dto.user;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserResponseDto {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.activecourses.upwork.mapper.user;

import com.activecourses.upwork.dto.user.UserProfileDto;
import com.activecourses.upwork.mapper.Mapper;
import com.activecourses.upwork.model.User;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@AllArgsConstructor
public class UserProfileDtoMapper implements Mapper<User, UserProfileDto> {
@Override
public UserProfileDto mapTo(User user) {
return UserProfileDto.builder()
.id(user.getId())
.title(user.getUserProfile().getTitle())
.description(user.getUserProfile().getDescription())
.hourlyRate(user.getUserProfile().getHourlyRate())
.location(user.getUserProfile().getLocation())
.firstName(user.getFirstName())
.lastName(user.getLastName())
.build();
}

@Override
public User mapFrom(UserProfileDto userProfileDto) {
return null;
}

}
3 changes: 2 additions & 1 deletion src/main/java/com/activecourses/upwork/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ public class User implements UserDetails, Principal {

@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, optional = true)
private RefreshToken refreshToken;

@OneToOne(mappedBy = "user",cascade = CascadeType.ALL)
private UserProfile userProfile;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/com/activecourses/upwork/model/UserProfile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.activecourses.upwork.model;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.math.BigDecimal;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Builder
@EntityListeners(AuditingEntityListener.class)
@Table(name = "user_profiles")
public class UserProfile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer profileId;

private String title;

private String description;

@Column(precision = 19, scale = 2) // Example precision and scale
private BigDecimal hourlyRate;


private String location;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id", unique = true)
private User user;

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.activecourses.upwork.service.authentication;
package com.activecourses.upwork.service;

import com.activecourses.upwork.config.security.jwt.JwtService;
import com.activecourses.upwork.dto.ResponseDto;
Expand Down Expand Up @@ -78,6 +78,9 @@ public ResponseEntity<ResponseDto> refreshToken(HttpServletRequest request) {
private String getRefreshTokenFromRequest(HttpServletRequest request) {
return jwtService.getJwtRefreshFromCookies(request);
}
private String getTokenFromRequest(HttpServletRequest request) {
return jwtService.getJwtFromCookies(request);
}

private RefreshToken getRefreshTokenEntity(String refreshToken) {
return findByToken(refreshToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import com.activecourses.upwork.mapper.Mapper;
import com.activecourses.upwork.model.RefreshToken;
import com.activecourses.upwork.model.User;
import com.activecourses.upwork.model.UserProfile;
import com.activecourses.upwork.repository.user.UserRepository;
import com.activecourses.upwork.config.security.jwt.JwtService;

import com.activecourses.upwork.service.RefreshTokenService;
import lombok.RequiredArgsConstructor;

import java.util.Map;
Expand Down Expand Up @@ -49,6 +51,7 @@ public class AuthServiceImpl implements AuthService {
public RegistrationResponseDto registerUser(RegistrationRequestDto registrationRequestDto) {
User user = userMapper.mapFrom(registrationRequestDto);
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setUserProfile(new UserProfile());
userRepository.save(user);

return RegistrationResponseDto
Expand Down
Loading

0 comments on commit c49077a

Please sign in to comment.