This commit is contained in:
jack ning
2024-09-23 23:18:46 +08:00
parent 654ad8b074
commit d56590d617
127 changed files with 1348 additions and 1681 deletions

Binary file not shown.

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-03-28 22:02:34
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-01 07:01:34
* @LastEditTime: 2024-09-23 22:21:54
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -14,12 +14,15 @@
*/
package com.bytedesk.core.black;
import com.bytedesk.core.base.BaseEntity;
import com.bytedesk.core.rbac.user.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import com.bytedesk.core.base.BaseEntity;
import com.bytedesk.core.constant.BdConstants;
import com.bytedesk.core.constant.TypeConsts;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -31,6 +34,7 @@ import lombok.experimental.Accessors;
/**
* black list
* 黑名单
* TODO: 拉黑ip、添加时间段限制
*/
@Entity
@Data
@@ -42,11 +46,13 @@ import lombok.experimental.Accessors;
@Table(name = "core_black")
public class Black extends BaseEntity {
//
private String reason;
@JsonIgnore
@ManyToOne
private User user;
// 访客 or 用户json类型在json中定义
@Builder.Default
@Column(name = "black_user", columnDefinition = TypeConsts.COLUMN_TYPE_JSON)
@JdbcTypeCode(SqlTypes.JSON)
private String blackUser = BdConstants.EMPTY_JSON_STRING;
private String userUid;
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-06-27 12:20:45
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-01 19:43:10
* @LastEditTime: 2024-09-23 21:47:16
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -14,20 +14,29 @@
*/
package com.bytedesk.core.black;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bytedesk.core.base.BaseController;
import com.bytedesk.core.utils.JsonResult;
import lombok.AllArgsConstructor;
@RestController
@RequestMapping("/api/v1/black")
@AllArgsConstructor
public class BlackController extends BaseController<BlackRequest> {
private final BlackService blackService;
@Override
public ResponseEntity<?> queryByOrg(BlackRequest request) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'queryByOrg'");
Page<BlackResponse> page = blackService.queryByOrg(request);
return ResponseEntity.ok(JsonResult.success(page));
}
@Override
@@ -38,20 +47,22 @@ public class BlackController extends BaseController<BlackRequest> {
@Override
public ResponseEntity<?> create(BlackRequest request) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'create'");
return ResponseEntity.ok(JsonResult.success(blackService.create(request)));
}
@Override
public ResponseEntity<?> update(BlackRequest request) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'update'");
return ResponseEntity.ok(JsonResult.success(blackService.update(request)));
}
@Override
public ResponseEntity<?> delete(BlackRequest request) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'delete'");
blackService.deleteByUid(request.getUid());
return ResponseEntity.ok(JsonResult.success());
}
}

View File

@@ -14,9 +14,9 @@
*/
package com.bytedesk.core.black;
import org.springframework.stereotype.Component;
// import org.springframework.stereotype.Component;
@Component
// @Component
public class BlackEntityListener {
}

View File

@@ -14,9 +14,12 @@
*/
package com.bytedesk.core.black;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface BlackRepository extends JpaRepository<Black, String>, JpaSpecificationExecutor<Black> {
Optional<Black> findByUid(String uid);
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-06-27 12:21:18
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-06-27 12:23:24
* @LastEditTime: 2024-09-23 22:22:05
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -16,6 +16,22 @@ package com.bytedesk.core.black;
import com.bytedesk.core.base.BaseRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@Builder
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class BlackRequest extends BaseRequest {
private String reason;
private String blackUser;
// private String userUid;
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-06-27 12:21:29
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-06-27 12:21:32
* @LastEditTime: 2024-09-23 22:21:11
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -16,6 +16,22 @@ package com.bytedesk.core.black;
import com.bytedesk.core.base.BaseResponse;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@Builder
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
@NoArgsConstructor
public class BlackResponse extends BaseResponse {
private String reason;
private String user;
// private String userUid;
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-06-27 12:20:55
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-01 19:42:05
* @LastEditTime: 2024-09-23 21:52:07
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -16,11 +16,20 @@ package com.bytedesk.core.black;
import java.util.Optional;
import org.modelmapper.ModelMapper;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import com.bytedesk.core.base.BaseService;
import com.bytedesk.core.rbac.auth.AuthService;
import com.bytedesk.core.rbac.user.User;
import com.bytedesk.core.uid.UidUtils;
import lombok.AllArgsConstructor;
@@ -28,10 +37,25 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public class BlackService extends BaseService<Black, BlackRequest, BlackResponse> {
private final BlackRepository repository;
private final ModelMapper modelMapper;
private final UidUtils uidUtils;
private final AuthService authService;
@Override
public Page<BlackResponse> queryByOrg(BlackRequest request) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'queryByOrg'");
Pageable pageable = PageRequest.of(request.getPageNumber(), request.getPageSize(), Sort.Direction.DESC,
"createdAt");
Specification<Black> specification = BlackSpecification.search(request);
Page<Black> blacks = repository.findAll(specification, pageable);
return blacks.map(this::convertToResponse);
}
@Override
@@ -40,16 +64,25 @@ public class BlackService extends BaseService<Black, BlackRequest, BlackResponse
throw new UnsupportedOperationException("Unimplemented method 'queryByUser'");
}
@Cacheable(value = "black", key = "#uid", unless = "#result == null")
@Override
public Optional<Black> findByUid(String uid) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'findByUid'");
return repository.findByUid(uid);
}
@Override
public BlackResponse create(BlackRequest request) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'create'");
User user = authService.getCurrentUser();
//
Black entity = modelMapper.map(request, Black.class);
entity.setUid(uidUtils.getUid());
entity.setUserUid(user.getUid());
//
Black savedBlack = save(entity);
if (savedBlack == null) {
throw new RuntimeException("Create black failed");
}
return convertToResponse(savedBlack);
}
@Override
@@ -60,8 +93,12 @@ public class BlackService extends BaseService<Black, BlackRequest, BlackResponse
@Override
public Black save(Black entity) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'save'");
try {
return repository.save(entity);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
@@ -84,8 +121,7 @@ public class BlackService extends BaseService<Black, BlackRequest, BlackResponse
@Override
public BlackResponse convertToResponse(Black entity) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'convertToResponse'");
return modelMapper.map(entity, BlackResponse.class);
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-06-27 12:21:44
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-06-27 12:24:15
* @LastEditTime: 2024-09-23 21:28:07
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -14,8 +14,24 @@
*/
package com.bytedesk.core.black;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.jpa.domain.Specification;
import com.bytedesk.core.base.BaseSpecification;
import jakarta.persistence.criteria.Predicate;
public class BlackSpecification extends BaseSpecification {
public static Specification<Black> search(BlackRequest request) {
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.addAll(getBasicPredicates(root, criteriaBuilder, request.getOrgUid()));
//
//
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-11 18:21:26
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-06-08 16:47:17
* @LastEditTime: 2024-09-20 16:03:46
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -16,8 +16,6 @@ package com.bytedesk.core.category;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -34,7 +32,6 @@ public class CategoryController extends BaseController<CategoryRequest> {
private final CategoryService categoryService;
@GetMapping("/query/org")
@Override
public ResponseEntity<?> queryByOrg(CategoryRequest request) {
@@ -49,7 +46,6 @@ public class CategoryController extends BaseController<CategoryRequest> {
throw new UnsupportedOperationException("Unimplemented method 'query'");
}
@PostMapping("/create")
@Override
public ResponseEntity<?> create(@RequestBody CategoryRequest request) {
@@ -58,7 +54,6 @@ public class CategoryController extends BaseController<CategoryRequest> {
return ResponseEntity.ok(JsonResult.success(response));
}
@PostMapping("/update")
@Override
public ResponseEntity<?> update(@RequestBody CategoryRequest request) {
@@ -67,7 +62,6 @@ public class CategoryController extends BaseController<CategoryRequest> {
return ResponseEntity.ok(JsonResult.success(response));
}
@PostMapping("/delete")
@Override
public ResponseEntity<?> delete(@RequestBody CategoryRequest request) {

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-30 07:52:26
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-07-30 09:11:25
* @LastEditTime: 2024-09-19 12:50:10
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -15,6 +15,7 @@
package com.bytedesk.core.config;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Value;
@@ -62,6 +63,7 @@ public class BytedeskConfig {
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); //
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
restTemplate.setInterceptors(Arrays.asList(new TraceIdInterceptor()));
return restTemplate;
}
@@ -71,16 +73,16 @@ public class BytedeskConfig {
}
@Bean
public OpenAPI apiInfo() {
return new OpenAPI().info(new Info().title("bytedesk apis").version(appVersion));
}
public OpenAPI apiInfo() {
return new OpenAPI().info(new Info().title("bytedesk apis").version(appVersion));
}
// @Bean
// public GroupedOpenApi httpApi() {
// return GroupedOpenApi.builder()
// .group("http")
// .pathsToMatch("/**")
// .build();
// }
// @Bean
// public GroupedOpenApi httpApi() {
// return GroupedOpenApi.builder()
// .group("http")
// .pathsToMatch("/**")
// .build();
// }
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-02-23 14:42:58
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-09 16:26:19
* @LastEditTime: 2024-09-20 10:29:14
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -46,6 +46,7 @@ import com.bytedesk.core.socket.stomp.StompUnsubscribeEvent;
import com.bytedesk.core.thread.Thread;
import com.bytedesk.core.thread.ThreadCreateEvent;
import com.bytedesk.core.thread.ThreadUpdateEvent;
import com.bytedesk.core.thread.ThreadUpdateStatusEvent;
import com.bytedesk.core.topic.TopicCreateEvent;
import com.bytedesk.core.topic.TopicUpdateEvent;
@@ -146,6 +147,10 @@ public class BytedeskEventPublisher {
applicationEventPublisher.publishEvent(new ThreadUpdateEvent(this, thread));
}
public void publishThreadUpdateStatusEvent(Thread thread, String status) {
applicationEventPublisher.publishEvent(new ThreadUpdateStatusEvent(this, thread, status));
}
public void publishActionCreateEvent(Action action) {
applicationEventPublisher.publishEvent(new ActionCreateEvent(this, action));
}

View File

@@ -29,9 +29,10 @@ public class CorsConfig {
/**
* 经测试仅有此处起作用corsFilter()和WebMvcConfig.addCorsMappings()不起作用
*
* @return
*/
// https://docs.spring.io/spring-security/reference/reactive/integrations/cors.html
// https://docs.spring.io/spring-security/reference/reactive/channels/cors.html
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
@@ -40,31 +41,33 @@ public class CorsConfig {
// configuration.setAllowedOriginPatterns(List.of("*")); // 不能启用
configuration.setAllowedMethods(List.of("*"));
configuration.setAllowedHeaders(List.of("*"));
// configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
// configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE",
// "OPTIONS"));
// configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
//
//
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
// @Bean
// public CorsFilter corsFilter() {
// log.info("CorsConfig.corsFilter()");
// CorsConfiguration corsConfiguration = new CorsConfiguration();
// //1,允许任何来源
// corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
// //2,允许任何请求头
// corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
// //3,允许任何方法
// corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
// //4,允许凭证
// corsConfiguration.setAllowCredentials(true);
// //
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// source.registerCorsConfiguration("/**", corsConfiguration);
// //
// return new CorsFilter(source);
// }
// @Bean
// public CorsFilter corsFilter() {
// log.info("CorsConfig.corsFilter()");
// CorsConfiguration corsConfiguration = new CorsConfiguration();
// //1,允许任何来源
// corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));
// //2,允许任何请求头
// corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
// //3,允许任何方法
// corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
// //4,允许凭证
// corsConfiguration.setAllowCredentials(true);
// //
// UrlBasedCorsConfigurationSource source = new
// UrlBasedCorsConfigurationSource();
// source.registerCorsConfiguration("/**", corsConfiguration);
// //
// return new CorsFilter(source);
// }
}

View File

@@ -62,7 +62,7 @@ public class SecurityConfig {
.requestMatchers("/api/**").authenticated()
// .requestMatchers("/actuator/**").authenticated() // monitor endpoints
.anyRequest().permitAll())
// https://docs.spring.io/spring-security/reference/servlet/integrations/websocket.html
// https://docs.spring.io/spring-security/reference/servlet/channels/websocket.html
.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin().disable()))
.authenticationProvider(authenticationProvider())
// .oauth2ResourceServer((oauth2) -> oauth2.jwt(withDefaults()))

View File

@@ -0,0 +1,70 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-09-19 11:36:33
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-19 12:47:23
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
* 仅支持企业内部员工自用严禁私自用于销售、二次销售或者部署SaaS方式销售
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.config;
import java.io.IOException;
import java.util.UUID;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import com.bytedesk.core.constant.BdConstants;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
/**
* 日志链路跟踪
* https://developer.aliyun.com/article/1581355?spm=5176.26934562.main.1.67c12f7755gBG5
*/
@Slf4j
@Component
public class TraceIdFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String traceId = httpRequest.getHeader(BdConstants.TRACE_ID);
if (traceId == null) {
traceId = UUID.randomUUID().toString();
}
// 设置到ThreadLocal方便后续在业务代码中获取
MDC.put(BdConstants.TRACE_ID, traceId);
// 添加到响应头,便于下游服务获取
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader(BdConstants.TRACE_ID, traceId);
chain.doFilter(request, response);
}
@Override
public void destroy() {
log.info("TraceIdFilter destroy");
// 请求处理完成后清理ThreadLocal中存储的traceId
// MDC.clear();
MDC.remove(BdConstants.TRACE_ID);
}
}

View File

@@ -0,0 +1,38 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-09-19 12:45:53
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-19 12:50:40
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
* 仅支持企业内部员工自用严禁私自用于销售、二次销售或者部署SaaS方式销售
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.config;
import java.io.IOException;
import org.slf4j.MDC;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import com.bytedesk.core.constant.BdConstants;
public class TraceIdInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
String traceId = MDC.get(BdConstants.TRACE_ID);
if (traceId != null) {
request.getHeaders().add(BdConstants.TRACE_ID, traceId);
}
return execution.execute(request, body);
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-02-02 21:48:19
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-08 08:43:47
* @LastEditTime: 2024-09-19 12:52:21
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -28,7 +28,7 @@ public class BdConstants {
// bytedesk
public static final String PLATFORM_BYTEDESK = "BYTEDESK";
// public static final boolean IS_DEBUG = false;
public static final String TRACE_ID = "traceId";
// 空字符串
public static final String EMPTY_STRING = "";
public static final String EMPTY_JSON_STRING = "{}";
@@ -40,6 +40,7 @@ public class BdConstants {
public static final String DEFAULT_FILE_ASISTANT_UID = "df_fa_uid";
public static final String DEFAULT_SYSTEM_UID = "df_sys_uid";
public static final String DEFAULT_KB_UID = "df_kb_uid";
public static final String DEFAULT_DY_UID = "df_dy_uid";
//
public static final String ACTION_LOGIN_USERNAME = "loginWithUsernamePassword";
public static final String ACTION_LOGIN_MOBILE = "loginWithMobileCode";

View File

@@ -20,6 +20,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.server.ResponseStatusException;
@@ -131,6 +132,12 @@ public class GlobalControllerAdvice {
return ResponseEntity.badRequest().body(JsonResult.error("TODO: jetty Websocket Timeout Exception"));
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseEntity<?> handleHttpRequestMethodNotSupportedException(
HttpRequestMethodNotSupportedException ex) {
return ResponseEntity.badRequest().body(JsonResult.error("Http Request Method Not Supported Exception", 400));
}
@ExceptionHandler(Exception.class)
// @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity<?> handleException(Exception e) {

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-26 09:28:30
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-06-12 19:06:55
* @LastEditTime: 2024-09-12 11:58:16
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -22,7 +22,4 @@ public class UsernameExistsException extends BaseException {
super(message);
//TODO Auto-generated constructor stub
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-17 12:53:46
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-06-27 17:04:27
* @LastEditTime: 2024-09-12 11:58:40
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -40,7 +40,7 @@ public class IpInterceptor implements HandlerInterceptor {
private static final List<String> BLACKLISTED_IPS = Arrays.asList(
"175.27.32.31",
"112.53.2.93"
// 可以根据需要动态配置这个列表,例如从数据库或配置文件中加载
// TODO: 可以根据需要动态配置这个列表,例如从数据库或配置文件中加载
);
@Override

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-16 18:04:37
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-07 16:23:29
* @LastEditTime: 2024-09-12 19:01:36
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -191,7 +191,8 @@ public class MessagePersistService {
// 消息撤回,从数据库中删除消息
private void dealWithMessageRecall(MessageProtobuf message) {
// log.info("dealWithMessageRecall");
messageService.deleteByUid(message.getUid());
// content为撤回消息的uid
messageService.deleteByUid(message.getContent());
}
private void dealWithRateMessage(MessageTypeEnum type, MessageProtobuf message) {
@@ -252,6 +253,7 @@ public class MessagePersistService {
}
}
// 处理转接消息
private void dealWithTransferMessage(MessageTypeEnum type, MessageProtobuf message) {
// log.info("dealWithTransferMessage");
MessageTransferContent transferContentObject = JSONObject.parseObject(message.getContent(),
@@ -269,4 +271,5 @@ public class MessagePersistService {
}
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-07-01 12:37:41
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-10 17:06:01
* @LastEditTime: 2024-09-12 22:23:34
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -194,14 +194,13 @@ public class MessageUnreadEventListener {
@EventListener
public void onQuartzFiveSecondEvent(QuartzFiveSecondEvent event) {
// log.info("message quartz five second event: " + event);
}
@EventListener
public void onMqttConnectEvent(MqttConnectedEvent event) {
// 用户clientId格式: uid/client/deviceUid
String clientId = event.getClientId();
log.info("message unread mqtt connect event: {}", clientId);
// String clientId = event.getClientId();
// log.info("message unread mqtt connect event: {}", clientId);
// String[] clientIdArray = clientId.split("/");
// if (clientIdArray.length != 3) {
// return;
@@ -217,7 +216,7 @@ public class MessageUnreadEventListener {
@EventListener
public void onStompSessionConnectedEvent(StompConnectedEvent event) {
// TODO: 将缓存消息推送给相应访客端
log.info("message unread stomp session connect event: {}", event.getClientId());
// log.info("message unread stomp session connect event: {}", event.getClientId());
}
}

View File

@@ -57,7 +57,6 @@ public class AuthEventListener {
contentObject.put(I18Consts.I18N_NOTICE_IP, action.getIp());
contentObject.put(I18Consts.I18N_NOTICE_IPLOCATION, action.getIpLocation());
//
// MessageProtobuf messsage = messageService.createNoticeMessage(user, JSON.toJSONString(contentObject));
MessageProtobuf messsage = MessageUtils.createNoticeMessage(uidUtils.getCacheSerialUid(), user.getUid(), user.getOrgUid(),
JSON.toJSONString(contentObject));
MessageUtils.notifyUser(messsage);

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-23 07:53:01
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-27 13:18:42
* @LastEditTime: 2024-09-19 10:03:16
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -23,7 +23,6 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
// import com.bytedesk.core.enums.PlatformEnum;
import com.bytedesk.core.rbac.user.User;
import com.bytedesk.core.rbac.user.UserDetailsImpl;
import com.bytedesk.core.rbac.user.UserDetailsServiceImpl;

View File

@@ -83,8 +83,6 @@ public class User extends BaseEntityNoOrg {
private String description = I18Consts.I18N_USER_DESCRIPTION;
@Builder.Default
// @Enumerated(EnumType.STRING)
// private Sex sex = Sex.UNKNOWN;
private String sex = Sex.UNKNOWN.name();
@Builder.Default
@@ -104,8 +102,6 @@ public class User extends BaseEntityNoOrg {
private boolean mobileVerified = false;
@Builder.Default
// @Enumerated(EnumType.STRING)
// private PlatformEnum platform = PlatformEnum.BYTEDESK;
private String platform = PlatformEnum.BYTEDESK.name();
@JsonIgnore

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-29 16:21:24
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-18 09:36:27
* @LastEditTime: 2024-09-19 10:05:17
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -19,10 +19,6 @@ import java.util.Optional;
// import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
// import org.springframework.data.rest.core.annotation.RepositoryRestResource;
// import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Repository;
// import com.bytedesk.core.enums.PlatformEnum;
/**
* https://spring.io/guides/tutorials/react-and-spring-data-rest/
@@ -31,7 +27,7 @@ import org.springframework.stereotype.Repository;
*/
// @RepositoryRestResource(exported = false)
// @PreAuthorize("hasRole('ROLE_ADMIN')")
@Repository
// @Repository
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
Optional<User> findByUid(String uid);

View File

@@ -48,7 +48,7 @@ public class StompConfig implements WebSocketMessageBrokerConfigurer {
stompEndpointRegistry.addEndpoint("/stomp")
.setAllowedOriginPatterns("*")
.setHandshakeHandler(handshakeHandler());
// https://docs.spring.io/spring-security/reference/servlet/integrations/websocket.html
// https://docs.spring.io/spring-security/reference/servlet/channels/websocket.html
// FIXME: Access to XMLHttpRequest at
// 'http://127.0.0.1:9003/sockjs/info?t=1718785780963' from origin
// 'http://127.0.0.1:9006' has been blocked by CORS policy: The value of the

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-07-09 22:19:21
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-07-09 22:19:24
* @LastEditTime: 2024-09-23 21:27:59
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -14,6 +14,8 @@
*/
package com.bytedesk.core.tag;
public class TagSpecification {
import com.bytedesk.core.base.BaseSpecification;
public class TagSpecification extends BaseSpecification {
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-29 16:21:24
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-11 08:50:25
* @LastEditTime: 2024-09-23 16:07:43
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -48,16 +48,16 @@ import lombok.experimental.Accessors;
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners({ ThreadEntityListener.class })
// 表继承Table Per Class
// Inheritance在这种策略中每一个类父类和每个子类都映射到一个独立的数据库表中。子类表将只包含子类特有的属性以及与父类表相关联的主键。
// @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Table(name = "core_thread")
public class Thread extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* used to push message
* topic format:
* workgroup_wid + '/' + visitor_vid
* agent_aid + '/' + visitor_vid
* such as: wid/vid or aid/vid
* @{TopicUtils}
*/
@NotBlank
private String topic;
@@ -69,16 +69,14 @@ public class Thread extends BaseEntity {
* @{ThreadTypeConsts}
*/
@Builder.Default
// @Enumerated(EnumType.STRING)
@Column(name = "thread_type", nullable = false)
// private ThreadTypeEnum type = ThreadTypeEnum.WORKGROUP;
private String type = ThreadTypeEnum.WORKGROUP.name();
// TODO: 标记问题是否解决
/** closed/open, agent closed/auto closed */
@Builder.Default
// @Enumerated(EnumType.STRING)
// private ThreadStatusEnum status = ThreadStatusEnum.NORMAL;
private String status = ThreadStatusEnum.NORMAL.name();
private String status = ThreadStatusEnum.START.name();
// 置顶
@Builder.Default
@@ -151,31 +149,50 @@ public class Thread extends BaseEntity {
@JdbcTypeCode(SqlTypes.JSON)
private String agent = BdConstants.EMPTY_JSON_STRING;
// 机器人和agent可以同时存在人工接待的时候机器人可以同时给出答案客服可以选用
// 存储机器人信息
// @Builder.Default
// @Column(columnDefinition = TypeConsts.COLUMN_TYPE_JSON)
// @JdbcTypeCode(SqlTypes.JSON)
// private String robot = BdConstants.EMPTY_JSON_STRING;
// belongs to user
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
private User owner;
// public Boolean isInit() {
// return this.status == ThreadStatusEnum.NORMAL.name();
// }
//
public Boolean isClosed() {
return this.status == ThreadStatusEnum.AGENT_CLOSED.name() || this.status == ThreadStatusEnum.AUTO_CLOSED.name();
return this.status.equals(ThreadStatusEnum.AGENT_CLOSED.name())
|| this.status.equals(ThreadStatusEnum.AUTO_CLOSED.name());
}
public Boolean isCustomerService() {
return this.type == ThreadTypeEnum.AGENT.name() || this.type == ThreadTypeEnum.WORKGROUP.name();
return this.type.equals(ThreadTypeEnum.AGENT.name())
|| this.type.equals(ThreadTypeEnum.WORKGROUP.name());
}
public Boolean isRobotType() {
return this.type.equals(ThreadTypeEnum.ROBOT.name());
}
public Boolean isWorkgroupType() {
return this.type.equals(ThreadTypeEnum.WORKGROUP.name());
}
public Boolean isAgentType() {
return this.type.equals(ThreadTypeEnum.AGENT.name());
}
public ThreadProtobuf toProtobuf() {
return ConvertUtils.convertToThreadProtobuf(this);
}
public UserProtobuf getAgentProtobuf() {
return JSON.parseObject(this.agent, UserProtobuf.class);
}
// public UserProtobuf getAgentProtobuf() {
// return JSON.parseObject(this.agent, UserProtobuf.class);
// }
public UserProtobuf getUserProtobuf() {
return JSON.parseObject(this.user, UserProtobuf.class);

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-29 16:21:24
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-07 16:41:04
* @LastEditTime: 2024-09-20 09:51:27
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -92,7 +92,7 @@ public class ThreadController extends BaseController<ThreadRequest> {
@PostMapping("/close")
public ResponseEntity<?> close(@RequestBody ThreadRequest request) {
request.setStatus(ThreadStatusEnum.AGENT_CLOSED);
request.setStatus(ThreadStatusEnum.AGENT_CLOSED.name());
ThreadResponse threadResponse = threadService.close(request);

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-15 09:30:56
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-27 13:07:30
* @LastEditTime: 2024-09-20 10:27:24
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -15,6 +15,7 @@
package com.bytedesk.core.thread;
import org.springframework.util.SerializationUtils;
import org.springframework.stereotype.Component;
import com.bytedesk.core.config.BytedeskEventPublisher;
@@ -22,29 +23,39 @@ import com.bytedesk.core.utils.ApplicationContextHolder;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostUpdate;
// import jakarta.persistence.PostUpdate;
import lombok.extern.slf4j.Slf4j;
// @Async
@Slf4j
@Component
public class ThreadEntityListener {
// @Transient
// private transient Thread oldThread;
@PostPersist
public void postPersist(Thread thread) {
log.info("thread postPersist {}", thread.getUid());
// send notifications
Thread clonedThread = SerializationUtils.clone(thread);
BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class);
bytedeskEventPublisher.publishThreadCreateEvent(clonedThread);
}
// @PreUpdate
// public void preUpdate(Thread thread) {
// log.info("preUpdate {}", thread.getUid());
// this.oldThread = SerializationUtils.clone(thread);
// }
@PostUpdate
public void postUpdate(Thread thread) {
log.info("postUpdate {}", thread.getUid());
// send notifications
Thread clonedThread = SerializationUtils.clone(thread);
//
BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class);
bytedeskEventPublisher.publishThreadUpdateEvent(clonedThread);
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-06-28 13:32:23
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-11 11:19:50
* @LastEditTime: 2024-09-19 14:44:32
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -56,6 +56,11 @@ public class ThreadEventListener {
// return;
// }
// 机器人接待的会话存在user == null的情况不需要订阅topic
if (user == null) {
return;
}
// 创建客服会话之后需要订阅topic
if (thread.getType().equals(ThreadTypeEnum.AGENT.name())
|| thread.getType().equals(ThreadTypeEnum.WORKGROUP.name())) {
@@ -101,7 +106,7 @@ public class ThreadEventListener {
.userUid(user.getUid())
.build();
topicCacheService.pushRequest(request);
} else if (thread.getOwner() != null) {
} else if (user != null) {
TopicRequest request = TopicRequest.builder()
.topic(thread.getTopic())
.userUid(user.getUid())

View File

@@ -1,8 +1,8 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-07-18 19:23:14
* @Date: 2024-09-19 10:44:15
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-07-18 19:23:17
* @LastEditTime: 2024-09-19 15:27:05
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -12,21 +12,28 @@
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.message;
package com.bytedesk.core.thread;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.Serializable;
import lombok.AllArgsConstructor;
// import lombok.extern.slf4j.Slf4j;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
// 消息接口可匿名访问
// @Slf4j
@RestController
@Data
@Builder
@AllArgsConstructor
@RequestMapping("/visitor/api/v1")
public class MessageControllerVisitor {
@NoArgsConstructor
public class ThreadFlowNode implements Serializable {
private final static long serialVersionUID = 1L;
private ThreadStatusEnum status;
private String content;
private String createAt;
private ThreadFlowNode children[];
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-02-21 10:01:12
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-16 08:12:30
* @LastEditTime: 2024-09-20 09:50:49
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -43,7 +43,7 @@ public class ThreadRequest extends BaseRequest {
//
private String topic;
private ThreadStatusEnum status;
private String status;
private UserProtobuf user;

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-02-21 10:01:27
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-16 08:12:39
* @LastEditTime: 2024-09-20 09:50:26
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -17,7 +17,6 @@ package com.bytedesk.core.thread;
import java.util.Date;
import com.bytedesk.core.base.BaseResponse;
import com.bytedesk.core.enums.ClientEnum;
import com.bytedesk.core.rbac.user.UserProtobuf;
import lombok.AllArgsConstructor;
@@ -44,9 +43,9 @@ public class ThreadResponse extends BaseResponse {
private String content;
private ThreadTypeEnum type;
private String type;
private ThreadStatusEnum status;
private String status;
//
private Boolean top;
@@ -63,7 +62,7 @@ public class ThreadResponse extends BaseResponse {
private Boolean folded;
private ClientEnum client;
private String client;
private String extra;

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-01-29 16:21:24
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-07 19:00:26
* @LastEditTime: 2024-09-20 10:27:49
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -35,6 +35,7 @@ import org.springframework.util.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.bytedesk.core.base.BaseService;
// import com.bytedesk.core.config.BytedeskEventPublisher;
import com.bytedesk.core.enums.ClientEnum;
import com.bytedesk.core.message.MessageProtobuf;
import com.bytedesk.core.message.MessageTypeEnum;
@@ -57,13 +58,15 @@ import lombok.extern.slf4j.Slf4j;
@AllArgsConstructor
public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResponse> {
private AuthService authService;
private final AuthService authService;
private ModelMapper modelMapper;
private final ModelMapper modelMapper;
private ThreadRepository threadRepository;
private final ThreadRepository threadRepository;
private UidUtils uidUtils;
private final UidUtils uidUtils;
// private final BytedeskEventPublisher bytedeskEventPublisher;
public Page<ThreadResponse> queryByOrg(ThreadRequest request) {
@@ -112,7 +115,7 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
//
Thread thread = modelMapper.map(request, Thread.class);
thread.setUid(uidUtils.getCacheSerialUid());
thread.setStatus(ThreadStatusEnum.NORMAL.name());
thread.setStatus(ThreadStatusEnum.START.name());
//
String user = JSON.toJSONString(request.getUser());
log.info("request {}, user {}", request.toString(), user);
@@ -176,7 +179,7 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
.type(ThreadTypeEnum.ASISTANT.name())
.topic(topic)
.unreadCount(0)
.status(ThreadStatusEnum.NORMAL.name())
.status(ThreadStatusEnum.START.name())
.client(ClientEnum.SYSTEM.name())
.user(JSON.toJSONString(userSimple))
.owner(user)
@@ -213,7 +216,7 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
.type(ThreadTypeEnum.CHANNEL.name())
.topic(topic)
.unreadCount(0)
.status(ThreadStatusEnum.NORMAL.name())
.status(ThreadStatusEnum.START.name())
.client(ClientEnum.SYSTEM.name())
.user(JSON.toJSONString(userSimple))
.owner(user)
@@ -259,40 +262,37 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
public ThreadResponse autoClose(Thread thread) {
// log.info(thread.getUid() + "自动关闭");
// thread.setStatus(ThreadStatusEnum.AUTO_CLOSED.name());
// return save(thread);
ThreadRequest threadRequest = ThreadRequest.builder()
.topic(thread.getTopic())
.status(ThreadStatusEnum.AUTO_CLOSED)
.status(ThreadStatusEnum.AUTO_CLOSED.name())
.build();
return close(threadRequest);
}
public ThreadResponse close(ThreadRequest threadRequest) {
// Optional<Thread> threadOptional = findByUid(threadRequest.getUid());
Optional<Thread> threadOptional = findByTopic(threadRequest.getTopic());
if (!threadOptional.isPresent()) {
throw new RuntimeException("close thread " + threadRequest.getTopic() + " not found");
}
//
Thread thread = threadOptional.get();
//
if (ThreadStatusEnum.AGENT_CLOSED.name().equals(thread.getStatus())
|| ThreadStatusEnum.AUTO_CLOSED.name().equals(thread.getStatus())) {
// log.info("thread {} is already closed", uid);
throw new RuntimeException("thread is already closed");
}
// thread.setStatus(ThreadStatusEnum.AGENT_CLOSED.name());
thread.setStatus(threadRequest.getStatus().name());
thread.setStatus(threadRequest.getStatus());
//
Thread updateThread = save(thread);
if (updateThread == null) {
throw new RuntimeException("thread save failed");
}
// bytedeskEventPublisher.publishThreadUpdateEvent(updateThread);
// 发布关闭消息, 通知用户
String content = threadRequest.getStatus().equals(ThreadStatusEnum.AUTO_CLOSED) ? I18Consts.I18N_AUTO_CLOSED : I18Consts.I18N_AGENT_CLOSED;
MessageProtobuf messageProtobuf = MessageUtils.createThreadMessage(uidUtils.getCacheSerialUid(), updateThread,
MessageTypeEnum.fromValue(threadRequest.getStatus().name()),
String content = threadRequest.getStatus().equals(ThreadStatusEnum.AUTO_CLOSED.name()) ? I18Consts.I18N_AUTO_CLOSED
: I18Consts.I18N_AGENT_CLOSED;
MessageProtobuf messageProtobuf = MessageUtils.createThreadMessage(uidUtils.getCacheSerialUid(), updateThread,
MessageTypeEnum.fromValue(threadRequest.getStatus()),
content);
MessageUtils.notifyUser(messageProtobuf);
//
@@ -335,15 +335,14 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
}
// 找到某个访客对应某个一对一客服未关闭会话
@Cacheable(value = "thread", key = "#topic", unless = "#result == null")
public Optional<Thread> findByTopicNotClosed(String topic, String status) {
return threadRepository.findFirstByTopicAndStatusNotContainingAndDeleted(topic, "CLOSED", false);
}
// @Cacheable(value = "thread", key = "#topic", unless = "#result == null")
// public Optional<Thread> findByTopicNotClosed(String topic, String status) {
// return threadRepository.findFirstByTopicAndStatusNotContainingAndDeleted(topic, "CLOSED", false);
// }
// 找到某个访客当前对应某技能组未关闭会话
@Cacheable(value = "thread", key = "#workgroupUid + '-' + #visitorUid", unless = "#result == null")
public Optional<Thread> findByWgTopicNotClosed(String topic) {
// String likeTopic = TopicUtils.TOPIC_ORG_WORKGROUP_PREFIX + workgroupUid + "/%/" + visitorUid;
// @Cacheable(value = "thread", key = "#workgroupUid + '-' + #visitorUid", unless = "#result == null")
@Cacheable(value = "thread", key = "#topic", unless = "#result == null")
public Optional<Thread> findByTopicNotClosed(String topic) {
List<String> statuses = Arrays
.asList(new String[] { ThreadStatusEnum.AGENT_CLOSED.name(), ThreadStatusEnum.AUTO_CLOSED.name() });
return threadRepository.findFirstTopicAndStatusesNotInAndDeleted(topic, statuses, false);
@@ -358,33 +357,13 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
// TODO: 更新缓存
// @Cacheable(value = "threadOpen")
public List<Thread> findStatusOpen() {
List<String> types = Arrays.asList(new String[] { ThreadTypeEnum.AGENT.name(), ThreadTypeEnum.WORKGROUP.name(), ThreadTypeEnum.ROBOT.name() });
List<String> types = Arrays.asList(new String[] { ThreadTypeEnum.AGENT.name(), ThreadTypeEnum.WORKGROUP.name(),
ThreadTypeEnum.ROBOT.name() });
List<String> statuses = Arrays
.asList(new String[] { ThreadStatusEnum.AUTO_CLOSED.name(), ThreadStatusEnum.AGENT_CLOSED.name() });
return threadRepository.findByTypesInAndStatusesNotInAndDeleted(types, statuses, false);
}
public Boolean isClosed(Thread thread) {
return ThreadStatusEnum.AGENT_CLOSED.name().equals(thread.getStatus())
|| ThreadStatusEnum.AUTO_CLOSED.name().equals(thread.getStatus());
}
// public Thread reenter(Thread thread) {
// if (thread.getType().equals(ThreadTypeEnum.AGENT)
// || thread.getType().equals(ThreadTypeEnum.WORKGROUP)) {
// thread.setUnreadCount(1);
// }
// thread.setStatus(ThreadStatusEnum.REENTER);
// return save(thread);
// }
// public Thread agentClose(Thread thread) {
// thread.setStatus(ThreadStatusEnum.AGENT_CLOSED);
// return save(thread);
// }
@Caching(put = {
@CachePut(value = "thread", key = "#thread.uid"),
@CachePut(value = "thread", key = "#thread.topic")
@@ -394,7 +373,6 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
return threadRepository.save(thread);
} catch (Exception e) {
e.printStackTrace();
// handleOptimisticLockingFailureException(e, thread);
}
return null;
}
@@ -422,15 +400,6 @@ public class ThreadService extends BaseService<Thread, ThreadRequest, ThreadResp
return threadResponse;
}
//
public void initData() {
if (threadRepository.count() > 0) {
return;
}
}
@Override
public Page<ThreadResponse> queryByUser(ThreadRequest request) {
// TODO Auto-generated method stub

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-05-25 10:43:58
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-08-04 17:52:52
* @LastEditTime: 2024-09-18 17:36:41
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -15,10 +15,10 @@
package com.bytedesk.core.thread;
public enum ThreadStatusEnum {
START, // 开始会话
QUEUING, // 排队中
NORMAL, // 正常
CONTINUE, // 会话进行中,访客关闭会话页面之后,重新进入
REOPEN, // 会话关闭之后,重新进入
RESTART, // 会话关闭之后,重新进入
OFFLINE, // 客服不在线
RATED, // rated, prevent repeated rate
AUTO_CLOSED, // 自动关闭
@@ -29,6 +29,7 @@ public enum ThreadStatusEnum {
MONITORED, // 会话监控
TRANSFERED, // 会话转接
INVITED, // 会话邀请
SOLVED, // 问题已解决
;
// 根据字符串查找对应的枚举常量

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-23 08:51:27
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-05-23 09:54:54
* @LastEditTime: 2024-09-20 10:27:36
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -29,5 +29,4 @@ public class ThreadUpdateEvent extends ApplicationEvent {
super(source);
this.thread = thread;
}
}

View File

@@ -0,0 +1,35 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-23 08:51:27
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-20 10:28:38
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
* 仅支持企业内部员工自用严禁私自用于销售、二次销售或者部署SaaS方式销售
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
* 联系270580156@qq.com
* Copyright (c) 2024 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.core.thread;
import org.springframework.context.ApplicationEvent;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class ThreadUpdateStatusEvent extends ApplicationEvent {
private Thread thread;
private String status;
public ThreadUpdateStatusEvent(Object source, Thread thread, String status) {
super(source);
this.thread = thread;
this.status = status;
}
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-13 16:03:44
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-07 12:51:48
* @LastEditTime: 2024-09-20 09:30:14
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -45,14 +45,11 @@ public class Topic extends BaseEntityNoOrg {
private static final long serialVersionUID = 1L;
// @Column(nullable = false)
// private String topic;
/** 为防止后添加的记录clientIds缺失所以用数组代替这样每个用户在topic中只有一条记录cliendIds可共用 */
@Builder.Default
@Column(columnDefinition = TypeConsts.COLUMN_TYPE_TEXT)
@Convert(converter = StringSetConverter.class)
private Set<String> topics = new HashSet<>();
// private String topic;
// 管理员监控的topic
@Builder.Default
@@ -62,6 +59,7 @@ public class Topic extends BaseEntityNoOrg {
// 每个用户仅存在一条记录
// user, no need map, just uid
// 用户uid或者robotUid
@NotBlank
@Column(unique = true, nullable = false)
private String userUid;

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-13 16:15:11
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-05-04 10:37:19
* @LastEditTime: 2024-09-20 09:29:45
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -35,8 +35,6 @@ import lombok.experimental.Accessors;
@AllArgsConstructor
public class TopicRequest extends BaseRequest {
// private String uid;
private String topic;
@NotBlank
@@ -55,7 +53,4 @@ public class TopicRequest extends BaseRequest {
*/
@Builder.Default
private List<String> clientIds = new ArrayList<>();
/** 描述 */
// private String description;
}

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-13 16:15:22
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-07 12:52:48
* @LastEditTime: 2024-09-20 09:30:00
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -36,9 +36,7 @@ import lombok.experimental.Accessors;
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class TopicResponse extends BaseResponse {
// private String uid;
@Builder.Default
private Set<String> topics = new HashSet<>();

View File

@@ -2,7 +2,7 @@
* @Author: jackning 270580156@qq.com
* @Date: 2024-04-26 21:51:31
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2024-09-06 23:07:16
* @LastEditTime: 2024-09-20 11:09:57
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
* Please be aware of the BSL license restrictions before installing Bytedesk IM
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
@@ -155,8 +155,6 @@ public class TopicUtils {
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
public static Boolean isOrgRobotTopic(String topic) {
return topic.startsWith(TOPIC_ORG_ROBOT_PREFIX);
}

View File

@@ -81,4 +81,8 @@ public class UidUtils {
return String.valueOf(uid);
}
public String getUid() {
return getDefaultSerialUid();
}
}

View File

@@ -21,11 +21,11 @@ public class DateUtils {
private static final String datetimeUidFormat = "yyyyMMddHHmmss";
private static final String dtFormat = "yyyy-MM-dd";
private static final String dateFormat = "yyyy-MM-dd";
private static final String dtFormatSlash = "yyyy/MM/dd";
private static final String dateFormatSlash = "yyyy/MM/dd";
private static final String dtFormatSlashNoZero = "yyyy/M/d";
private static final String dateFormatSlashNoZero = "yyyy/M/d";
private static final String timeFormat = "HH:mm:ss";
@@ -55,7 +55,7 @@ public class DateUtils {
}
public static String formatDateNow() {
SimpleDateFormat dateFormater = new SimpleDateFormat(dtFormat);
SimpleDateFormat dateFormater = new SimpleDateFormat(dateFormat);
return dateFormater.format(new Date());
}
@@ -78,27 +78,27 @@ public class DateUtils {
}
public static String formatDateSlashNow() {
SimpleDateFormat dateFormater = new SimpleDateFormat(dtFormatSlash);
SimpleDateFormat dateFormater = new SimpleDateFormat(dateFormatSlash);
return dateFormater.format(new Date());
}
public static String formatDateSlashNowNoZero() {
SimpleDateFormat dateFormater = new SimpleDateFormat(dtFormatSlashNoZero);
SimpleDateFormat dateFormater = new SimpleDateFormat(dateFormatSlashNoZero);
return dateFormater.format(new Date());
}
public static String formatDateToString(Date date) {
SimpleDateFormat formatter = new SimpleDateFormat(dtFormat);
return formatter.format(date);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
return simpleDateFormat.format(date);
}
public static Date formatStringToDate(String date) {
if (!StringUtils.hasText(date)) {
return null;
}
SimpleDateFormat dateFormat = new SimpleDateFormat(dtFormat);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
try {
return dateFormat.parse(date);
return simpleDateFormat.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
@@ -126,7 +126,7 @@ public class DateUtils {
fromFormat = new SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH);
}
//
SimpleDateFormat cnFormat = new SimpleDateFormat(dtFormat);
SimpleDateFormat cnFormat = new SimpleDateFormat(dateFormat);
Date parse = null;
try {
parse = fromFormat.parse(enDate);