mirror of
https://github.com/blossom-editor/blossom
synced 2024-11-17 14:39:21 +08:00
Merge branch 'blossom-editor:dev' into dev
This commit is contained in:
commit
106ae03a3d
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blossom-backend</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.blossom.backend.base.auth;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.blossom.backend.base.auth.pojo.LoginReq;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.auth.pojo.AccessToken;
|
||||
import com.blossom.backend.base.auth.pojo.KickOutReq;
|
||||
import com.blossom.backend.base.auth.pojo.LoginReq;
|
||||
import com.blossom.backend.base.user.UserTypeEnum;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -52,6 +55,18 @@ public class AuthController {
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 踢出用户
|
||||
*
|
||||
* @since 1.13.0
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("kickout")
|
||||
public R<?> kickout(@RequestBody KickOutReq req) {
|
||||
authService.kickout(req.getUserId());
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 Token 状态
|
||||
*/
|
||||
|
@ -46,6 +46,7 @@ public class AuthService extends AbstractAuthService {
|
||||
AuthException.throwBy(StrUtil.isBlank(login.getPassword()), AuthRCode.USERNAME_OR_PWD_FAULT);
|
||||
UserEntity user = userService.selectByUsername(login.getUsername());
|
||||
AuthException.throwBy(ObjUtil.isNull(user), AuthRCode.USERNAME_OR_PWD_FAULT);
|
||||
AuthException.throwBy(user.getDelTime() == null || !user.getDelTime().equals(0L), AuthRCode.USER_NOT_ENABLED);
|
||||
AuthException.throwBy(!passwordEncoder.matches(login.getPassword() + user.getSalt(), user.getPassword()), AuthRCode.USERNAME_OR_PWD_FAULT);
|
||||
fillUserDetail(accessToken, user);
|
||||
}
|
||||
@ -59,6 +60,15 @@ public class AuthService extends AbstractAuthService {
|
||||
tokenRepository.remove(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 踢出用户的所有令牌
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
public void kickout(Long userId) {
|
||||
tokenRepository.removeAll(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.blossom.backend.base.auth.annotation;
|
||||
|
||||
import com.blossom.backend.base.user.UserTypeEnum;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 接口校验用户类型
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AuthUserType {
|
||||
|
||||
/**
|
||||
* 用户的类型, 接口只允许该类型用户调用
|
||||
*/
|
||||
UserTypeEnum value();
|
||||
}
|
@ -13,6 +13,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@ -42,7 +43,7 @@ public class CaffeineTokenRepository implements TokenRepository {
|
||||
.initialCapacity(1000)
|
||||
.expireAfterWrite(client.getDuration(), TimeUnit.SECONDS)
|
||||
.removalListener((String key, AccessToken value, RemovalCause cause) ->
|
||||
log.info("Token [" + key + "] 被删除")
|
||||
log.info("Token [" + key + "] has been deleted")
|
||||
)
|
||||
.build();
|
||||
|
||||
@ -50,9 +51,10 @@ public class CaffeineTokenRepository implements TokenRepository {
|
||||
.initialCapacity(1000)
|
||||
.expireAfterWrite(client.getDuration(), TimeUnit.SECONDS)
|
||||
.removalListener((String userId, String token, RemovalCause cause) ->
|
||||
log.info("Unique Token(userId) [" + userId + "] 被删除")
|
||||
log.info("Unique Token(userId) [" + userId + "] has been deleted")
|
||||
)
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -78,6 +80,17 @@ public class CaffeineTokenRepository implements TokenRepository {
|
||||
tokenCache.invalidate(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(Long userId) {
|
||||
uniqueTokenCache.invalidate(userId);
|
||||
Map<String, AccessToken> maps = tokenCache.asMap();
|
||||
maps.forEach((k, t) -> {
|
||||
if (t.getUserId().equals(userId)) {
|
||||
tokenCache.invalidate(k);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUniqueToken(AccessToken accessToken) {
|
||||
if (accessToken == null || StrUtil.isBlank(accessToken.getToken())) {
|
||||
|
@ -27,7 +27,7 @@ public enum AuthRCode implements IRCode {
|
||||
*/
|
||||
USERNAME_OR_PWD_FAULT ("AUTH-40004", "用户名或密码错误","用户名或密码错误, 或用户名不存在。"),
|
||||
CAPTCHA_FAULT ("AUTH-40005", "验证码错误","验证码错误, 或手机号不存在。"),
|
||||
USER_NOT_ENABLED ("AUTH-40010", "用户已禁用, 暂时无法登录","用户已禁用, 暂时无法登录。"),
|
||||
USER_NOT_ENABLED ("AUTH-40010", "您的账户已被已禁用, 暂时无法登录","您的账户已被已禁用, 暂时无法登录。"),
|
||||
|
||||
/**
|
||||
* 401: 未经过认证
|
||||
|
@ -2,8 +2,10 @@ package com.blossom.backend.base.auth.interceptor;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.auth.exception.AuthException;
|
||||
import com.blossom.backend.base.auth.exception.AuthRCode;
|
||||
import com.blossom.backend.base.user.UserTypeEnum;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
@ -14,7 +16,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 判断用户的类型, 只读用户只允许发送 get 请求
|
||||
* 接口对于用户的校验
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserTypeInterceptor implements HandlerInterceptor {
|
||||
@ -28,7 +30,7 @@ public class UserTypeInterceptor implements HandlerInterceptor {
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
// 忽略静态资源处理器
|
||||
if(handler instanceof ResourceHttpRequestHandler) {
|
||||
if (handler instanceof ResourceHttpRequestHandler) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -40,12 +42,25 @@ public class UserTypeInterceptor implements HandlerInterceptor {
|
||||
if (isIgnore) {
|
||||
return true;
|
||||
}
|
||||
// GET请求校验
|
||||
if (HttpMethod.GET.name().equals(request.getMethod())) {
|
||||
return true;
|
||||
|
||||
// 校验接口允许的用户类型
|
||||
boolean isCheckUserType = handlerMethod.hasMethodAnnotation(AuthUserType.class);
|
||||
if (isCheckUserType) {
|
||||
AuthUserType userType = handlerMethod.getMethodAnnotation(AuthUserType.class);
|
||||
if (userType != null) {
|
||||
UserTypeEnum type = userType.value();
|
||||
if (!type.getType().equals(AuthContext.getType())) {
|
||||
throw new AuthException(AuthRCode.PERMISSION_DENIED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 只读账号不非 GET 请求
|
||||
if (UserTypeEnum.READONLY.getType().equals(AuthContext.getType()) && !HttpMethod.GET.name().equals(request.getMethod())) {
|
||||
throw new AuthException(AuthRCode.PERMISSION_DENIED.getCode(), "您的账号为只读账号, 无法使用该功能");
|
||||
}
|
||||
|
||||
XzException400.throwBy(UserTypeEnum.READONLY.getType().equals(AuthContext.getType()), "您的账号为只读账号, 无法使用该功能");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,10 @@ public class JWTTokenRepository implements TokenRepository {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(Long userId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUniqueToken(AccessToken accessToken) {
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.blossom.backend.base.auth.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 踢出用户
|
||||
*/
|
||||
@Data
|
||||
public class KickOutReq {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "userId 为必填项")
|
||||
private Long userId;
|
||||
}
|
@ -31,6 +31,13 @@ public interface TokenRepository {
|
||||
*/
|
||||
void remove(String token);
|
||||
|
||||
/**
|
||||
* 删除某个用户的所有 token
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void removeAll(Long userId);
|
||||
|
||||
/**
|
||||
* 保存唯一生效的 token 对象
|
||||
*
|
||||
|
@ -1,7 +1,11 @@
|
||||
package com.blossom.backend.base.paramu;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.paramu.pojo.UserParamUpdReq;
|
||||
import com.blossom.backend.base.user.UserTypeEnum;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -45,6 +49,20 @@ public class UserParamController {
|
||||
return R.ok(baseService.selectMap(AuthContext.getUserId(), true, UserParamEnum.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户参数
|
||||
*
|
||||
* @apiNote 需要管理员权限
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/upd/admin")
|
||||
public R<Map<String, String>> updByAdmin(@Validated @RequestBody UserParamUpdReq req) {
|
||||
XzException400.throwBy(ObjUtil.isNull(req.getUserId()), "用户ID为必填项");
|
||||
baseService.update(req);
|
||||
baseService.refresh();
|
||||
return R.ok(baseService.selectMap(req.getUserId(), true, UserParamEnum.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新用户配置
|
||||
*/
|
||||
|
@ -38,6 +38,11 @@ public enum UserParamEnum {
|
||||
* 更多链接 JSON
|
||||
*/
|
||||
WEB_BLOG_LINKS(false, 0, ""),
|
||||
/**
|
||||
* 博客端专题特殊形式, 0:false;1:是
|
||||
* @since 1.13.0
|
||||
*/
|
||||
WEB_BLOG_SUBJECT_TITLE(false, 0, "0"),
|
||||
;
|
||||
|
||||
/**
|
||||
|
@ -44,4 +44,10 @@ public interface UserParamMapper extends BaseMapper<UserParamEntity> {
|
||||
* 新增参数
|
||||
*/
|
||||
int insertByUserId(UserParamEntity param);
|
||||
|
||||
/**
|
||||
* 删除参数
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.blossom.backend.base.sys;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.param.ParamEnum;
|
||||
import com.blossom.backend.base.param.ParamService;
|
||||
import com.blossom.backend.base.param.pojo.ParamUpdReq;
|
||||
@ -63,6 +64,7 @@ public class SysController {
|
||||
/**
|
||||
* 修改系统参数
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/param/upd")
|
||||
public R<Map<String, String>> upd(@Validated @RequestBody ParamUpdReq req) {
|
||||
if (!UserTypeEnum.ADMIN.getType().equals(AuthContext.getType())) {
|
||||
@ -76,6 +78,7 @@ public class SysController {
|
||||
/**
|
||||
* 刷新系统配置
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/param/refresh")
|
||||
public R<?> paramRefresh() {
|
||||
paramService.refresh();
|
||||
|
@ -2,7 +2,9 @@ package com.blossom.backend.base.user;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.AuthService;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.param.ParamEnum;
|
||||
import com.blossom.backend.base.param.ParamService;
|
||||
import com.blossom.backend.base.paramu.UserParamEnum;
|
||||
@ -12,14 +14,15 @@ import com.blossom.backend.base.user.pojo.*;
|
||||
import com.blossom.backend.config.BlConstants;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleStatRes;
|
||||
import com.blossom.backend.server.article.stat.ArticleStatService;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.exception.XzException404;
|
||||
import com.blossom.common.base.exception.XzException500;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
import com.blossom.common.base.util.spring.SpringUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -31,25 +34,86 @@ import java.util.Map;
|
||||
@RequestMapping("/user")
|
||||
@AllArgsConstructor
|
||||
public class UserController {
|
||||
|
||||
private final UserService userService;
|
||||
private final AuthService authService;
|
||||
private final ArticleStatService articleService;
|
||||
private final SysService sysService;
|
||||
private final ParamService paramService;
|
||||
private final UserParamService userParamService;
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
*
|
||||
* @apiNote 需要管理员权限
|
||||
* @since 1.13.0
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@GetMapping("/list")
|
||||
public R<List<UserListRes>> list() {
|
||||
return R.ok(userService.listAll(), UserListRes.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @apiNote 根据用户ID获取用户信息, 需要管理员权限
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@GetMapping("/info/admin")
|
||||
public R<BlossomUserRes> user(@RequestParam("id") Long id) {
|
||||
return getUserById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
*
|
||||
* @apiNote 需要管理员权限
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/add")
|
||||
public R<?> add(@Validated @RequestBody UserAddReq req) {
|
||||
userService.insert(req);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*
|
||||
* @apiNote 需要管理员权限
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/upd/admin")
|
||||
public R<?> updateImportant(@Validated @RequestBody UserUpdAdminReq req) {
|
||||
UserEntity user = req.to(UserEntity.class);
|
||||
userService.updById(user);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用启用
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/disabled")
|
||||
public R<?> disabled(@Validated @RequestBody UserDisabledReq req) {
|
||||
if (req.getId().equals(AuthContext.getUserId())) {
|
||||
throw new XzException500("不能禁用自己");
|
||||
}
|
||||
UserEntity user = req.to(UserEntity.class);
|
||||
userService.updById(user);
|
||||
authService.kickout(req.getId());
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*
|
||||
* @apiNote 当前登录用户的用户信息
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public R<BlossomUserRes> user() {
|
||||
BlossomUserRes user = userService.selectById(AuthContext.getUserId()).to(BlossomUserRes.class);
|
||||
user.setOsRes(sysService.getOsConfig());
|
||||
Map<String, String> paramMap = paramService.selectMap(true, ParamEnum.values());
|
||||
user.setParams(paramMap);
|
||||
paramMap.put("SERVER_VERSION", SpringUtil.get("project.base.version"));
|
||||
Map<String, String> userParamMap = userParamService.selectMap(AuthContext.getUserId(), true, UserParamEnum.values());
|
||||
user.setUserParams(userParamMap);
|
||||
return R.ok(user);
|
||||
return getUserById(AuthContext.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,15 +160,33 @@ public class UserController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
* 删除用户
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public R<?> add(@Validated @RequestBody UserAddReq req) {
|
||||
UserEntity curUser = userService.getById(AuthContext.getUserId());
|
||||
if (curUser == null || !UserTypeEnum.ADMIN.getType().equals(curUser.getType())) {
|
||||
throw new XzException400("您没有权限添加用户");
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@PostMapping("/del")
|
||||
public R<?> delete(@Validated @RequestBody UserDeleteReq req) {
|
||||
if (req.getId().equals(AuthContext.getUserId())) {
|
||||
throw new XzException500("不能删除自己");
|
||||
}
|
||||
userService.insert(req);
|
||||
userService.delete(req.getId());
|
||||
authService.kickout(req.getId());
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
private R<BlossomUserRes> getUserById(Long userId) {
|
||||
BlossomUserRes user = userService.selectById(userId).to(BlossomUserRes.class);
|
||||
user.setOsRes(sysService.getOsConfig());
|
||||
Map<String, String> paramMap = paramService.selectMap(true, ParamEnum.values());
|
||||
user.setParams(paramMap);
|
||||
paramMap.put("SERVER_VERSION", SpringUtil.get("project.base.version"));
|
||||
Map<String, String> userParamMap = userParamService.selectMap(userId, true, UserParamEnum.values());
|
||||
user.setUserParams(userParamMap);
|
||||
return R.ok(user);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,13 @@ public interface UserMapper extends BaseMapper<UserEntity> {
|
||||
*/
|
||||
void updById(UserEntity user);
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void delById(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*
|
||||
|
@ -1,15 +1,31 @@
|
||||
package com.blossom.backend.base.user;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.blossom.backend.base.auth.security.PasswordEncoder;
|
||||
import com.blossom.backend.base.paramu.UserParamMapper;
|
||||
import com.blossom.backend.base.paramu.UserParamService;
|
||||
import com.blossom.backend.base.user.pojo.UserAddReq;
|
||||
import com.blossom.backend.base.user.pojo.UserEntity;
|
||||
import com.blossom.backend.base.user.pojo.UserUpdPwdReq;
|
||||
import com.blossom.backend.server.article.draft.ArticleMapper;
|
||||
import com.blossom.backend.server.article.log.ArticleLogMapper;
|
||||
import com.blossom.backend.server.article.open.ArticleOpenMapper;
|
||||
import com.blossom.backend.server.article.recycle.ArticleRecycleMapper;
|
||||
import com.blossom.backend.server.article.reference.ArticleReferenceMapper;
|
||||
import com.blossom.backend.server.article.stat.ArticleStatMapper;
|
||||
import com.blossom.backend.server.article.view.ArticleViewMapper;
|
||||
import com.blossom.backend.server.folder.FolderMapper;
|
||||
import com.blossom.backend.server.note.NoteMapper;
|
||||
import com.blossom.backend.server.picture.PictureMapper;
|
||||
import com.blossom.backend.server.plan.PlanMapper;
|
||||
import com.blossom.backend.server.todo.TodoMapper;
|
||||
import com.blossom.backend.server.web.WebMapper;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.util.security.SaltUtil;
|
||||
import com.blossom.common.iaas.OSManager;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -29,6 +45,21 @@ public class UserService extends ServiceImpl<UserMapper, UserEntity> {
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final UserParamService userParamService;
|
||||
private final UserParamMapper userParamMapper;
|
||||
private final ArticleMapper articleMapper;
|
||||
private final ArticleLogMapper articleLogMapper;
|
||||
private final ArticleViewMapper articleViewMapper;
|
||||
private final ArticleOpenMapper articleOpenMapper;
|
||||
private final ArticleReferenceMapper articleReferenceMapper;
|
||||
private final ArticleRecycleMapper articleRecycleMapper;
|
||||
private final FolderMapper folderMapper;
|
||||
private final NoteMapper noteMapper;
|
||||
private final PlanMapper planMapper;
|
||||
private final PictureMapper pictureMapper;
|
||||
private final TodoMapper todoMapper;
|
||||
private final WebMapper webMapper;
|
||||
private final ArticleStatMapper statMapper;
|
||||
private final OSManager osManager;
|
||||
|
||||
/**
|
||||
* 查询全部用户
|
||||
@ -79,6 +110,52 @@ public class UserService extends ServiceImpl<UserMapper, UserEntity> {
|
||||
baseMapper.updById(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户信息
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(final Long userId) {
|
||||
List<Long> articleIds = articleMapper.listIdByUserId(userId);
|
||||
System.out.println(articleIds);
|
||||
// base_user
|
||||
baseMapper.delById(userId);
|
||||
// base_user_param
|
||||
userParamMapper.delByUserId(userId);
|
||||
// blossom_article
|
||||
articleMapper.delByUserId(userId);
|
||||
// blossom_article_open
|
||||
articleOpenMapper.delByUserId(userId);
|
||||
// blossom_article_recycle
|
||||
articleRecycleMapper.delByUserId(userId);
|
||||
// blossom_article_reference
|
||||
articleReferenceMapper.delByUserId(userId);
|
||||
if (CollUtil.isNotEmpty(articleIds)) {
|
||||
// blossom_article_log
|
||||
articleLogMapper.delByIds(articleIds);
|
||||
// blossom_article_view
|
||||
articleViewMapper.delByIds(articleIds);
|
||||
}
|
||||
// blossom_folder
|
||||
folderMapper.delByUserId(userId);
|
||||
// blossom_note
|
||||
noteMapper.delByUserId(userId);
|
||||
// blossom_picture
|
||||
pictureMapper.delByUserId(userId);
|
||||
// blossom_plan
|
||||
planMapper.delByUserId(userId);
|
||||
// blossom_stat
|
||||
statMapper.delByUserId(userId);
|
||||
// blossom_todo
|
||||
todoMapper.delByUserId(userId);
|
||||
// blossom_web
|
||||
webMapper.delByUserId(userId);
|
||||
|
||||
// 删除物理文件
|
||||
final String rootPath = osManager.getDefaultPath();
|
||||
final String uid = "/U" + userId;
|
||||
osManager.deletePath(rootPath + uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
|
@ -7,6 +7,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -56,6 +57,14 @@ public class BlossomUserRes extends AbstractPOJO implements Serializable {
|
||||
* 文章字数
|
||||
*/
|
||||
private Integer articleWords;
|
||||
/**
|
||||
* 创建日期
|
||||
*/
|
||||
private Date creTime;
|
||||
/**
|
||||
* 逻辑删除, 目前用于禁用用户, 而不是删除
|
||||
*/
|
||||
private Long delTime;
|
||||
|
||||
/**
|
||||
* 对象存储信息, 非登录状态不返回该字段
|
||||
|
@ -0,0 +1,17 @@
|
||||
package com.blossom.backend.base.user.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
@Data
|
||||
public class UserDeleteReq {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID为必填项")
|
||||
private Long id;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.blossom.backend.base.user.pojo;
|
||||
|
||||
import com.blossom.common.base.pojo.AbstractPOJO;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
public class UserDisabledReq extends AbstractPOJO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID为必填项")
|
||||
private Long id;
|
||||
/**
|
||||
* 禁用状态
|
||||
*/
|
||||
private Long delTime;
|
||||
}
|
@ -8,6 +8,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户
|
||||
@ -66,5 +67,13 @@ public class UserEntity extends AbstractPOJO implements Serializable {
|
||||
* 用户的位置
|
||||
*/
|
||||
private String location;
|
||||
/**
|
||||
* 创建日期
|
||||
*/
|
||||
private Date creTime;
|
||||
/**
|
||||
* 逻辑删除, 目前用于禁用用户, 而不是删除
|
||||
*/
|
||||
private Long delTime;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.blossom.backend.base.user.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class UserListRes {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String avatar;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 创建日期
|
||||
*/
|
||||
private Date creTime;
|
||||
/**
|
||||
* 逻辑删除, 目前用于禁用用户, 而不是删除
|
||||
*/
|
||||
private Long delTime;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.blossom.backend.base.user.pojo;
|
||||
|
||||
import com.blossom.common.base.pojo.AbstractEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 用户请求
|
||||
*
|
||||
* @author xzzz
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class UserUpdAdminReq extends AbstractEntity {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 和风天气的位置
|
||||
*/
|
||||
private String location;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Integer type;
|
||||
}
|
@ -37,6 +37,5 @@ public class UserUpdReq extends AbstractEntity {
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
@NotBlank(message = "用户头像为必填项")
|
||||
private String avatar;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import javax.sql.DataSource;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* 启动检查配置文件内容, 用于检查配置项是否正确
|
||||
@ -34,6 +35,7 @@ public class PropertiesCheckListener implements ApplicationListener<ApplicationE
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
|
||||
ConfigurableEnvironment env = event.getEnvironment();
|
||||
setTimeZone(env);
|
||||
log.warn("\n\n正在检查 Blossom 后台配置项\n\n" +
|
||||
"\n[CHECK] ==========================================================================================================================" +
|
||||
"\n[CHECK] 使用环境: [{}], 版本: [{}]" +
|
||||
@ -46,6 +48,7 @@ public class PropertiesCheckListener implements ApplicationListener<ApplicationE
|
||||
"\n[CHECK] 文件大小: {}" +
|
||||
"\n[CHECK] 授权时长: {}" +
|
||||
"\n[CHECK] 重置密码: {}" +
|
||||
"\n[CHECK] 指定时区: {}" +
|
||||
"\n[CHECK] ==========================================================================================================================\n\n",
|
||||
get(env, SpringUtil.PROFILE_ACTION), get(env, "project.base.version"),
|
||||
get(env, "spring.datasource.url"),
|
||||
@ -55,7 +58,8 @@ public class PropertiesCheckListener implements ApplicationListener<ApplicationE
|
||||
get(env, "project.iaas.blos.default-path"),
|
||||
get(env, "spring.servlet.multipart.max-file-size"),
|
||||
get(env, "project.auth.clients[0].duration"),
|
||||
get(env, "project.auth.password-reset")
|
||||
get(env, "project.auth.password-reset"),
|
||||
get(env, "project.base.time-zone")
|
||||
);
|
||||
|
||||
String defaultPath = get(env, "project.iaas.blos.default-path");
|
||||
@ -167,4 +171,15 @@ public class PropertiesCheckListener implements ApplicationListener<ApplicationE
|
||||
public boolean isNotReceived(String message) {
|
||||
return message.contains("The driver has not received any packets from the server");
|
||||
}
|
||||
|
||||
private void setTimeZone(ConfigurableEnvironment env) {
|
||||
String timeZone = get(env, "project.base.time-zone");
|
||||
if (StrUtil.isBlank(timeZone) || TimeZone.getTimeZone(timeZone) == null) {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
} else {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(timeZone));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -289,13 +289,19 @@ public class ArticleController {
|
||||
/**
|
||||
* 创建文章的临时访问缓存
|
||||
*
|
||||
* @param id 文章ID
|
||||
* @param id 文章ID
|
||||
* @param duration 临时访问的过期时间
|
||||
* @return 临时访问Key
|
||||
* @since 1.9.0
|
||||
*/
|
||||
@GetMapping("/temp/key")
|
||||
public R<String> createTempVisitKey(@RequestParam("id") Long id) {
|
||||
return R.ok(tempVisitService.create(id, AuthContext.getUserId()));
|
||||
public R<String> createTempVisitKey(@RequestParam("id") Long id,
|
||||
@RequestParam(value = "duration", required = false) Long duration) {
|
||||
if (duration == null) {
|
||||
duration = 3 * 60L;
|
||||
}
|
||||
log.info("创建文章临时访问权限 [{}:{}m]", id, duration);
|
||||
return R.ok(tempVisitService.create(id, AuthContext.getUserId(), duration));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,12 @@ public interface ArticleMapper extends BaseMapper<ArticleEntity> {
|
||||
*/
|
||||
List<ArticleEntity> listAll(ArticleEntity entity);
|
||||
|
||||
/**
|
||||
* 获取指定用户的全部文章ID
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
List<Long> listIdByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 查询全部需要索引的字段
|
||||
*/
|
||||
@ -70,4 +76,8 @@ public interface ArticleMapper extends BaseMapper<ArticleEntity> {
|
||||
*/
|
||||
void uvAndPv(@Param("articleId") Long article, @Param("pv") Integer pv, @Param("uv") Integer uv);
|
||||
|
||||
/**
|
||||
* 删除文章
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.blossom.backend.server.article.draft;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.util.security.SHA256Util;
|
||||
import com.blossom.common.cache.caffeine.DynamicExpiry;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
@ -10,6 +11,7 @@ import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -24,25 +26,31 @@ public class ArticleTempVisitService {
|
||||
|
||||
/**
|
||||
* 存放文章ID的缓存
|
||||
*
|
||||
* @since 1.13.0 支持动态过期时间
|
||||
*/
|
||||
private final Cache<String, TempVisit> tempVisitCache = Caffeine.newBuilder()
|
||||
.expireAfter(new DynamicExpiry())
|
||||
.initialCapacity(500)
|
||||
.expireAfterWrite(3, TimeUnit.HOURS)
|
||||
.removalListener((String key, TempVisit value, RemovalCause cause) ->
|
||||
log.info("临时访问文章 [" + value.getArticleId() + "] 被删除")
|
||||
log.info("remove temp visit articleId [" + Objects.requireNonNull(value).getArticleId() + "]")
|
||||
)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* 生成一个缓存 key, key 并非文章的摘要码
|
||||
* 生成一个缓存 key, key 并非文章的摘要码,
|
||||
*
|
||||
* @param articleId 文章ID
|
||||
* @param userId 用户ID
|
||||
* @param duration 过期时间, 单位分钟
|
||||
* @return 缓存 key
|
||||
*/
|
||||
public String create(Long articleId, Long userId) {
|
||||
public String create(Long articleId, Long userId, Long duration) {
|
||||
XzException400.throwBy(ObjUtil.isNull(articleId), "文章ID为必填项");
|
||||
String key = SHA256Util.encode(UUID.randomUUID().toString());
|
||||
tempVisitCache.put(key, new TempVisit(articleId, userId));
|
||||
tempVisitCache.policy().expireVariably().ifPresent(e -> {
|
||||
e.put(key, new TempVisit(articleId, userId), duration, TimeUnit.MINUTES);
|
||||
});
|
||||
return key;
|
||||
}
|
||||
|
||||
|
@ -20,4 +20,11 @@ public interface ArticleLogMapper extends BaseMapper<ArticleLogEntity> {
|
||||
* @param articleId 文章ID
|
||||
*/
|
||||
List<ArticleLogEntity> listAll(@Param("articleId") Long articleId);
|
||||
|
||||
/**
|
||||
* 删除文章的记录
|
||||
*
|
||||
* @param articleIds 文章ID集合
|
||||
*/
|
||||
Long delByIds(@Param("articleIds") List<Long> articleIds);
|
||||
}
|
@ -3,6 +3,7 @@ package com.blossom.backend.server.article.open;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.blossom.backend.server.article.open.pojo.ArticleOpenEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 公开文章
|
||||
@ -32,4 +33,9 @@ public interface ArticleOpenMapper extends BaseMapper<ArticleOpenEntity> {
|
||||
* @param id 公开文章的ID
|
||||
*/
|
||||
void sync(Long id);
|
||||
|
||||
/**
|
||||
* 删除公开文章
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -37,4 +37,9 @@ public interface ArticleRecycleMapper extends BaseMapper<ArticleRecycleEntity> {
|
||||
* @param pid 文章的父ID
|
||||
*/
|
||||
void restore(@Param("id") Long id, @Param("pid") Long pid);
|
||||
|
||||
/**
|
||||
* 删除文章回收站
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -61,4 +61,8 @@ public interface ArticleReferenceMapper extends BaseMapper<ArticleReferenceEntit
|
||||
*/
|
||||
void updateToKnown(@Param("userId") Long userId, @Param("targetId") Long targetId, @Param("targetName") String targetName);
|
||||
|
||||
/**
|
||||
* 删除文章引用
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.blossom.backend.server.article.reference.pojo.ArticleReferenceEntity;
|
||||
import com.blossom.backend.server.article.reference.pojo.ArticleReferenceReq;
|
||||
import com.blossom.common.base.util.BeanUtil;
|
||||
import com.blossom.common.base.util.security.Base64Util;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@ -48,6 +49,9 @@ public class ArticleReferenceService extends ServiceImpl<ArticleReferenceMapper,
|
||||
ref.setUserId(userId);
|
||||
ref.setSourceId(sourceId);
|
||||
ref.setSourceName(sourceName);
|
||||
if (Base64Util.isBase64Img(ref.getTargetUrl())) {
|
||||
ref.setTargetUrl("");
|
||||
}
|
||||
}
|
||||
baseMapper.insertList(refs);
|
||||
}
|
||||
|
@ -2,12 +2,16 @@ package com.blossom.backend.server.article.stat;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.auth.exception.AuthException;
|
||||
import com.blossom.backend.base.auth.exception.AuthRCode;
|
||||
import com.blossom.backend.base.user.UserTypeEnum;
|
||||
import com.blossom.backend.config.BlConstants;
|
||||
import com.blossom.backend.server.article.draft.pojo.ArticleStatRes;
|
||||
import com.blossom.backend.server.article.stat.pojo.ArticleHeatmapRes;
|
||||
import com.blossom.backend.server.article.stat.pojo.ArticleLineRes;
|
||||
import com.blossom.backend.server.article.stat.pojo.ArticleWordsSaveReq;
|
||||
import com.blossom.backend.server.article.stat.pojo.ArticleWordsRes;
|
||||
import com.blossom.backend.server.article.stat.pojo.ArticleWordsSaveReq;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -77,6 +81,21 @@ public class ArticleStatController {
|
||||
return R.ok(statService.statCount(null, null, AuthContext.getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章数和文章字数
|
||||
*
|
||||
* @apiNote 只有管理员可以查看
|
||||
* @since 1.13.0
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@GetMapping("/words/user")
|
||||
public R<ArticleStatRes> word(@RequestParam("id") Long id) {
|
||||
if (!AuthContext.getType().equals(UserTypeEnum.ADMIN.getType())) {
|
||||
throw new AuthException(AuthRCode.PERMISSION_DENIED);
|
||||
}
|
||||
return R.ok(statService.statCount(null, null, id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字数统计列表
|
||||
*
|
||||
|
@ -3,6 +3,7 @@ package com.blossom.backend.server.article.stat;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.blossom.backend.server.article.stat.pojo.ArticleStatEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 文章统计
|
||||
@ -11,4 +12,9 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
*/
|
||||
@Mapper
|
||||
public interface ArticleStatMapper extends BaseMapper<ArticleStatEntity> {
|
||||
|
||||
/**
|
||||
* 删除统计信息
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import com.blossom.backend.server.article.view.pojo.ArticleViewEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 文章访问记录 [@A#View]
|
||||
@ -22,4 +24,11 @@ public interface ArticleViewMapper extends BaseMapper<ArticleViewEntity> {
|
||||
* @param articleId 文章ID
|
||||
*/
|
||||
Long checkUv(@Param("today") String today, @Param("ip") String ip, @Param("articleId") Long articleId);
|
||||
|
||||
/**
|
||||
* 删除文章的访问记录
|
||||
*
|
||||
* @param articleIds 文章ID集合
|
||||
*/
|
||||
void delByIds(@Param("articleIds") List<Long> articleIds);
|
||||
}
|
@ -39,4 +39,9 @@ public interface FolderMapper extends BaseMapper<FolderEntity> {
|
||||
* 根据ID集合修改
|
||||
*/
|
||||
void updByIds(FolderEntity entity);
|
||||
|
||||
/**
|
||||
* 删除文件夹
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
@ -28,4 +28,9 @@ public interface NoteMapper extends BaseMapper<NoteEntity> {
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
void updById(@Param("id") Long id, @Param("userId") Long userId, @Param("content") String content);
|
||||
|
||||
/**
|
||||
* 删除便签
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package com.blossom.backend.server.picture;
|
||||
|
||||
import com.blossom.backend.base.auth.AuthContext;
|
||||
import com.blossom.backend.base.auth.annotation.AuthIgnore;
|
||||
import com.blossom.backend.base.auth.annotation.AuthUserType;
|
||||
import com.blossom.backend.base.user.UserTypeEnum;
|
||||
import com.blossom.backend.server.picture.pojo.*;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.pojo.PageRes;
|
||||
@ -116,4 +118,15 @@ public class PictureController {
|
||||
public R<PictureStatRes> stat(@RequestParam(value = "pid", required = false) Long pid) {
|
||||
return R.ok(baseService.stat(AuthContext.getUserId(), pid));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户的图片统计
|
||||
*
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
@AuthUserType(UserTypeEnum.ADMIN)
|
||||
@GetMapping("/stat/user")
|
||||
public R<PictureStatRes> statUser(@RequestParam(value = "id") Long userId) {
|
||||
return R.ok(baseService.stat(userId, null));
|
||||
}
|
||||
}
|
||||
|
@ -56,4 +56,9 @@ public interface PictureMapper extends BaseMapper<PictureEntity> {
|
||||
* @param pid 文件夹ID
|
||||
*/
|
||||
PictureStatRes stat(@Param("userId") Long userId, @Param("pid") Long pid);
|
||||
|
||||
/**
|
||||
* 删除图片
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
@ -8,7 +8,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -32,7 +31,7 @@ public class PlanController {
|
||||
* @param month 查询的月份, 会查询该月的所有每日计划
|
||||
*/
|
||||
@GetMapping("/list/day")
|
||||
public R<Map<Date, List<PlanDayRes>>> days(String month) {
|
||||
public R<Map<String, List<PlanDayRes>>> days(String month) {
|
||||
return R.ok(baseService.listDay(month, AuthContext.getUserId()));
|
||||
}
|
||||
|
||||
|
@ -40,4 +40,9 @@ public interface PlanMapper extends BaseMapper<PlanEntity> {
|
||||
* @param groupId 计划分组ID
|
||||
*/
|
||||
void delById(@Param("id") Long id, @Param("groupId") Long groupId);
|
||||
|
||||
/**
|
||||
* 删除计划
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
|
@ -28,12 +28,19 @@ public class PlanService extends ServiceImpl<PlanMapper, PlanEntity> {
|
||||
/**
|
||||
* 按月查询每日计划
|
||||
*/
|
||||
public Map<Date, List<PlanDayRes>> listDay(String month, Long userId) {
|
||||
public Map<String, List<PlanDayRes>> listDay(String month, Long userId) {
|
||||
PlanEntity where = new PlanEntity();
|
||||
where.setPlanMonth(month);
|
||||
where.setUserId(userId);
|
||||
where.setType(PlanTypeEnum.DAY.getType());
|
||||
return PlanUtil.sortToTreeMap(BeanUtil.toList(baseMapper.listAll(where), PlanDayRes.class), false);
|
||||
List<PlanDayRes> list = new ArrayList<>();
|
||||
for (PlanEntity plan : baseMapper.listAll(where)) {
|
||||
PlanDayRes res = BeanUtil.toObj(plan, PlanDayRes.class);
|
||||
res.setPlanDate(DateUtils.toYMD(plan.getPlanDate()) + " 00:00:00");
|
||||
list.add(res);
|
||||
}
|
||||
|
||||
return PlanUtil.sortToTreeMap(list, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,6 @@ package com.blossom.backend.server.plan.pojo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 每日计划
|
||||
@ -34,7 +33,7 @@ public class PlanDayRes implements Serializable {
|
||||
/**
|
||||
* 日期
|
||||
*/
|
||||
private Date planDate;
|
||||
private String planDate;
|
||||
/**
|
||||
* 计划开始时间
|
||||
*/
|
||||
|
@ -90,4 +90,9 @@ public interface TodoMapper extends BaseMapper<TodoEntity> {
|
||||
* 根据ID集合删除
|
||||
*/
|
||||
void delByIds(@Param("ids") List<Long> ids, @Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 删除待办
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
@ -4,10 +4,12 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.blossom.backend.server.plan.pojo.PlanDayRes;
|
||||
import com.blossom.common.base.util.DateUtils;
|
||||
import com.blossom.common.base.util.SortUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -22,8 +24,8 @@ public class PlanUtil {
|
||||
*
|
||||
* @param plans 计划列表
|
||||
*/
|
||||
private static TreeMap<Date, List<PlanDayRes>> byDay(List<PlanDayRes> plans) {
|
||||
TreeMap<Date, List<PlanDayRes>> map = new TreeMap<>();
|
||||
private static TreeMap<String, List<PlanDayRes>> byDay(List<PlanDayRes> plans) {
|
||||
TreeMap<String, List<PlanDayRes>> map = new TreeMap<>();
|
||||
for (PlanDayRes plan : plans) {
|
||||
List<PlanDayRes> list = map.getOrDefault(plan.getPlanDate(), new ArrayList<>());
|
||||
list.add(plan);
|
||||
@ -57,7 +59,7 @@ public class PlanUtil {
|
||||
if (CollUtil.isEmpty(plans)) {
|
||||
return plans;
|
||||
}
|
||||
Map<Date, List<PlanDayRes>> byDay = byDay(plans);
|
||||
Map<String, List<PlanDayRes>> byDay = byDay(plans);
|
||||
Map<Long, List<PlanDayRes>> byGroupId = byGroupId(plans);
|
||||
|
||||
// 先为所有计划设置默认排序
|
||||
@ -105,13 +107,13 @@ public class PlanUtil {
|
||||
* @param plans 计划列表, 传入的计划列表需要提前按 {@link PlanDayRes#getPlanDate()} 升序
|
||||
* @return treeMap key 为日期(天), value 为该日期计划数组
|
||||
*/
|
||||
public static TreeMap<Date, List<PlanDayRes>> sortToTreeMap(List<PlanDayRes> plans, boolean debug) {
|
||||
public static TreeMap<String, List<PlanDayRes>> sortToTreeMap(List<PlanDayRes> plans, boolean debug) {
|
||||
if (CollUtil.isEmpty(plans)) {
|
||||
return new TreeMap<>();
|
||||
}
|
||||
Map<Date, List<PlanDayRes>> map = sort(plans).stream()
|
||||
Map<String, List<PlanDayRes>> map = sort(plans).stream()
|
||||
.collect(Collectors.groupingBy(PlanDayRes::getPlanDate));
|
||||
TreeMap<Date, List<PlanDayRes>> treeMap = MapUtil.sort(map);
|
||||
TreeMap<String, List<PlanDayRes>> treeMap = MapUtil.sort(map);
|
||||
treeMap.forEach((k, v) -> {
|
||||
v = v.stream().sorted((p1, p2) -> SortUtil.intSort.compare(p1.getSort(), p2.getSort())).collect(Collectors.toList());
|
||||
treeMap.put(k, v);
|
||||
@ -127,9 +129,9 @@ public class PlanUtil {
|
||||
/**
|
||||
* 控制台打印计划的排序
|
||||
*/
|
||||
private static void debugTreeMap(TreeMap<Date, List<PlanDayRes>> treeMap) {
|
||||
for (Date date : treeMap.keySet()) {
|
||||
System.out.print(DateUtils.format(date, DateUtils.PATTERN_YYYYMMDD) + "|");
|
||||
private static void debugTreeMap(TreeMap<String, List<PlanDayRes>> treeMap) {
|
||||
for (String date : treeMap.keySet()) {
|
||||
System.out.print(date + "|");
|
||||
}
|
||||
System.out.println();
|
||||
for (int i = 0; i < treeMap.values().size(); i++) {
|
||||
@ -151,7 +153,7 @@ public class PlanUtil {
|
||||
* @param date 日期
|
||||
* @param sort 顺序
|
||||
*/
|
||||
private static PlanDayRes getHolderPlan(Date date, int sort) {
|
||||
private static PlanDayRes getHolderPlan(String date, int sort) {
|
||||
PlanDayRes holder = new PlanDayRes();
|
||||
holder.setId(sort * -1L - 1);
|
||||
holder.setGroupId(0L);
|
||||
@ -166,31 +168,31 @@ public class PlanUtil {
|
||||
PlanDayRes p1_1 = new PlanDayRes();
|
||||
p1_1.setId(1L);
|
||||
p1_1.setGroupId(1L);
|
||||
p1_1.setPlanDate(DateUtils.parse("2023-09-01", DateUtils.PATTERN_YYYYMMDD));
|
||||
p1_1.setPlanDate("2023-09-01");
|
||||
plans.add(p1_1);
|
||||
|
||||
PlanDayRes p1_2 = new PlanDayRes();
|
||||
p1_2.setId(2L);
|
||||
p1_2.setGroupId(1L);
|
||||
p1_2.setPlanDate(DateUtils.parse("2023-09-02", DateUtils.PATTERN_YYYYMMDD));
|
||||
p1_2.setPlanDate("2023-09-02");
|
||||
plans.add(p1_2);
|
||||
|
||||
PlanDayRes p2 = new PlanDayRes();
|
||||
p2.setId(3L);
|
||||
p2.setGroupId(2L);
|
||||
p2.setPlanDate(DateUtils.parse("2023-09-01", DateUtils.PATTERN_YYYYMMDD));
|
||||
p2.setPlanDate("2023-09-01");
|
||||
plans.add(p2);
|
||||
|
||||
PlanDayRes p3_1 = new PlanDayRes();
|
||||
p3_1.setId(4L);
|
||||
p3_1.setGroupId(3L);
|
||||
p3_1.setPlanDate(DateUtils.parse("2023-09-02", DateUtils.PATTERN_YYYYMMDD));
|
||||
p3_1.setPlanDate("2023-09-02");
|
||||
plans.add(p3_1);
|
||||
|
||||
PlanDayRes p3_2 = new PlanDayRes();
|
||||
p3_2.setId(4L);
|
||||
p3_2.setGroupId(3L);
|
||||
p3_2.setPlanDate(DateUtils.parse("2023-09-03", DateUtils.PATTERN_YYYYMMDD));
|
||||
p3_2.setPlanDate("2023-09-03");
|
||||
plans.add(p3_2);
|
||||
|
||||
sortToTreeMap(plans, true);
|
||||
|
@ -3,6 +3,7 @@ package com.blossom.backend.server.web;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.blossom.backend.server.web.pojo.WebEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 网站收藏
|
||||
@ -12,4 +13,8 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
@Mapper
|
||||
public interface WebMapper extends BaseMapper<WebEntity> {
|
||||
|
||||
/**
|
||||
* 删除文章
|
||||
*/
|
||||
void delByUserId(@Param("userId") Long userId);
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
package com.blossom.backend.thirdparty;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.blossom.backend.base.user.UserService;
|
||||
import com.blossom.backend.base.user.pojo.UserEntity;
|
||||
import com.blossom.backend.thirdparty.hefeng.WeatherManager;
|
||||
import com.blossom.common.base.pojo.R;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.blossom.expand.tracker.core.adapter.aspect.TrackerStart;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -22,11 +21,9 @@ import java.util.stream.Collectors;
|
||||
*
|
||||
* @author : xzzz
|
||||
*/
|
||||
@Component
|
||||
@RestController
|
||||
@RequestMapping("/thirdparty/scheduled")
|
||||
public class ThirdPartyScheduled {
|
||||
private static final Logger log = LoggerFactory.getLogger(ThirdPartyScheduled.class);
|
||||
|
||||
@Autowired
|
||||
private WeatherManager weatherManager;
|
||||
@ -39,14 +36,17 @@ public class ThirdPartyScheduled {
|
||||
*
|
||||
* @apiNote 每30分钟刷新, 请求会立即刷新
|
||||
*/
|
||||
@TrackerStart
|
||||
@PostMapping("/weather")
|
||||
@Scheduled(cron = "0 0/30 * * * ?")
|
||||
public R<?> refreshWeather() {
|
||||
log.debug("[BLOSSOM] 刷新天气");
|
||||
List<UserEntity> users = userService.listAll();
|
||||
Set<String> locations = users.stream().collect(Collectors.groupingBy(UserEntity::getLocation)).keySet();
|
||||
for (String location : locations) {
|
||||
weatherManager.clearAll(location);
|
||||
if (StrUtil.isBlank(location)) {
|
||||
continue;
|
||||
}
|
||||
weatherManager.clear(location);
|
||||
weatherManager.findWeatherAll(location);
|
||||
}
|
||||
return R.ok();
|
||||
|
@ -23,9 +23,11 @@ public class WeatherController {
|
||||
|
||||
/**
|
||||
* 获取天气信息
|
||||
*
|
||||
* @param location 用户位置
|
||||
*/
|
||||
@GetMapping
|
||||
public R<WeatherRes> weather(@RequestParam(value = "location",required = false)String location) {
|
||||
public R<WeatherRes> weather(@RequestParam(value = "location", required = false) String location) {
|
||||
if (StrUtil.isBlank(location)) {
|
||||
return R.ok(new WeatherRes());
|
||||
}
|
||||
|
@ -9,17 +9,19 @@ import com.blossom.backend.thirdparty.hefeng.pojo.*;
|
||||
import com.blossom.common.base.exception.XzException400;
|
||||
import com.blossom.common.base.util.json.JsonUtil;
|
||||
import com.blossom.common.base.util.okhttp.HttpUtil;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.RemovalCause;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 天气查询
|
||||
@ -38,19 +40,32 @@ public class WeatherManager {
|
||||
private static final String URL_NOW = "https://devapi.heweather.net/v7/weather/now";
|
||||
private static final String URL_DAILY = "https://devapi.heweather.net/v7/weather/3d";
|
||||
private static final String URL_HOURLY = "https://devapi.heweather.net/v7/weather/24h";
|
||||
|
||||
private static final String WEATHER_ALL = "weather_all";
|
||||
|
||||
private static final String SUCCESS = "200";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final Cache<String, WeatherRes> weatherCache = Caffeine.newBuilder()
|
||||
.initialCapacity(50)
|
||||
.expireAfterWrite(45, TimeUnit.MINUTES)
|
||||
.removalListener((String location, WeatherRes weather, RemovalCause cause) ->
|
||||
log.info("Weather cache [" + location + "] has been deleted")
|
||||
)
|
||||
.build();
|
||||
|
||||
@Autowired
|
||||
private ParamService paramService;
|
||||
|
||||
/**
|
||||
* 查询天气信息
|
||||
*/
|
||||
@Cacheable(cacheNames = WEATHER_ALL, key = "'location_' + #location", unless = "#result == null")
|
||||
public WeatherRes findWeatherAll(String location) {
|
||||
WeatherRes cache = weatherCache.getIfPresent(location);
|
||||
if (cache != null) {
|
||||
log.debug("[BLOSSOM] get weather from cache: {}", location);
|
||||
return cache;
|
||||
}
|
||||
log.info("[BLOSSOM] refresh weather: {}", location);
|
||||
Map<String, String> maps = initParam(location);
|
||||
if (maps == null) {
|
||||
log.info("未配置天气信息, 忽略天气查询");
|
||||
@ -128,15 +143,15 @@ public class WeatherManager {
|
||||
} else {
|
||||
log.error("获取小时预报失败, resp: {}", cityStr);
|
||||
}
|
||||
weatherCache.put(location, weather);
|
||||
return weather;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
@CacheEvict(cacheNames = WEATHER_ALL, key = "'location_' + #location")
|
||||
public void clearAll(String location) {
|
||||
|
||||
public void clear(String location) {
|
||||
weatherCache.invalidate(location);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://192.168.31.99:3306/xzzz-blossom?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&allowMultiQueries=true&useSSL=false&&serverTimezone=GMT%2B8
|
||||
url: jdbc:mysql://localhost:3306/blossom?useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&allowMultiQueries=true&useSSL=false&&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: jasmine888
|
||||
hikari:
|
||||
@ -29,6 +29,7 @@ logging:
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
base:
|
||||
time-zone: GMT+8
|
||||
version: @project.version@
|
||||
ex:
|
||||
# 异常打印格式 all/project
|
||||
@ -58,7 +59,6 @@ project:
|
||||
duration: 21600 # 客户端授权时间 6 小时
|
||||
multi-place-login: true # 客户端是否允许多地登录
|
||||
white-list: # 白名单
|
||||
- /sentinel/**
|
||||
- /editor/**
|
||||
- /blog/**
|
||||
- /assets/**
|
||||
|
@ -20,6 +20,7 @@ logging:
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
base:
|
||||
time-zone: GMT+8
|
||||
version: @project.version@
|
||||
ex:
|
||||
# 异常打印格式 all/project
|
||||
|
@ -23,6 +23,7 @@ logging:
|
||||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ project ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
project:
|
||||
base:
|
||||
time-zone: GMT+8
|
||||
version: @project.version@
|
||||
ex:
|
||||
# 异常打印格式 all/project
|
||||
|
@ -8,4 +8,9 @@
|
||||
where article_id = #{articleId}
|
||||
order by cre_time desc
|
||||
</select>
|
||||
|
||||
<delete id="delByIds">
|
||||
delete from blossom_article_log
|
||||
where article_id in <foreach collection="articleIds" item="item" open="(" close=")" separator=",">#{item}</foreach>
|
||||
</delete>
|
||||
</mapper>
|
@ -48,6 +48,10 @@
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="listIdByUserId" resultType="java.lang.Long">
|
||||
select id from blossom_article where user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<!-- 查询全部文章,包含id, name , markdown, tags , userId字段,用于批量索引的建立 -->
|
||||
<select id="listAllIndexField" resultType="com.blossom.backend.server.article.draft.pojo.ArticleEntity">
|
||||
select
|
||||
@ -121,4 +125,9 @@
|
||||
</if>
|
||||
where id = #{articleId}
|
||||
</update>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_article where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -27,4 +27,8 @@
|
||||
o.html = a.html,
|
||||
o.sync_time = now()
|
||||
</update>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_article_open where user_id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
@ -65,4 +65,8 @@
|
||||
from blossom_article_recycle
|
||||
where id = #{id})
|
||||
</insert>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_article_recycle where user_id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
@ -87,4 +87,8 @@
|
||||
where target_Id = #{targetId}
|
||||
and user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_article_reference where user_id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
@ -9,4 +9,8 @@
|
||||
and cre_day = #{today}
|
||||
</select>
|
||||
|
||||
<delete id="delByIds">
|
||||
delete from blossom_article_view
|
||||
where article_id in <foreach collection="articleIds" item="item" open="(" close=")" separator=",">#{item}</foreach>
|
||||
</delete>
|
||||
</mapper>
|
@ -83,4 +83,9 @@
|
||||
</set>
|
||||
where id in <foreach collection="ids" item="item" open="(" close=")" separator=",">#{item}</foreach>
|
||||
</update>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_folder where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -22,4 +22,9 @@
|
||||
where id = #{id}
|
||||
and user_id = #{userId}
|
||||
</update>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_note where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -71,5 +71,7 @@
|
||||
<if test="pid != null">and pid = #{pid}</if>
|
||||
</select>
|
||||
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_picture where user_id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
@ -78,4 +78,8 @@
|
||||
</if>
|
||||
</delete>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_plan where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.blossom.backend.server.article.stat.ArticleStatMapper">
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_stat where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -136,4 +136,8 @@
|
||||
<foreach collection="ids" item="item" open="(" close=")" separator=",">#{item}</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_todo where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -24,6 +24,8 @@
|
||||
<if test="avatar != null">avatar = #{avatar},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
<if test="location != null">location = #{location},</if>
|
||||
<if test="delTime != null">del_time = #{delTime},</if>
|
||||
<if test="type != null">type = #{type},</if>
|
||||
upd_time = now()
|
||||
</set>
|
||||
where id = #{id}
|
||||
@ -33,4 +35,7 @@
|
||||
update base_user set password = '${password}',upd_time = now() where id = #{userId}
|
||||
</update>
|
||||
|
||||
<delete id="delById">
|
||||
delete from base_user where id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
@ -26,4 +26,8 @@
|
||||
<insert id="insertByUserId">
|
||||
insert into base_user_param values (null, #{userId}, #{paramName}, #{paramValue}, now())
|
||||
</insert>
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from base_user_param where user_id = #{userId}
|
||||
</delete>
|
||||
</mapper>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.blossom.backend.server.web.WebMapper">
|
||||
|
||||
<delete id="delByUserId">
|
||||
delete from blossom_web where user_id = #{userId}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
@ -387,7 +387,7 @@ CREATE TABLE IF NOT EXISTS `blossom_article_reference`
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 100000
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_bin
|
||||
COLLATE = utf8mb4_bin COMMENT = '文章引用'
|
||||
ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
@ -478,7 +478,7 @@ CREATE TABLE IF NOT EXISTS `blossom_note`
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 18
|
||||
CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_bin
|
||||
COLLATE = utf8mb4_bin COMMENT = '便签,Note'
|
||||
ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
@ -559,7 +559,7 @@ CREATE TABLE IF NOT EXISTS `blossom_stat`
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 218
|
||||
CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_bin
|
||||
COLLATE = utf8mb4_bin COMMENT = '统计信息'
|
||||
ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
@ -584,7 +584,7 @@ CREATE TABLE IF NOT EXISTS `blossom_web`
|
||||
) ENGINE = InnoDB
|
||||
AUTO_INCREMENT = 292
|
||||
CHARACTER SET = utf8mb4
|
||||
COLLATE = utf8mb4_bin COMMENT = '[FS] 网站收藏'
|
||||
COLLATE = utf8mb4_bin COMMENT = '网站收藏'
|
||||
ROW_FORMAT = DYNAMIC;
|
||||
|
||||
alter table blossom_web
|
||||
@ -637,5 +637,5 @@ CREATE TABLE IF NOT EXISTS `base_user_param`
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `unq_bup_userid_paramname` (`user_id`, `param_name`) COMMENT '用户参数唯一'
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
DEFAULT CHARSET = utf8mb4 COMMENT = '用户参数'
|
||||
COLLATE = utf8mb4_bin;
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>common</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.blossom.common.base;
|
||||
|
||||
import com.blossom.common.base.util.DateUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@ -22,7 +23,7 @@ public final class BaseConstants {
|
||||
public static void desc() {
|
||||
log.info("启动完成" +
|
||||
"\n=========================================================================" +
|
||||
"\n启动成功: 可使用客户端登录, 默认用户名/密码: blos/blos" +
|
||||
"\n启动成功 [" + DateUtils.now() + "], 可使用客户端登录, 默认用户名/密码: blos/blos" +
|
||||
"\n下载地址: https://github.com/blossom-editor/blossom/releases" +
|
||||
"\n文档地址: https://www.wangyunf.com/blossom-doc/index" +
|
||||
"\n博客端访问地址: http://IP:端口(域名)/blog/#/home" +
|
||||
|
@ -17,6 +17,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
@ConfigurationProperties(prefix = "project.base")
|
||||
public class BaseProperties {
|
||||
|
||||
/**
|
||||
* 指定项目的时区
|
||||
*/
|
||||
private String timeZone = "GMT+8";
|
||||
|
||||
/**
|
||||
* 系统版本, 可以使用 @project.version@ 获取 pom 中版本
|
||||
*/
|
||||
|
@ -1,20 +1,34 @@
|
||||
package com.blossom.common.base.util.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 消息编码算法
|
||||
*
|
||||
* @author xzzz
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class Base64Util {
|
||||
|
||||
public static String encrypt(byte[] data) {
|
||||
return Base64.getEncoder().encodeToString(data);
|
||||
}
|
||||
public static String encrypt(byte[] data) {
|
||||
return Base64.getEncoder().encodeToString(data);
|
||||
}
|
||||
|
||||
public static String decrypt(String data) throws IOException {
|
||||
return new String(Base64.getDecoder().decode(data));
|
||||
}
|
||||
public static String decrypt(String data) {
|
||||
return new String(Base64.getDecoder().decode(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否 base64 图片, 只校验格式, 不判断内容是否为正确的图片
|
||||
* 例如: 传入 data:image/png;base64,a, 将会返回 true
|
||||
*/
|
||||
public static boolean isBase64Img(String image) {
|
||||
if (StrUtil.isBlank(image)) {
|
||||
return false;
|
||||
}
|
||||
String prefix = image.substring(0, Math.max(image.indexOf(','), 0));
|
||||
return prefix.startsWith("data:image") && prefix.endsWith("base64");
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>common</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
package com.blossom.common.cache.caffeine;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Expiry;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* key 使用不同的过期时间
|
||||
*
|
||||
* @since 1.13.0
|
||||
*/
|
||||
public class DynamicExpiry implements Expiry<String, Object> {
|
||||
|
||||
@Override
|
||||
public long expireAfterCreate(@NonNull String key, @NonNull Object value, long currentTime) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long expireAfterUpdate(@NonNull String key, @NonNull Object value, long currentTime, @NonNegative long currentDuration) {
|
||||
return currentDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long expireAfterRead(@NonNull String key, @NonNull Object value, long currentTime, @NonNegative long currentDuration) {
|
||||
return currentDuration;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.blossom.common.base.caffeine;
|
||||
package com.blossom.common.cache.caffeine;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
@ -13,25 +13,31 @@ import java.util.concurrent.TimeUnit;
|
||||
public class Test {
|
||||
|
||||
private static final Cache<String, String> cache = Caffeine.newBuilder()
|
||||
.expireAfter(new DynamicExpiry())
|
||||
.initialCapacity(100)
|
||||
.expireAfterWrite(10, TimeUnit.SECONDS)
|
||||
.removalListener((String key, String value, RemovalCause cause) -> System.out.println(key + " 被删除"))
|
||||
.removalListener((String key, String value, RemovalCause cause) -> log.info(key + " 被删除"))
|
||||
.build();
|
||||
|
||||
private static final ScheduledExecutorService clearUpScheduled = Executors.newScheduledThreadPool(1);
|
||||
|
||||
public Test() {
|
||||
clearUpScheduled.scheduleWithFixedDelay(this::clear, 5, 1, TimeUnit.SECONDS);
|
||||
clearUpScheduled.scheduleWithFixedDelay(this::clear, 0, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
log.info("尝试过期缓存");
|
||||
log.info("删除");
|
||||
cache.cleanUp();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Test test = new Test();
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
Test t = new Test();
|
||||
cache.policy().expireVariably().ifPresent(e -> {
|
||||
e.put("A1", "1", 7, TimeUnit.SECONDS);
|
||||
});
|
||||
cache.policy().expireVariably().ifPresent(e -> {
|
||||
e.put("A2", "2", 3, TimeUnit.SECONDS);
|
||||
});
|
||||
Thread.sleep(20 * 1000);
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>common</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>common</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -79,4 +79,8 @@ public abstract class AbstractOSManager implements OSManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deletePath(String pathname) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -73,4 +73,11 @@ public interface OSManager {
|
||||
* @return 是否删除
|
||||
*/
|
||||
boolean delete(String filename);
|
||||
|
||||
/**
|
||||
* 删除文件夹
|
||||
*
|
||||
* @param pathname 文件夹路径
|
||||
*/
|
||||
boolean deletePath(String pathname);
|
||||
}
|
||||
|
@ -111,4 +111,9 @@ public class BLOSManager extends AbstractOSManager implements OSManager {
|
||||
File file = FileUtil.newFile(filename);
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deletePath(String pathname) {
|
||||
return FileUtil.del(pathname);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.blossom</groupId>
|
||||
<artifactId>blossom-backend</artifactId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.blossom</groupId>
|
||||
<artifactId>expand-sentinel</artifactId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -191,7 +191,7 @@ public class SentinelMetricController extends AbstractSentinelController {
|
||||
String interval,
|
||||
Integer customInterval,
|
||||
TimeUnit customIntervalUnit) {
|
||||
log.info("查询 Sentinel 单机流量折线图");
|
||||
log.debug("[SENTINEL] 查询 Sentinel 单机流量折线图");
|
||||
ResourceHistogram rh = explain(startTime, endTime, interval, customInterval, customIntervalUnit, "local");
|
||||
// 读取日志
|
||||
String all = this.metric(resource, rh.getStartTime(), rh.getEndTime(), "");
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.blossom</groupId>
|
||||
<artifactId>expand-sentinel</artifactId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blossom-backend</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>expand-tracker</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>blossom-backend</artifactId>
|
||||
<groupId>com.blossom</groupId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -14,11 +14,11 @@
|
||||
|
||||
<groupId>com.blossom</groupId>
|
||||
<artifactId>blossom-backend</artifactId>
|
||||
<version>1.12.0-SNAPSHOT</version>
|
||||
<version>1.13.0-SNAPSHOT</version>
|
||||
|
||||
<!-- 版本控制 -->
|
||||
<properties>
|
||||
<revision>1.12.0-SNAPSHOT</revision>
|
||||
<revision>1.13.0-SNAPSHOT</revision>
|
||||
|
||||
<!-- 编译设置 -->
|
||||
<java.version>1.8</java.version>
|
||||
|
4
blossom-editor/package-lock.json
generated
4
blossom-editor/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "blossom",
|
||||
"version": "1.12.0",
|
||||
"version": "1.13.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "blossom",
|
||||
"version": "1.12.0",
|
||||
"version": "1.13.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "blossom",
|
||||
"productName": "Blossom",
|
||||
"version": "1.12.0",
|
||||
"version": "1.13.0",
|
||||
"description": "A markdown editor",
|
||||
"license": "MIT",
|
||||
"main": "./out/main/index.js",
|
||||
|
@ -387,7 +387,7 @@
|
||||
<br />
|
||||
<span style="font-size: 13px">加载中...</span>
|
||||
</div>
|
||||
<div class="html-loading-version">Blossom | v1.12.0</div>
|
||||
<div class="html-loading-version">Blossom | v1.13.0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<el-config-provider :size="'small'" :locale="zhCn">
|
||||
<div class="app">
|
||||
<div class="app-header">
|
||||
<AppHeader></AppHeader>
|
||||
</div>
|
||||
<div class="app-main">
|
||||
<RouterView />
|
||||
</div>
|
||||
@ -13,7 +10,6 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElConfigProvider } from 'element-plus'
|
||||
import AppHeader from './components/AppHeader.vue'
|
||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||
</script>
|
||||
|
||||
@ -21,12 +17,9 @@ import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||
.app {
|
||||
@include box(100%, 100%);
|
||||
overflow: hidden;
|
||||
.app-header {
|
||||
@include box(100%, 30px);
|
||||
}
|
||||
|
||||
.app-main {
|
||||
@include box(100%, calc(100% - 30px));
|
||||
@include box(100%, 100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -18,10 +18,18 @@ export const checkApi = (): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/check', {})
|
||||
}
|
||||
|
||||
export const userListApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/user/list', { params })
|
||||
}
|
||||
|
||||
export const userinfoApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/user/info', { params })
|
||||
}
|
||||
|
||||
export const userinfoAdminApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/user/info/admin', { params })
|
||||
}
|
||||
|
||||
export const userUpdApi = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<any>('/user/upd', data)
|
||||
}
|
||||
@ -30,6 +38,18 @@ export const userUpdPwdApi = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<any>('/user/upd/pwd', data)
|
||||
}
|
||||
|
||||
export const userUpdAdminApi = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<any>('/user/upd/admin', data)
|
||||
}
|
||||
|
||||
export const userAddApi = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<any>('/user/add', data)
|
||||
}
|
||||
|
||||
export const userDisabledApi = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<any>('/user/disabled', data)
|
||||
}
|
||||
|
||||
export const userDelReq = (data?: object): Promise<R<any>> => {
|
||||
return rq.post<any>('/user/del', data)
|
||||
}
|
@ -40,13 +40,21 @@ export const userParamListApi = (): Promise<R<any>> => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改系统参数
|
||||
* 修改用户参数
|
||||
* @returns
|
||||
*/
|
||||
export const userParamUpdApi = (data: object): Promise<R<any>> => {
|
||||
return rq.post<R<any>>('/user/param/upd', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员修改用户参数
|
||||
* @returns
|
||||
*/
|
||||
export const userParamUpdAdminApi = (data: object): Promise<R<any>> => {
|
||||
return rq.post<R<any>>('/user/param/upd/admin', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新系统参数缓存
|
||||
* @param data 文件 form
|
||||
@ -304,6 +312,15 @@ export const articleWordsApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/article/stat/words', { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定用户的文章数和文章字数统计
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export const articleWordsUserApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/article/stat/words/user', { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 文章数和文章字数统计
|
||||
* @param params
|
||||
@ -543,6 +560,15 @@ export const pictureStatApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/picture/stat', { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除图片
|
||||
* @param params {id:id}
|
||||
* @returns
|
||||
*/
|
||||
export const pictureStatUserApi = (params?: object): Promise<R<any>> => {
|
||||
return rq.get<R<any>>('/picture/stat/user', { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 转移文件
|
||||
* @param data
|
||||
|
@ -5,7 +5,7 @@ const blossom = {
|
||||
SYS: {
|
||||
NAME: 'Blossom',
|
||||
FULL_NAME: 'BLOSSOM-EDITOR',
|
||||
VERSION: 'v1.12.0',
|
||||
VERSION: 'v1.13.0',
|
||||
|
||||
//
|
||||
DOC: 'https://www.wangyunf.com/blossom-doc/index',
|
||||
|
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconbl"; /* Project id 4118609 */
|
||||
src: url('iconfont.woff2?t=1705742748603') format('woff2'),
|
||||
url('iconfont.woff?t=1705742748603') format('woff'),
|
||||
url('iconfont.ttf?t=1705742748603') format('truetype');
|
||||
src: url('iconfont.woff2?t=1706597865404') format('woff2'),
|
||||
url('iconfont.woff?t=1706597865404') format('woff'),
|
||||
url('iconfont.ttf?t=1706597865404') format('truetype');
|
||||
}
|
||||
|
||||
.iconbl {
|
||||
@ -13,6 +13,14 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.bl-brush-line:before {
|
||||
content: "\ea4f";
|
||||
}
|
||||
|
||||
.bl-a-morevertical-line:before {
|
||||
content: "\ea50";
|
||||
}
|
||||
|
||||
.bl-scroll:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -5,6 +5,20 @@
|
||||
"css_prefix_text": "bl-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "24341231",
|
||||
"name": "brush-line",
|
||||
"font_class": "brush-line",
|
||||
"unicode": "ea4f",
|
||||
"unicode_decimal": 59983
|
||||
},
|
||||
{
|
||||
"icon_id": "24341987",
|
||||
"name": "more 2-line",
|
||||
"font_class": "a-morevertical-line",
|
||||
"unicode": "ea50",
|
||||
"unicode_decimal": 59984
|
||||
},
|
||||
{
|
||||
"icon_id": "9691336",
|
||||
"name": "滚轮滚动",
|
||||
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user