mirror of
https://gitee.com/youlaitech/youlai-mall.git
synced 2024-12-23 05:00:25 +08:00
wip: 基础框架同步
This commit is contained in:
parent
ce243d8137
commit
cce4f8845e
@ -53,4 +53,15 @@ public interface RedisConstants {
|
||||
*/
|
||||
String PRODUCT_SKUS_LOCK_PREFIX = "product:skus:lock:";
|
||||
|
||||
/**
|
||||
* 手机验证码缓存前缀
|
||||
*/
|
||||
|
||||
String MOBILE_VERIFICATION_CODE_PREFIX = "verification_code:mobile:";
|
||||
|
||||
/**
|
||||
* 邮箱验证码缓存前缀
|
||||
*/
|
||||
String EMAIL_VERIFICATION_CODE_PREFIX = "verification_code:email:";
|
||||
|
||||
}
|
||||
|
@ -48,8 +48,11 @@ public class MenuController {
|
||||
|
||||
@Operation(summary = "菜单下拉列表")
|
||||
@GetMapping("/options")
|
||||
public Result listMenuOptions() {
|
||||
List<Option> menus = menuService.listMenuOptions();
|
||||
public Result<?> listMenuOptions(
|
||||
@Parameter(description = "是否只查询父级菜单")
|
||||
@RequestParam(required = false, defaultValue = "false") boolean onlyParent
|
||||
) {
|
||||
List<Option> menus = menuService.listMenuOptions(onlyParent);
|
||||
return Result.success(menus);
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,12 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.youlai.common.result.PageResult;
|
||||
import com.youlai.common.result.Result;
|
||||
import com.youlai.common.core.annotation.RepeatSubmit;
|
||||
import com.youlai.common.security.util.SecurityUtils;
|
||||
import com.youlai.system.dto.UserAuthInfo;
|
||||
import com.youlai.system.enums.ContactType;
|
||||
import com.youlai.system.listener.excel.UserImportListener;
|
||||
import com.youlai.system.model.entity.User;
|
||||
import com.youlai.system.model.form.UserForm;
|
||||
import com.youlai.system.model.form.UserRegisterForm;
|
||||
import com.youlai.system.model.form.*;
|
||||
import com.youlai.system.model.query.UserPageQuery;
|
||||
import com.youlai.system.model.vo.*;
|
||||
import com.youlai.system.service.UserService;
|
||||
@ -181,30 +182,68 @@ public class UserController {
|
||||
.doWrite(exportUserList);
|
||||
}
|
||||
|
||||
@Operation(summary = "注册用户")
|
||||
@PostMapping("/register")
|
||||
public Result registerUser(
|
||||
@RequestBody @Valid UserRegisterForm userRegisterForm
|
||||
) {
|
||||
boolean result = userService.registerUser(userRegisterForm);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "发送注册短信验证码")
|
||||
@PostMapping("/register/sms_code")
|
||||
public Result sendRegistrationSmsCode(
|
||||
@Parameter(description = "手机号") @RequestParam String mobile
|
||||
) {
|
||||
boolean result = userService.sendRegistrationSmsCode(mobile);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取用户个人中心信息")
|
||||
@Operation(summary = "获取个人中心用户信息")
|
||||
@GetMapping("/profile")
|
||||
public Result getUserProfile() {
|
||||
UserProfileVO userProfile = userService.getUserProfile();
|
||||
public Result<UserProfileVO> getUserProfile() {
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
UserProfileVO userProfile = userService.getUserProfile(userId);
|
||||
return Result.success(userProfile);
|
||||
}
|
||||
|
||||
@Operation(summary = "修改个人中心用户信息")
|
||||
@PutMapping("/profile")
|
||||
public Result<?> updateUserProfile(@RequestBody UserProfileForm formData) {
|
||||
boolean result = userService.updateUserProfile(formData);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "重置用户密码")
|
||||
@PutMapping(value = "/{userId}/password/reset")
|
||||
@PreAuthorize("@ss.hasPerm('sys:user:password:reset')")
|
||||
public Result<?> resetPassword(
|
||||
@Parameter(description = "用户ID") @PathVariable Long userId,
|
||||
@RequestParam String password
|
||||
) {
|
||||
boolean result = userService.resetPassword(userId, password);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "修改密码")
|
||||
@PutMapping(value = "/password")
|
||||
public Result<?> changePassword(
|
||||
@RequestBody PasswordChangeForm data
|
||||
) {
|
||||
Long currUserId = SecurityUtils.getUserId();
|
||||
boolean result = userService.changePassword(currUserId, data);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "发送短信/邮箱验证码")
|
||||
@PostMapping(value = "/send-verification-code")
|
||||
public Result<?> sendVerificationCode(
|
||||
@Parameter(description = "联系方式(手机号码或邮箱地址)", required = true) @RequestParam String contact,
|
||||
@Parameter(description = "联系方式类型(Mobile或Email)", required = true) @RequestParam ContactType contactType
|
||||
) {
|
||||
boolean result = userService.sendVerificationCode(contact, contactType);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "绑定个人中心用户手机号")
|
||||
@PutMapping(value = "/mobile")
|
||||
public Result<?> bindMobile(
|
||||
@RequestBody @Validated MobileBindingForm data
|
||||
) {
|
||||
boolean result = userService.bindMobile(data);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "绑定个人中心用户邮箱")
|
||||
@PutMapping(value = "/email")
|
||||
public Result<?> bindEmail(
|
||||
@RequestBody @Validated EmailChangeForm data
|
||||
) {
|
||||
boolean result = userService.bindEmail(data);
|
||||
return Result.judge(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.youlai.system.model.bo.UserBO;
|
||||
import com.youlai.system.model.entity.User;
|
||||
import com.youlai.system.model.form.UserForm;
|
||||
import com.youlai.system.model.form.UserProfileForm;
|
||||
import com.youlai.system.model.vo.UserImportVO;
|
||||
import com.youlai.system.model.vo.UserInfoVO;
|
||||
import com.youlai.system.model.vo.UserPageVO;
|
||||
@ -43,8 +44,8 @@ public interface UserConverter {
|
||||
|
||||
User importVo2Entity(UserImportVO vo);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "genderLabel", expression = "java(com.youlai.common.base.IBaseEnum.getLabelByValue(bo.getGender(), com.youlai.common.enums.GenderEnum.class))")
|
||||
})
|
||||
|
||||
UserProfileVO toProfileVO(UserBO bo);
|
||||
|
||||
User toEntity(UserProfileForm formData);
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.youlai.system.enums;
|
||||
|
||||
/**
|
||||
* 联系方式类型
|
||||
*
|
||||
* @author Ray
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public enum ContactType {
|
||||
/**
|
||||
* 手机
|
||||
*/
|
||||
MOBILE,
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
EMAIL
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.youlai.system.model.form;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 修改邮箱表单
|
||||
*
|
||||
* @author Ray
|
||||
* @since 2024/8/19
|
||||
*/
|
||||
@Schema(description = "修改邮箱表单")
|
||||
@Data
|
||||
public class EmailChangeForm {
|
||||
|
||||
@Schema(description = "原密码")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "验证码")
|
||||
private String code;
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.youlai.system.model.form;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 修改手机表单
|
||||
*
|
||||
* @author Ray
|
||||
* @since 2024/8/19
|
||||
*/
|
||||
@Schema(description = "修改手机表单")
|
||||
@Data
|
||||
public class MobileBindingForm {
|
||||
|
||||
@Schema(description = "原密码")
|
||||
private String mobile;
|
||||
|
||||
@Schema(description = "验证码")
|
||||
private String code;
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.youlai.system.model.form;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 修改密码表单
|
||||
*
|
||||
* @author Ray
|
||||
* @since 2024/8/13
|
||||
*/
|
||||
@Schema(description = "修改密码表单")
|
||||
@Data
|
||||
public class PasswordChangeForm {
|
||||
|
||||
@Schema(description = "原密码")
|
||||
private String oldPassword;
|
||||
|
||||
@Schema(description = "新密码")
|
||||
private String newPassword;
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.youlai.system.model.form;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 重置密码表单
|
||||
*
|
||||
* @author Ray
|
||||
* @since 2024/8/13
|
||||
*/
|
||||
@Schema(description = "重置密码表单")
|
||||
@Data
|
||||
public class PasswordResetForm {
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "密码")
|
||||
private String password;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.youlai.system.model.form;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 个人中心用户信息
|
||||
*
|
||||
* @author Ray
|
||||
* @since 2024/8/13
|
||||
*/
|
||||
@Schema(description = "个人中心用户信息")
|
||||
@Data
|
||||
public class UserProfileForm {
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户名")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "用户昵称")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "头像URL")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "性别")
|
||||
private Integer gender;
|
||||
|
||||
@Schema(description = "手机号")
|
||||
private String mobile;
|
||||
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
|
||||
}
|
@ -29,8 +29,10 @@ public interface MenuService extends IService<Menu> {
|
||||
|
||||
/**
|
||||
* 获取菜单下拉列表
|
||||
*
|
||||
* @param onlyParent 是否只查询父级菜单
|
||||
*/
|
||||
List<Option> listMenuOptions();
|
||||
List<Option> listMenuOptions(boolean onlyParent);
|
||||
|
||||
/**
|
||||
* 新增菜单
|
||||
|
@ -4,9 +4,9 @@ package com.youlai.system.service;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.youlai.system.dto.UserAuthInfo;
|
||||
import com.youlai.system.enums.ContactType;
|
||||
import com.youlai.system.model.entity.User;
|
||||
import com.youlai.system.model.form.UserForm;
|
||||
import com.youlai.system.model.form.UserRegisterForm;
|
||||
import com.youlai.system.model.form.*;
|
||||
import com.youlai.system.model.query.UserPageQuery;
|
||||
import com.youlai.system.model.vo.UserExportVO;
|
||||
import com.youlai.system.model.vo.UserInfoVO;
|
||||
@ -116,17 +116,66 @@ public interface UserService extends IService<User> {
|
||||
|
||||
/**
|
||||
* 发送注册短信验证码
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @return {@link Boolean} 是否发送成功
|
||||
* @param mobile
|
||||
* @return
|
||||
*/
|
||||
boolean sendRegistrationSmsCode(String mobile);
|
||||
|
||||
/**
|
||||
* 获取个人中心用户信息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
UserProfileVO getUserProfile(Long userId);
|
||||
|
||||
/**
|
||||
* 获取用户个人中心信息
|
||||
* 修改个人中心用户信息
|
||||
*
|
||||
* @return {@link UserProfileVO}
|
||||
* @param formData 表单数据
|
||||
* @return
|
||||
*/
|
||||
UserProfileVO getUserProfile();
|
||||
boolean updateUserProfile(UserProfileForm formData);
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param data 修改密码表单数据
|
||||
* @return
|
||||
*/
|
||||
boolean changePassword(Long userId, PasswordChangeForm data);
|
||||
|
||||
/**
|
||||
* 重置用户密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param password 重置后的密码
|
||||
* @return
|
||||
*/
|
||||
boolean resetPassword(Long userId, String password);
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param contact 联系方式
|
||||
* @param type 联系方式类型
|
||||
* @return
|
||||
*/
|
||||
boolean sendVerificationCode(String contact, ContactType type);
|
||||
|
||||
/**
|
||||
* 修改当前用户手机号
|
||||
*
|
||||
* @param data 表单数据
|
||||
* @return
|
||||
*/
|
||||
boolean bindMobile(MobileBindingForm data);
|
||||
|
||||
/**
|
||||
* 修改当前用户邮箱
|
||||
*
|
||||
* @param data 表单数据
|
||||
* @return
|
||||
*/
|
||||
boolean bindEmail(EmailChangeForm data);
|
||||
}
|
||||
|
@ -98,13 +98,19 @@ public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements Me
|
||||
|
||||
/**
|
||||
* 菜单下拉数据
|
||||
*
|
||||
* @param onlyParent 是否只查询父级菜单 如果为true,排除按钮
|
||||
*/
|
||||
@Override
|
||||
public List<Option> listMenuOptions() {
|
||||
List<Menu> menuList = this.list(new LambdaQueryWrapper<Menu>().orderByAsc(Menu::getSort));
|
||||
public List<Option> listMenuOptions(boolean onlyParent) {
|
||||
List<Menu> menuList = this.list(new LambdaQueryWrapper<Menu>()
|
||||
.in(onlyParent, Menu::getType, MenuTypeEnum.CATALOG.getValue(), MenuTypeEnum.MENU.getValue())
|
||||
.orderByAsc(Menu::getSort)
|
||||
);
|
||||
return buildMenuOptions(GlobalConstants.ROOT_NODE_ID, menuList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 递归生成菜单下拉层级列表
|
||||
*
|
||||
|
@ -13,17 +13,18 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.youlai.common.constant.GlobalConstants;
|
||||
import com.youlai.common.constant.RedisConstants;
|
||||
import com.youlai.common.constant.SystemConstants;
|
||||
import com.youlai.common.core.exception.BusinessException;
|
||||
import com.youlai.common.security.service.PermissionService;
|
||||
import com.youlai.common.security.util.SecurityUtils;
|
||||
import com.youlai.common.sms.config.AliyunSmsProperties;
|
||||
import com.youlai.common.sms.service.SmsService;
|
||||
import com.youlai.system.converter.UserConverter;
|
||||
import com.youlai.system.dto.UserAuthInfo;
|
||||
import com.youlai.system.enums.ContactType;
|
||||
import com.youlai.system.mapper.UserMapper;
|
||||
import com.youlai.system.model.bo.UserBO;
|
||||
import com.youlai.system.model.entity.User;
|
||||
import com.youlai.system.model.form.UserForm;
|
||||
import com.youlai.system.model.form.UserRegisterForm;
|
||||
import com.youlai.system.model.form.*;
|
||||
import com.youlai.system.model.query.UserPageQuery;
|
||||
import com.youlai.system.model.vo.UserExportVO;
|
||||
import com.youlai.system.model.vo.UserInfoVO;
|
||||
@ -353,17 +354,168 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户个人中心信息
|
||||
* 获取个人中心用户信息
|
||||
*
|
||||
* @return {@link UserProfileVO}
|
||||
* @param userId 用户ID
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public UserProfileVO getUserProfile() {
|
||||
public UserProfileVO getUserProfile(Long userId) {
|
||||
UserBO entity = this.baseMapper.getUserProfile(userId);
|
||||
return userConverter.toProfileVO(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改个人中心用户信息
|
||||
*
|
||||
* @param formData 表单数据
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean updateUserProfile(UserProfileForm formData) {
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
// 获取用户个人中心信息
|
||||
UserBO userBO = this.baseMapper.getUserProfile(userId);
|
||||
return userConverter.toProfileVO(userBO);
|
||||
User entity = userConverter.toEntity(formData);
|
||||
entity.setId(userId);
|
||||
return this.updateById(entity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param data 密码修改表单数据
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean changePassword(Long userId, PasswordChangeForm data) {
|
||||
|
||||
User user = this.getById(userId);
|
||||
if (user == null) {
|
||||
throw new BusinessException("用户不存在");
|
||||
}
|
||||
|
||||
String oldPassword = data.getOldPassword();
|
||||
|
||||
// 校验原密码
|
||||
if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
|
||||
throw new BusinessException("原密码错误");
|
||||
}
|
||||
// 新旧密码不能相同
|
||||
if (passwordEncoder.matches(data.getNewPassword(), user.getPassword())) {
|
||||
throw new BusinessException("新密码不能与原密码相同");
|
||||
}
|
||||
|
||||
String newPassword = data.getNewPassword();
|
||||
return this.update(new LambdaUpdateWrapper<User>()
|
||||
.eq(User::getId, userId)
|
||||
.set(User::getPassword, passwordEncoder.encode(newPassword))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param password 密码重置表单数据
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean resetPassword(Long userId, String password) {
|
||||
return this.update(new LambdaUpdateWrapper<User>()
|
||||
.eq(User::getId, userId)
|
||||
.set(User::getPassword, passwordEncoder.encode(password))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param contact 联系方式 手机号/邮箱
|
||||
* @param type 联系方式类型 {@link ContactType}
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean sendVerificationCode(String contact, ContactType type) {
|
||||
|
||||
// 随机生成4位验证码
|
||||
String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
|
||||
// 发送验证码
|
||||
|
||||
String verificationCodePrefix = null;
|
||||
switch (type) {
|
||||
case MOBILE:
|
||||
// 获取修改密码的模板code
|
||||
String changePasswordSmsTemplateCode = aliyunSmsProperties.getTemplateCodes().get("changePassword");
|
||||
smsService.sendSms(contact, changePasswordSmsTemplateCode, "[{\"code\":\"" + code + "\"}]");
|
||||
verificationCodePrefix = RedisConstants.MOBILE_VERIFICATION_CODE_PREFIX;
|
||||
break;
|
||||
case EMAIL:
|
||||
mailService.sendMail(contact, "验证码", "您的验证码是:" + code);
|
||||
verificationCodePrefix = RedisConstants.EMAIL_VERIFICATION_CODE_PREFIX;
|
||||
break;
|
||||
default:
|
||||
throw new BusinessException("不支持的联系方式类型");
|
||||
}
|
||||
// 存入 redis 用于校验, 5分钟有效
|
||||
redisTemplate.opsForValue().set(verificationCodePrefix + contact, code, 5, TimeUnit.MINUTES );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改当前用户手机号码
|
||||
*
|
||||
* @param data 表单数据
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean bindMobile(MobileBindingForm data) {
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
User user = this.getById(userId);
|
||||
if (user == null) {
|
||||
throw new BusinessException("用户不存在");
|
||||
}
|
||||
// 校验验证码
|
||||
String verificationCode = data.getCode();
|
||||
String contact = data.getMobile();
|
||||
String verificationCodeKey = RedisConstants.MOBILE_VERIFICATION_CODE_PREFIX + contact;
|
||||
String code = redisTemplate.opsForValue().get(verificationCodeKey);
|
||||
if (!verificationCode.equals(code)) {
|
||||
throw new BusinessException("验证码错误");
|
||||
}
|
||||
// 更新手机号码
|
||||
return this.update(new LambdaUpdateWrapper<User>()
|
||||
.eq(User::getId, userId)
|
||||
.set(User::getMobile, contact)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改当前用户邮箱
|
||||
*
|
||||
* @param data 表单数据
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean bindEmail(EmailChangeForm data) {
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
User user = this.getById(userId);
|
||||
if (user == null) {
|
||||
throw new BusinessException("用户不存在");
|
||||
}
|
||||
// 校验验证码
|
||||
String verificationCode = data.getCode();
|
||||
String email = data.getEmail();
|
||||
String verificationCodeKey = RedisConstants.EMAIL_VERIFICATION_CODE_PREFIX + email;
|
||||
String code = redisTemplate.opsForValue().get(verificationCodeKey);
|
||||
if (!verificationCode.equals(code)) {
|
||||
throw new BusinessException("验证码错误");
|
||||
}
|
||||
// 更新邮箱
|
||||
return this.update(new LambdaUpdateWrapper<User>()
|
||||
.eq(User::getId, userId)
|
||||
.set(User::getEmail, email)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user