update plugins/freeswitch: add 36 mod 4 del 1 files

This commit is contained in:
jack ning
2025-06-08 16:04:08 +08:00
parent 84c0030019
commit e52c3a3525
25 changed files with 972 additions and 0 deletions

View File

@@ -0,0 +1,186 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import java.time.LocalDateTime;
import com.bytedesk.core.base.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* FreeSwitch通话详单记录实体
* 对应数据库表freeswitch_cdr
*/
@Entity
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners({FreeSwitchCdrEntityListener.class})
@Table(name = "freeswitch_cdr")
public class FreeSwitchCdrEntity extends BaseEntity {
/**
* 通话唯一标识符
*/
@Column(name = "uuid", nullable = false, unique = true, length = 36)
private String uuid;
/**
* 主叫名称
*/
@Column(name = "caller_id_name", length = 100)
private String callerIdName;
/**
* 主叫号码
*/
@Column(name = "caller_id_number", nullable = false, length = 50)
private String callerIdNumber;
/**
* 被叫号码
*/
@Column(name = "destination_number", nullable = false, length = 50)
private String destinationNumber;
/**
* 上下文
*/
@Column(name = "context", length = 50)
private String context;
/**
* 通话开始时间
*/
@Column(name = "start_stamp")
private LocalDateTime startStamp;
/**
* 通话接通时间
*/
@Column(name = "answer_stamp")
private LocalDateTime answerStamp;
/**
* 通话结束时间
*/
@Column(name = "end_stamp")
private LocalDateTime endStamp;
/**
* 通话总时长(秒)
*/
@Column(name = "duration")
private Integer duration;
/**
* 计费时长(秒)
*/
@Column(name = "billsec")
private Integer billsec;
/**
* 挂断原因
*/
@Column(name = "hangup_cause", length = 50)
private String hangupCause;
/**
* 账户代码
*/
@Column(name = "accountcode", length = 50)
private String accountcode;
/**
* 读取编解码器
*/
@Column(name = "read_codec", length = 20)
private String readCodec;
/**
* 写入编解码器
*/
@Column(name = "write_codec", length = 20)
private String writeCodec;
/**
* SIP挂断处理
*/
@Column(name = "sip_hangup_disposition", length = 50)
private String sipHangupDisposition;
/**
* 录音文件路径
*/
@Column(name = "record_file", length = 500)
private String recordFile;
/**
* 通话方向inbound/outbound
*/
@Column(name = "direction", length = 20)
private String direction;
/**
* JSON格式的扩展信息
*/
@Column(name = "json", columnDefinition = "TEXT")
private String json;
/**
* 获取通话状态描述
*/
public String getCallStatusDescription() {
if (answerStamp != null) {
return "已接通";
} else if (hangupCause != null) {
return "未接通 - " + hangupCause;
} else {
return "未知状态";
}
}
/**
* 检查是否为成功通话
*/
public boolean isSuccessfulCall() {
return answerStamp != null && billsec != null && billsec > 0;
}
/**
* 获取格式化的通话时长
*/
public String getFormattedDuration() {
if (duration == null) return "00:00:00";
int hours = duration / 3600;
int minutes = (duration % 3600) / 60;
int seconds = duration % 60;
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
}
}

View File

@@ -0,0 +1,34 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import org.springframework.stereotype.Component;
import jakarta.persistence.PostPersist;
import lombok.extern.slf4j.Slf4j;
/**
* FreeSwitch CDR实体监听器
*/
@Slf4j
@Component
public class FreeSwitchCdrEntityListener {
@PostPersist
public void postPersist(FreeSwitchCdrEntity entity) {
log.info("FreeSwitch CDR记录创建: uuid={}, caller={}, destination={}, duration={}",
entity.getUuid(), entity.getCallerIdNumber(),
entity.getDestinationNumber(), entity.getDuration());
}
}

View File

