Commit e3bc6200 by Ninh Hoang Cuong

update and get settings

parent ef7e5aee
......@@ -17,7 +17,7 @@ public class OpenAPIConfig {
return new OpenAPI()
.servers(
Arrays.asList(
new Server().url("http://localhost:8080"),
new Server().url("http://localhost:8085"),
new Server().url("https://user.loda.me")
)
)
......
......@@ -8,6 +8,7 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
......@@ -48,14 +49,23 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests().antMatchers("/feedback-settings/**").permitAll().anyRequest().permitAll();
http
.authorizeRequests()
.antMatchers("/v3/api-docs/**","/swagger-ui/**","/swagger-ui.html")
.permitAll();
http.authorizeRequests().antMatchers("/feedback-settings/**").permitAll();
http.authorizeRequests().antMatchers("/auth/signup").permitAll();
http.authorizeRequests().antMatchers("/auth/changepass").authenticated();
http.authorizeRequests().antMatchers("/auth/**").permitAll().anyRequest().authenticated();
// http.authorizeRequests().antMatchers("/admin/**").hasAuthority("admin");
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
// http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
......
package com.feedback.demo.controllers;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Tag(name = "Feed Back Options")
@RequestMapping("/feedback-options")
public class FeedBackOptionsController {
}
package com.feedback.demo.controllers;
import com.feedback.demo.dto.FeedBackSettingsDTO;
import com.feedback.demo.dto.FeedBackSettingsRequest;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.repositories.UserRepository;
import com.feedback.demo.service.FeedBackSettingsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
......@@ -23,11 +23,9 @@ import javax.validation.Valid;
public class FeedBackSettingsController {
@Autowired
private FeedBackSettingsService feedBackSettingsService;
@Autowired
private UserRepository userRepository;
@Operation(description = "Update FeedBack settings", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = FeedBackSettings.class))), responseCode = "200")
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = FeedBackSettingsRequest.class))), responseCode = "200")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Thành công"),
......@@ -36,14 +34,14 @@ public class FeedBackSettingsController {
@ApiResponse(responseCode = "403", description = "Truy cập bị cấm"),
})
@PostMapping("/update")
public ResponseEntity<FeedBackSettingsDTO> addFeedbackSettings(@Valid @RequestBody FeedBackSettingsDTO feedBackSettingsDTO){
return ResponseEntity.ok(feedBackSettingsService.updateSettings(feedBackSettingsDTO));
public ResponseEntity<FeedBackSettingsRequest> addFeedbackSettings(@Valid @RequestBody FeedBackSettingsRequest fsRequest){
return ResponseEntity.ok(feedBackSettingsService.updateSettings(fsRequest));
}
@Operation(description = "Get FeedBack settings", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = FeedBackSettings.class))), responseCode = "200")
})
@GetMapping("/")
public ResponseEntity<FeedBackSettingsDTO> getFeedbackSettings(){
public ResponseEntity<FeedBackSettingsRequest> getFeedbackSettings(){
return ResponseEntity.ok(feedBackSettingsService.getFeedbackSettings());
}
}
package com.feedback.demo.controllers;
import com.feedback.demo.dto.ChangePasswordRequest;
import com.feedback.demo.dto.LoginRequest;
import com.feedback.demo.dto.LoginResponse;
import com.feedback.demo.dto.SignupRequest;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.repositories.UserRepository;
import com.feedback.demo.service.JwtService;
import com.feedback.demo.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.io.IOException;
@RestController
@Tag(name = "User")
public class UserController {
@Autowired
private UserService userService;
@Autowired
UserRepository userRepository;
@Autowired
JwtService jwtService;
@Operation(description = "Update FeedBack settings", responses = {
@ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = FeedBackSettings.class))), responseCode = "200")
})
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Thành công"),
@ApiResponse(responseCode = "404", description = "Không tìm thấy"),
@ApiResponse(responseCode = "401", description = "Chưa xác thực"),
@ApiResponse(responseCode = "403", description = "Truy cập bị cấm"),
})
@PostMapping("/auth/login")
public LoginResponse login(@Valid @RequestBody LoginRequest loginRequest) {
return userService.getLoginResponse(loginRequest.getUsername(), loginRequest.getPassword());
}
@PostMapping("/auth/changepass")
public LoginResponse changePassword(@Valid @RequestBody ChangePasswordRequest changePasswordRequest) {
return userService.changePassword(changePasswordRequest);
}
@PostMapping("/auth/signup")
public LoginResponse signup(@Valid @RequestBody SignupRequest signupRequest) throws Exception {
System.out.println(signupRequest);
return userService.signUp(signupRequest);
}
@GetMapping("/auth/verify/{token}")
public LoginResponse checkToken(@PathVariable String token) throws IOException {
return userService.checkToken(token);
}
}
......@@ -5,6 +5,9 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@AllArgsConstructor
@NoArgsConstructor
......@@ -12,7 +15,10 @@ import lombok.NoArgsConstructor;
public class FeedBackOptionsDTO {
private Long id;
@NotNull
private Integer optionOrder;
@NotBlank
private String optionValue;
private Integer optionOrder;
}
package com.feedback.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FeedBackSettingsRequest {
private Long id;
@NotNull
private Integer position;
private String iconURL;
@NotBlank
private String feedbackTitle;
@NotBlank
private String titleFullName;
@NotBlank
private String titleEmail;
@NotBlank
private String titlePhoneNumber;
@NotBlank
private String titleOptions;
@NotBlank
private String titleDescription;
@NotNull
@Size(min = 5,max = 5)
private List<FeedBackOptionsDTO> optionSettings = new ArrayList<>();
}
......@@ -45,7 +45,7 @@ public class FeedBack {
@Column(name ="last_modified_date")
private Date updateDate;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
}
package com.feedback.demo.entities;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.util.Date;
......@@ -17,6 +14,7 @@ import java.util.Date;
@NoArgsConstructor
@Builder
@Table
@EntityListeners(AuditingEntityListener.class)
public class FeedBackOptions {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
......@@ -36,8 +34,10 @@ public class FeedBackOptions {
@Column(name ="last_modified_date")
private Date updateDate;
@JsonIgnore
@OneToOne(fetch = FetchType.LAZY)
// @JsonIgnore
@EqualsAndHashCode.Exclude
@ToString.Exclude
@ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
}
......@@ -47,8 +47,8 @@ public class FeedBackSettings {
@Column(name ="last_modified_date")
private Date updateDate;
@JsonIgnore
@OneToOne(fetch = FetchType.LAZY)
// @JsonIgnore
@OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
}
......@@ -36,6 +36,7 @@ public class User {
@Column(unique = true,length = 300)
private String email;
@Column(length = 20)
private String phone;
......@@ -56,11 +57,11 @@ public class User {
@LastModifiedDate
private Date updateDate;
@OneToMany(mappedBy ="user",fetch = FetchType.LAZY)
@OneToMany(mappedBy ="user",fetch = FetchType.LAZY,cascade = CascadeType.ALL)
private List<FeedBack> feedBacks = new ArrayList<>();
@OneToOne(mappedBy = "user",cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
private FeedBackOptions feedBackOptions;
@OneToMany(mappedBy = "user",cascade = CascadeType.ALL,fetch = FetchType.LAZY)
private List<FeedBackOptions> feedBackOptions;
@OneToOne(mappedBy = "user",cascade = CascadeType.ALL,fetch = FetchType.LAZY,optional = false)
private FeedBackSettings feedBackSettings;
......
package com.feedback.demo.mappers;
import com.feedback.demo.dto.FeedBackOptionsDTO;
import com.feedback.demo.entities.FeedBackOptions;
public class FeedBackOptionsMapper {
public static FeedBackOptions toEntity(FeedBackOptionsDTO feedBackOptionsDTO){
return FeedBackOptions.builder()
.optionOrder(feedBackOptionsDTO.getOptionOrder())
.optionValue(feedBackOptionsDTO.getOptionValue())
.build();
}
public static FeedBackOptionsDTO toDTO(FeedBackOptions feedBackOptions){
return FeedBackOptionsDTO.builder()
.id(feedBackOptions.getId())
.optionOrder(feedBackOptions.getOptionOrder())
.optionValue(feedBackOptions.getOptionValue())
.build();
}
}
package com.feedback.demo.mappers;
import com.feedback.demo.dto.FeedBackSettingsDTO;
import com.feedback.demo.dto.FeedBackSettingsRequest;
import com.feedback.demo.entities.FeedBackOptions;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.entities.User;
import java.util.List;
import java.util.stream.Collectors;
public class FeedBackSettingsMapper {
public static FeedBackSettings toEntity(FeedBackSettingsDTO feedBackSettingsDTO,Long userId){
return FeedBackSettings.builder()
.id(feedBackSettingsDTO.getId())
.position(feedBackSettingsDTO.getPosition())
.iconURL(feedBackSettingsDTO.getIconURL())
.feedbackTitle(feedBackSettingsDTO.getFeedbackTitle())
.titleDescription(feedBackSettingsDTO.getTitleDescription())
.titleEmail(feedBackSettingsDTO.getTitleEmail())
.titleFullName(feedBackSettingsDTO.getTitleFullName())
.titleOptions(feedBackSettingsDTO.getTitleOptions())
.titlePhoneNumber(feedBackSettingsDTO.getTitlePhoneNumber())
.createDate(feedBackSettingsDTO.getCreateDate())
.updateDate(feedBackSettingsDTO.getUpdateDate())
.user(
User.builder()
.id(userId)
.build()
)
.build();
}
// public static FeedBackSettings toEntity(FeedBackSettingsDTO feedBackSettingsDTO,Long userId){
// return FeedBackSettings.builder()
// .id(feedBackSettingsDTO.getId())
// .position(feedBackSettingsDTO.getPosition())
// .iconURL(feedBackSettingsDTO.getIconURL())
// .feedbackTitle(feedBackSettingsDTO.getFeedbackTitle())
// .titleDescription(feedBackSettingsDTO.getTitleDescription())
// .titleEmail(feedBackSettingsDTO.getTitleEmail())
// .titleFullName(feedBackSettingsDTO.getTitleFullName())
// .titleOptions(feedBackSettingsDTO.getTitleOptions())
// .titlePhoneNumber(feedBackSettingsDTO.getTitlePhoneNumber())
// .createDate(feedBackSettingsDTO.getCreateDate())
// .updateDate(feedBackSettingsDTO.getUpdateDate())
// .user(
// User.builder()
// .id(userId)
// .build()
// )
// .build();
// }
public static FeedBackSettingsDTO toDTO(FeedBackSettings feedBackSettings){
return FeedBackSettingsDTO.builder()
.id(feedBackSettings.getId())
......@@ -40,4 +45,20 @@ public class FeedBackSettingsMapper {
.updateDate(feedBackSettings.getUpdateDate())
.build();
}
public static FeedBackSettingsRequest toFBSettingsRequest(FeedBackSettings settings, List<FeedBackOptions> options){
return FeedBackSettingsRequest.builder()
.id(settings.getId())
.position(settings.getPosition())
.iconURL(settings.getIconURL())
.feedbackTitle(settings.getFeedbackTitle())
.titleDescription(settings.getTitleDescription())
.titleEmail(settings.getTitleEmail())
.titleFullName(settings.getTitleFullName())
.titleOptions(settings.getTitleOptions())
.titlePhoneNumber(settings.getTitlePhoneNumber())
.optionSettings(
options.stream().map(FeedBackOptionsMapper::toDTO).collect(Collectors.toList())
)
.build();
}
}
......@@ -4,6 +4,9 @@ import com.feedback.demo.entities.FeedBackOptions;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface FeedBackOptionsRepository extends JpaRepository<FeedBackOptions,Long> {
List<FeedBackOptions> findByUserId(Long userId);
}
package com.feedback.demo.service;
import com.feedback.demo.dto.FeedBackOptionsDTO;
import com.feedback.demo.entities.FeedBackOptions;
import com.feedback.demo.entities.User;
import com.feedback.demo.repositories.FeedBackOptionsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class FeedBackOptionsService {
@Autowired
private FeedBackOptionsRepository feedBackOptionsRepository;
@Autowired
private UserService userService;
// public FeedBackOptionsDTO updateAllFeedbackOptions(FeedBackOptionsDTO feedBackOptionsDTO){
// User currentUser = userService.getCurrentUser();
// List<FeedBackOptions> allOptions = feedBackOptionsRepository.findAllByUser(currentUser.getId());
// if (allOptions!=null){
//
// }
// }
}
package com.feedback.demo.service;
import com.feedback.demo.dto.FeedBackSettingsDTO;
import com.feedback.demo.dto.FeedBackOptionsDTO;
import com.feedback.demo.dto.FeedBackSettingsRequest;
import com.feedback.demo.entities.FeedBackOptions;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.entities.User;
import com.feedback.demo.mappers.FeedBackSettingsMapper;
import com.feedback.demo.repositories.FeedBackOptionsRepository;
import com.feedback.demo.repositories.FeedBackSettingsRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class FeedBackSettingsService {
@Autowired
private FeedBackSettingsRepository feedBackSettingsRepository;
@Autowired
private FeedBackOptionsRepository feedBackOptionsRepository;
@Autowired
private UserService userService;
public FeedBackSettingsDTO updateSettings(FeedBackSettingsDTO feedBackSettingsDTO){
public FeedBackSettingsRequest updateSettings(FeedBackSettingsRequest fsRequest) {
User user = userService.getCurrentUser();
FeedBackSettings settings = feedBackSettingsRepository.findByUserId(user.getId());
if (settings==null){
List<FeedBackOptions> options = feedBackOptionsRepository.findByUserId(user.getId());
if (settings == null) {
throw new RuntimeException("setting not available ! ");
}
settings.setPosition(feedBackSettingsDTO.getPosition());
settings.setIconURL(feedBackSettingsDTO.getIconURL());
settings.setFeedbackTitle(feedBackSettingsDTO.getFeedbackTitle());
settings.setTitleFullName(feedBackSettingsDTO.getTitleFullName());
settings.setTitleEmail(feedBackSettingsDTO.getTitleEmail());
settings.setTitlePhoneNumber(feedBackSettingsDTO.getTitlePhoneNumber());
settings.setTitleOptions(feedBackSettingsDTO.getTitleOptions());
settings.setTitleDescription(feedBackSettingsDTO.getTitleDescription());
return FeedBackSettingsMapper.toDTO(feedBackSettingsRepository.save(settings));
if (options == null) {
throw new RuntimeException("option not available ! ");
}
updateSettings(settings, fsRequest);
updateOptions(options, fsRequest.getOptionSettings());
try {
feedBackSettingsRepository.save(settings);
feedBackOptionsRepository.saveAll(options);
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException("Setting error ! ");
}
return fsRequest;
}
public FeedBackSettingsDTO getFeedbackSettings(){
public FeedBackSettingsRequest getFeedbackSettings() {
User user = userService.getCurrentUser();
FeedBackSettings settings = feedBackSettingsRepository.findByUserId(user.getId());
if (settings==null){
List<FeedBackOptions> options = feedBackOptionsRepository.findByUserId(user.getId());
if (settings == null) {
throw new RuntimeException("setting not available ! ");
}
return FeedBackSettingsMapper.toDTO(settings);
if (options == null) {
throw new RuntimeException("option not available ! ");
}
options.sort(Comparator.comparingInt(FeedBackOptions::getOptionOrder));
return FeedBackSettingsMapper.toFBSettingsRequest(settings,options);
}
private void updateSettings(FeedBackSettings fs, FeedBackSettingsRequest fsRequest) {
fs.setPosition(fsRequest.getPosition());
fs.setIconURL(fsRequest.getIconURL());
fs.setFeedbackTitle(fsRequest.getFeedbackTitle());
fs.setTitleFullName(fsRequest.getTitleFullName());
fs.setTitleEmail(fsRequest.getTitleEmail());
fs.setTitlePhoneNumber(fsRequest.getTitlePhoneNumber());
fs.setTitleOptions(fsRequest.getTitleOptions());
fs.setTitleDescription(fsRequest.getTitleDescription());
}
private void updateOptions(List<FeedBackOptions> foList, List<FeedBackOptionsDTO> foRequest) {
foList.forEach(fo -> {
foRequest.stream()
.filter(i -> i.getId().equals(fo.getId()))
.forEach(i -> {
fo.setOptionOrder(i.getOptionOrder());
fo.setOptionValue(i.getOptionValue());
});
});
}
}
......@@ -4,6 +4,8 @@ import com.feedback.demo.config.CustomUserDetail;
import com.feedback.demo.dto.ChangePasswordRequest;
import com.feedback.demo.dto.LoginResponse;
import com.feedback.demo.dto.SignupRequest;
import com.feedback.demo.entities.FeedBackOptions;
import com.feedback.demo.entities.FeedBackSettings;
import com.feedback.demo.entities.User;
import com.feedback.demo.exceptionhandle.ApiMissingException;
import com.feedback.demo.exceptionhandle.UsernameIsAlreadyTakenException;
......@@ -16,10 +18,16 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
@Service
@Transactional(rollbackFor = Exception.class)
public class UserService {
@Autowired
private UserRepository userRepository;
......@@ -82,17 +90,63 @@ public class UserService {
if (userCheck != null) {
throw new UsernameIsAlreadyTakenException();
}
userRepository.save(
User.builder()
.username(signupRequest.getUsername())
.password(
passwordEncoder.encode(signupRequest.getPassword())
)
.email(signupRequest.getEmail())
.phone(signupRequest.getPhone())
.domain(signupRequest.getDomain())
.build()
);
User user = User.builder()
.username(signupRequest.getUsername())
.password(
passwordEncoder.encode(signupRequest.getPassword())
)
.email(signupRequest.getEmail())
.phone(signupRequest.getPhone())
.domain(signupRequest.getDomain())
.feedBacks(null)
.build();
FeedBackSettings defaultSettings = getDefaultSettings();
defaultSettings.setUser(user);
user.setFeedBackSettings(defaultSettings);
List<FeedBackOptions> defaultOptions = getDefaultOptions(user);
user.setFeedBackOptions(defaultOptions);
userRepository.save(user);
return getLoginResponse(signupRequest.getUsername(),signupRequest.getPassword());
}
public FeedBackSettings getDefaultSettings(){
return FeedBackSettings.builder()
.position(1)
.feedbackTitle("Hệ thống gửi phản hồi")
.titleFullName("Họ và tên")
.titleEmail("Email")
.titlePhoneNumber("Số điện thoại")
.titleOptions("Danh mục phải hồi")
.titleDescription("Nội dung chi tiết")
.iconURL(null)
.build();
}
public List<FeedBackOptions> getDefaultOptions(User user){
List<FeedBackOptions> feedBackOptions = new ArrayList<>();
feedBackOptions.add(FeedBackOptions.builder()
.optionOrder(1)
.optionValue("Sản phẩm rất tốt")
.user(user)
.build());
feedBackOptions.add(FeedBackOptions.builder()
.optionOrder(2)
.optionValue("Sản phẩm tốt")
.user(user)
.build());
feedBackOptions.add(FeedBackOptions.builder()
.optionOrder(3)
.optionValue("Sản phẩm bình thường")
.user(user)
.build());
feedBackOptions.add(FeedBackOptions.builder()
.optionOrder(4)
.optionValue("Sản phẩm kém")
.user(user)
.build());
feedBackOptions.add(FeedBackOptions.builder()
.optionOrder(5)
.optionValue("Sản phẩm quá kém")
.user(user)
.build());
return feedBackOptions;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment