Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change avatar #143

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ build/

### VS Code ###
.vscode/
.env
.env

src/main/resources/serviceAccountKey.json
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@
<artifactId>spring-dotenv</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>8.1.0</version>
</dependency>
<dependency>
<groupId>org.instancio</groupId>
<artifactId>instancio-junit</artifactId>
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/fjb/sunrise/config/security/FirebaseConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.fjb.sunrise.config.security;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import jakarta.annotation.PostConstruct;
import java.io.FileInputStream;
import java.io.IOException;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FirebaseConfig {

@PostConstruct
public void initialize() throws IOException {
FileInputStream serviceAccount = new FileInputStream("src/main/resources/serviceAccountKey.json");

FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setStorageBucket("sun-rise-4ebbb.appspot.com")
.build();

if (FirebaseApp.getApps().isEmpty()) {
FirebaseApp.initializeApp(options);
} else {
FirebaseApp.getApps();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ public class CreateAndEditUserByAdminDTO {
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
private String avatarUrl;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fjb.sunrise.dtos.responses;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

@Data
public class UserResponseDTO {
Expand All @@ -11,5 +12,7 @@ public class UserResponseDTO {
private String lastname;
private String email;
private String phone;
private String avatarUrl;
private MultipartFile avatar;
private String role;
}
3 changes: 3 additions & 0 deletions src/main/java/com/fjb/sunrise/models/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public class User extends AuditEntity<String> implements Serializable, UserDetai
@Column(name = "verification_code")
private String verificationCode;

@Column(name = "avatar_url") // Thêm cột avatarUrl
private String avatarUrl;

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority("ROLE_" + this.role.name()));
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/fjb/sunrise/services/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.fjb.sunrise.models.User;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.web.multipart.MultipartFile;

public interface UserService {
String checkRegister(RegisterRequest registerRequest);
Expand All @@ -31,7 +32,7 @@ public interface UserService {

UserResponseDTO getInfor();

boolean editUser(UserResponseDTO userResponseDTO);
boolean editUser(UserResponseDTO userResponseDTO, MultipartFile avatarFile);

boolean checkIsEmailDuplicate(String email);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.fjb.sunrise.services.impl;

import com.google.auth.Credentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;



@Service
public class FirebaseStorageService {

private final Storage storage;
private static final Logger logger = LoggerFactory.getLogger(FirebaseStorageService.class);

public FirebaseStorageService() throws IOException {
Credentials credentials = GoogleCredentials.fromStream(
Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("serviceAccountKey.json"))
);
storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
}

public String uploadFile(MultipartFile file, Long userId) throws IOException {
// Generate a unique file name
String fileName = "avatars/userId_" + userId + "/" + UUID.randomUUID().toString() + "-"
+ file.getOriginalFilename();

// Ensure the file is not empty
if (file.isEmpty()) {
logger.error("File is empty. Upload failed.");
throw new IOException("Cannot upload an empty file.");
}

try (InputStream inputStream = file.getInputStream()) {
// Create the BlobId and BlobInfo
BlobId blobId = BlobId.of("sun-rise-4ebbb.appspot.com", fileName); // Replace with your bucket name
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType(file.getContentType()).build();

// Upload the file to Firebase Storage
storage.create(blobInfo, inputStream);
logger.info("File uploaded to Firebase Storage: {}", fileName);

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarCloud
}

// Return the publicly accessible URL
return String.format("https://storage.googleapis.com/%s/%s", "sun-rise-4ebbb.appspot.com", fileName); // Correct URL
}
}
86 changes: 37 additions & 49 deletions src/main/java/com/fjb/sunrise/services/impl/UserServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.fjb.sunrise.repositories.UserRepository;
import com.fjb.sunrise.services.UserService;
import com.fjb.sunrise.utils.Constants;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
Expand All @@ -26,37 +27,31 @@
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
@Value("${default.admin-create-key}")
private String key;
private final UserMapper mapper;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final FirebaseStorageService firebaseStorageService;

@Override
public String checkRegister(RegisterRequest registerRequest) {
//check already exist email or phone
// Check if email or phone already exists
if (userRepository.existsUserByEmailOrPhone(registerRequest.getEmail(), registerRequest.getPhone())) {
throw new DuplicatedException("Email hoặc số điện thoại đã được đăng ký!");
}

User user = mapper.toEntity(registerRequest);
User user = userMapper.toEntity(registerRequest);
user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
user.setStatus(EStatus.ACTIVE);

// check password start with create admin key -> create with role admin
if (registerRequest.getPassword().startsWith(key)) {
user.setRole(ERole.ADMIN);
} else {
user.setRole(ERole.USER);
}
user.setRole(registerRequest.getPassword().startsWith(key) ? ERole.ADMIN : ERole.USER);

userRepository.save(user);

return null;
}

Expand All @@ -70,19 +65,13 @@ public String changePassword(String email, String password) {
user.setPassword(passwordEncoder.encode(password));
user.setVerificationCode(null);
userRepository.save(user);

return null;
}

@Override
public User createUserByAdmin(CreateAndEditUserByAdminDTO byAdminDTO) {
User user = mapper.toEntityCreateByAdmin(byAdminDTO);
user.setUsername(byAdminDTO.getUsername());
User user = userMapper.toEntityCreateByAdmin(byAdminDTO);
user.setPassword(passwordEncoder.encode(byAdminDTO.getPassword()));
user.setFirstname(byAdminDTO.getFirstname());
user.setLastname(byAdminDTO.getLastname());
user.setEmail(byAdminDTO.getEmail());
user.setPhone(byAdminDTO.getPhone());
user.setCreatedBy(byAdminDTO.getCreatedBy());
user.setCreatedDate(byAdminDTO.getCreatedDate());
user.setRole(ERole.valueOf(byAdminDTO.getRole()));
Expand All @@ -93,7 +82,7 @@ public User createUserByAdmin(CreateAndEditUserByAdminDTO byAdminDTO) {
@Override
public boolean updateUserByAdmin(CreateAndEditUserByAdminDTO byAdminDTO) {
User user = userRepository.findById(byAdminDTO.getId())
.orElseThrow(() -> new NotFoundException("User not found"));
.orElseThrow(() -> new NotFoundException("User not found"));

user.setUsername(byAdminDTO.getUsername());
user.setFirstname(byAdminDTO.getFirstname());
Expand Down Expand Up @@ -124,53 +113,42 @@ public void deleteUserById(Long id) {

@Override
public void deactivateUserById(Long id) {
Optional<User> userOptional = userRepository.findById(id);
if (userOptional.isPresent()) {
User user = userOptional.get();
user.setStatus(EStatus.NOT_ACTIVE);
userRepository.save(user);
} else {
throw new NotFoundException(Constants.ErrorCode.USER_NOT_FOUND);
}
User user = userRepository.findById(id)
.orElseThrow(() -> new NotFoundException(Constants.ErrorCode.USER_NOT_FOUND));
user.setStatus(EStatus.NOT_ACTIVE);
userRepository.save(user);
}

@Override
public void activateUserById(Long id) {
Optional<User> userOptional = userRepository.findById(id);
if (userOptional.isPresent()) {
User user = userOptional.get();
user.setStatus(EStatus.ACTIVE);
userRepository.save(user);
} else {
throw new NotFoundException("User not found");
}
User user = userRepository.findById(id)
.orElseThrow(() -> new NotFoundException("User not found"));
user.setStatus(EStatus.ACTIVE);
userRepository.save(user);
}

@Override
public Page<User> getUserList(DataTableInputDTO payload) {
Sort sortOpt = Sort.by(Sort.Direction.ASC, "id");
if (!payload.getOrder().isEmpty()) {
sortOpt = Sort.by(
Sort.Direction.fromString(payload.getOrder().get(0).get("dir").toUpperCase()),
payload.getOrder().get(0).get("colName"));
}
int pageNumber = payload.getStart() / 10;
if (payload.getStart() % 10 != 0) {
pageNumber = pageNumber - 1;
Sort.Direction.fromString(payload.getOrder().get(0).get("dir").toUpperCase()),
payload.getOrder().get(0).get("colName"));
}

int pageNumber = payload.getStart() / payload.getLength();
Pageable pageable = PageRequest.of(pageNumber, payload.getLength(), sortOpt);
final String keyword = payload.getSearch().getOrDefault("value", "");
Specification<User> specs = null;

if (StringUtils.hasText(keyword)) {
String likePattern = "%" + keyword.toLowerCase() + "%";
specs = (root, query, builder) ->
builder.or(
builder.like(builder.lower(root.get("username")), likePattern),
builder.like(builder.lower(root.get("phone")), likePattern),
builder.like(builder.lower(root.get("email")), likePattern)
);
builder.or(
builder.like(builder.lower(root.get("username")), likePattern),
builder.like(builder.lower(root.get("phone")), likePattern),
builder.like(builder.lower(root.get("email")), likePattern)
);
}
return userRepository.findAll(specs, pageable);
}
Expand All @@ -188,7 +166,7 @@ public UserResponseDTO getInfor() {
}

@Override
public boolean editUser(UserResponseDTO userResponseDTO) {
public boolean editUser(UserResponseDTO userResponseDTO, MultipartFile avatarFile) {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
User user = userRepository.findByEmailOrPhone(name);
if (user == null) {
Expand All @@ -197,6 +175,18 @@ public boolean editUser(UserResponseDTO userResponseDTO) {
user.setUsername(userResponseDTO.getUsername());
user.setFirstname(userResponseDTO.getFirstname());
user.setLastname(userResponseDTO.getLastname());
user.setPhone(userResponseDTO.getPhone());
user.setEmail(userResponseDTO.getEmail());

if (avatarFile != null && !avatarFile.isEmpty()) {
try {
String avatarUrl = firebaseStorageService.uploadFile(avatarFile, user.getId());
user.setAvatarUrl(avatarUrl);
} catch (IOException e) {
e.printStackTrace();
}
}

userRepository.save(user);
return true;
}
Expand Down Expand Up @@ -242,6 +232,4 @@ public String processPasswordChange(String oldPassword, String newPassword) {
public List<User> findAllNormalUser() {
return userRepository.findAllByRole(ERole.USER);
}

}

3 changes: 3 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ spring:
springframework:
security: DEBUG
aop: DEBUG
com:
fjb:
sunrise: DEBUG

server:
port: ${SERVER_LOCAL_PORT}
Expand Down
Loading
Loading