@@ -0,0 +1,117 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import com.bytedesk.core.base.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* FreeSwitch会议室实体
* 对应数据库表freeswitch_conferences
*/
@Entity
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners({FreeSwitchConferenceEntityListener.class})
@Table(name = "freeswitch_conferences")
public class FreeSwitchConferenceEntity extends BaseEntity {
/**
* 会议室名称
*/
@Column(name = "conference_name", nullable = false, unique = true, length = 100)
private String conferenceName;
/**
* 会议室描述
*/
@Column(name = "description", length = 255)
private String description;
/**
* 会议室密码
*/
@Column(name = "password", length = 50)
private String password;
/**
* 最大参与者数量
*/
@Column(name = "max_members")
private Integer maxMembers;
/**
* 是否启用
*/
@Column(name = "enabled", nullable = false)
private Boolean enabled = true;
/**
* 是否录音
*/
@Column(name = "record_enabled", nullable = false)
private Boolean recordEnabled = false;
/**
* 录音文件路径
*/
@Column(name = "record_path", length = 500)
private String recordPath;
/**
* 创建者
*/
@Column(name = "creator", length = 100)
private String creator;
/**
* 会议室配置参数JSON格式
*/
@Column(name = "config_json", columnDefinition = "TEXT")
private String configJson;
/**
* 备注
*/
@Column(name = "remarks", length = 500)
private String remarks;
/**
* 检查会议室是否有密码保护
*/
public boolean isPasswordProtected() {
return password != null && !password.trim().isEmpty();
}
/**
* 检查会议室是否已满
*/
public boolean isFull(int currentMembers) {
return maxMembers != null && currentMembers >= maxMembers;
}
}

View File

@@ -0,0 +1,40 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import org.springframework.stereotype.Component;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostUpdate;
import lombok.extern.slf4j.Slf4j;
/**
* FreeSwitch会议室实体监听器
*/
@Slf4j
@Component
public class FreeSwitchConferenceEntityListener {
@PostPersist
public void postPersist(FreeSwitchConferenceEntity entity) {
log.info("FreeSwitch会议室创建: name={}, maxMembers={}",
entity.getConferenceName(), entity.getMaxMembers());
}
@PostUpdate
public void postUpdate(FreeSwitchConferenceEntity entity) {
log.info("FreeSwitch会议室更新: name={}, enabled={}",
entity.getConferenceName(), entity.getEnabled());
}
}

View File

@@ -0,0 +1,138 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import com.bytedesk.core.base.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* FreeSwitch网关实体
* 对应数据库表freeswitch_gateways
*/
@Entity
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners({FreeSwitchGatewayEntityListener.class})
@Table(name = "freeswitch_gateways")
public class FreeSwitchGatewayEntity extends BaseEntity {
/**
* 网关名称
*/
@Column(name = "gateway_name", nullable = false, unique = true, length = 100)
private String gatewayName;
/**
* 网关描述
*/
@Column(name = "description", length = 255)
private String description;
/**
* SIP服务器地址
*/
@Column(name = "proxy", nullable = false, length = 255)
private String proxy;
/**
* 用户名
*/
@Column(name = "username", nullable = false, length = 100)
private String username;
/**
* 密码
*/
@Column(name = "password", nullable = false, length = 255)
private String password;
/**
* 从号码
*/
@Column(name = "from_user", length = 100)
private String fromUser;
/**
* 从域名
*/
@Column(name = "from_domain", length = 100)
private String fromDomain;
/**
* 注册
*/
@Column(name = "register", nullable = false)
private Boolean register = true;
/**
* 注册传输协议
*/
@Column(name = "register_transport", length = 20)
private String registerTransport = "udp";
/**
* 网关状态
*/
@Column(name = "status", length = 20)
private String status = "DOWN";
/**
* 是否启用
*/
@Column(name = "enabled", nullable = false)
private Boolean enabled = true;
/**
* 扩展配置JSON格式
*/
@Column(name = "config_json", columnDefinition = "TEXT")
private String configJson;
/**
* 备注
*/
@Column(name = "remarks", length = 500)
private String remarks;
/**
* 检查网关是否在线
*/
public boolean isOnline() {
return "UP".equalsIgnoreCase(status) && enabled;
}
/**
* 获取完整的代理地址
*/
public String getFullProxy() {
if (proxy.contains("sip:")) {
return proxy;
}
return "sip:" + proxy;
}
}

View File

@@ -0,0 +1,40 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import org.springframework.stereotype.Component;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostUpdate;
import lombok.extern.slf4j.Slf4j;
/**
* FreeSwitch网关实体监听器
*/
@Slf4j
@Component
public class FreeSwitchGatewayEntityListener {
@PostPersist
public void postPersist(FreeSwitchGatewayEntity entity) {
log.info("FreeSwitch网关创建: name={}, proxy={}",
entity.getGatewayName(), entity.getProxy());
}
@PostUpdate
public void postUpdate(FreeSwitchGatewayEntity entity) {
log.info("FreeSwitch网关更新: name={}, status={}, enabled={}",
entity.getGatewayName(), entity.getStatus(), entity.getEnabled());
}
}

View File

@@ -0,0 +1,126 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import java.time.LocalDateTime;
import com.bytedesk.core.base.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* FreeSwitch用户实体
* 对应数据库表freeswitch_users
*/
@Entity
@Data
@SuperBuilder
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners({FreeSwitchUserEntityListener.class})
@Table(name = "freeswitch_users")
public class FreeSwitchUserEntity extends BaseEntity {
/**
* 用户名SIP用户名
*/
@Column(name = "username", nullable = false, unique = true, length = 50)
private String username;
/**
* SIP域名
*/
@Column(name = "domain", nullable = false, length = 100)
private String domain;
/**
* 密码
*/
@Column(name = "password", nullable = false, length = 255)
private String password;
/**
* 显示名称
*/
@Column(name = "display_name", length = 100)
private String displayName;
/**
* 邮箱
*/
@Column(name = "email", length = 100)
private String email;
/**
* 账户代码
*/
@Column(name = "accountcode", length = 50)
private String accountcode;
/**
* 是否启用
*/
@Column(name = "enabled", nullable = false)
private Boolean enabled = true;
/**
* 最后注册时间
*/
@Column(name = "last_register")
private LocalDateTime lastRegister;
/**
* 注册IP地址
*/
@Column(name = "register_ip", length = 45)
private String registerIp;
/**
* 用户代理
*/
@Column(name = "user_agent", length = 255)
private String userAgent;
/**
* 备注
*/
@Column(name = "remarks", length = 500)
private String remarks;
/**
* 获取完整的SIP地址
*/
public String getSipAddress() {
return username + "@" + domain;
}
/**
* 检查用户是否在线
*/
public boolean isOnline() {
return enabled && lastRegister != null &&
lastRegister.isAfter(LocalDateTime.now().minusMinutes(5));
}
}

View File

@@ -0,0 +1,40 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.model;
import org.springframework.stereotype.Component;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostUpdate;
import lombok.extern.slf4j.Slf4j;
/**
* FreeSwitch用户实体监听器
*/
@Slf4j
@Component
public class FreeSwitchUserEntityListener {
@PostPersist
public void postPersist(FreeSwitchUserEntity entity) {
log.info("FreeSwitch用户创建: username={}, domain={}",
entity.getUsername(), entity.getDomain());
}
@PostUpdate
public void postUpdate(FreeSwitchUserEntity entity) {
log.info("FreeSwitch用户更新: username={}, enabled={}",
entity.getUsername(), entity.getEnabled());
}
}

View File

@@ -0,0 +1,139 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.bytedesk.freeswitch.model.FreeSwitchCdrEntity;
/**
* FreeSwitch CDR仓库接口
*/
@Repository
public interface FreeSwitchCdrRepository extends JpaRepository<FreeSwitchCdrEntity, Long>,
JpaSpecificationExecutor<FreeSwitchCdrEntity> {
/**
* 根据UUID查找CDR记录
*/
Optional<FreeSwitchCdrEntity> findByUuid(String uuid);
/**
* 根据主叫号码查找CDR记录
*/
List<FreeSwitchCdrEntity> findByCallerIdNumber(String callerIdNumber);
/**
* 根据被叫号码查找CDR记录
*/
List<FreeSwitchCdrEntity> findByDestinationNumber(String destinationNumber);
/**
* 根据账户代码查找CDR记录
*/
List<FreeSwitchCdrEntity> findByAccountcode(String accountcode);
/**
* 根据通话方向查找CDR记录
*/
List<FreeSwitchCdrEntity> findByDirection(String direction);
/**
* 根据挂断原因查找CDR记录
*/
List<FreeSwitchCdrEntity> findByHangupCause(String hangupCause);
/**
* 查找指定时间范围内的CDR记录
*/
List<FreeSwitchCdrEntity> findByStartStampBetween(LocalDateTime startTime, LocalDateTime endTime);
/**
* 查找成功接通的通话记录
*/
List<FreeSwitchCdrEntity> findByAnswerStampIsNotNull();
/**
* 查找有录音文件的通话记录
*/
List<FreeSwitchCdrEntity> findByRecordFileIsNotNull();
/**
* 根据主叫或被叫号码查找CDR记录
*/
@Query("SELECT c FROM FreeSwitchCdrEntity c WHERE c.callerIdNumber = :number OR c.destinationNumber = :number")
List<FreeSwitchCdrEntity> findByCallerOrDestination(@Param("number") String number);
/**
* 查找指定号码的通话历史(分页)
*/
@Query("SELECT c FROM FreeSwitchCdrEntity c WHERE c.callerIdNumber = :number OR c.destinationNumber = :number ORDER BY c.startStamp DESC")
Page<FreeSwitchCdrEntity> findCallHistory(@Param("number") String number, Pageable pageable);
/**
* 统计指定时间范围内的通话数量
*/
@Query("SELECT COUNT(c) FROM FreeSwitchCdrEntity c WHERE c.startStamp BETWEEN :startTime AND :endTime")
long countCallsInTimeRange(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
/**
* 统计指定时间范围内成功接通的通话数量
*/
@Query("SELECT COUNT(c) FROM FreeSwitchCdrEntity c WHERE c.startStamp BETWEEN :startTime AND :endTime AND c.answerStamp IS NOT NULL")
long countAnsweredCallsInTimeRange(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
/**
* 计算指定时间范围内的总通话时长
*/
@Query("SELECT COALESCE(SUM(c.billsec), 0) FROM FreeSwitchCdrEntity c WHERE c.startStamp BETWEEN :startTime AND :endTime AND c.answerStamp IS NOT NULL")
long sumBillSecInTimeRange(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
/**
* 查找最近的通话记录
*/
@Query("SELECT c FROM FreeSwitchCdrEntity c ORDER BY c.startStamp DESC")
Page<FreeSwitchCdrEntity> findRecentCalls(Pageable pageable);
/**
* 根据主叫号码统计通话次数
*/
@Query("SELECT COUNT(c) FROM FreeSwitchCdrEntity c WHERE c.callerIdNumber = :callerNumber")
long countByCallerNumber(@Param("callerNumber") String callerNumber);
/**
* 根据被叫号码统计通话次数
*/
@Query("SELECT COUNT(c) FROM FreeSwitchCdrEntity c WHERE c.destinationNumber = :destinationNumber")
long countByDestinationNumber(@Param("destinationNumber") String destinationNumber);
/**
* 检查UUID是否存在
*/
boolean existsByUuid(String uuid);
/**
* 删除指定日期之前的CDR记录
*/
void deleteByStartStampBefore(LocalDateTime cutoffDate);
}

View File

@@ -0,0 +1,112 @@
/*
* @Author: jackning 270580156@qq.com
* @Date: 2025-06-09 10:00:00
* @LastEditors: jackning 270580156@qq.com
* @LastEditTime: 2025-06-09 10:00: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.
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
* contact: 270580156@qq.com
*
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
*/
package com.bytedesk.freeswitch.repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.bytedesk.freeswitch.model.FreeSwitchUserEntity;
/**
* FreeSwitch用户仓库接口
*/
@Repository
public interface FreeSwitchUserRepository extends JpaRepository<FreeSwitchUserEntity, Long>,
JpaSpecificationExecutor<FreeSwitchUserEntity> {
/**
* 根据用户名查找用户
*/
Optional<FreeSwitchUserEntity> findByUsername(String username);
/**
* 根据用户名和域名查找用户
*/
Optional<FreeSwitchUserEntity> findByUsernameAndDomain(String username, String domain);
/**
* 根据邮箱查找用户
*/
Optional<FreeSwitchUserEntity> findByEmail(String email);
/**
* 查找启用的用户
*/
List<FreeSwitchUserEntity> findByEnabledTrue();
/**
* 根据域名查找用户
*/
List<FreeSwitchUserEntity> findByDomain(String domain);
/**
* 根据账户代码查找用户
*/
List<FreeSwitchUserEntity> findByAccountcode(String accountcode);
/**
* 检查用户名是否存在
*/
boolean existsByUsername(String username);
/**
* 检查用户名和域名组合是否存在
*/
boolean existsByUsernameAndDomain(String username, String domain);
/**
* 查找在线用户最近5分钟内有注册记录
*/
@Query("SELECT u FROM FreeSwitchUserEntity u WHERE u.enabled = true AND u.lastRegister > :cutoffTime")
List<FreeSwitchUserEntity> findOnlineUsers(@Param("cutoffTime") LocalDateTime cutoffTime);
/**
* 根据用户名模糊搜索
*/
Page<FreeSwitchUserEntity> findByUsernameContainingIgnoreCase(String username, Pageable pageable);
/**
* 根据显示名称模糊搜索
*/
Page<FreeSwitchUserEntity> findByDisplayNameContainingIgnoreCase(String displayName, Pageable pageable);
/**
* 统计启用的用户数量
*/
long countByEnabledTrue();
/**
* 统计在线用户数量
*/
@Query("SELECT COUNT(u) FROM FreeSwitchUserEntity u WHERE u.enabled = true AND u.lastRegister > :cutoffTime")
long countOnlineUsers(@Param("cutoffTime") LocalDateTime cutoffTime);
/**
* 更新用户最后注册时间和IP
*/
@Query("UPDATE FreeSwitchUserEntity u SET u.lastRegister = :registerTime, u.registerIp = :registerIp WHERE u.username = :username AND u.domain = :domain")
int updateLastRegister(@Param("username") String username,
@Param("domain") String domain,
@Param("registerTime") LocalDateTime registerTime,
@Param("registerIp") String registerIp);
}